mission_planning_node.cpp
Go to the documentation of this file.
1 /**************************************************************************************************
2  Software License Agreement (BSD License)
3 
4  Copyright (c) 2011-2013, LAR toolkit developers - University of Aveiro - http://lars.mec.ua.pt
5  All rights reserved.
6 
7  Redistribution and use in source and binary forms, with or without modification, are permitted
8  provided that the following conditions are met:
9 
10  *Redistributions of source code must retain the above copyright notice, this list of
11  conditions and the following disclaimer.
12  *Redistributions in binary form must reproduce the above copyright notice, this list of
13  conditions and the following disclaimer in the documentation and/or other materials provided
14  with the distribution.
15  *Neither the name of the University of Aveiro nor the names of its contributors may be used to
16  endorse or promote products derived from this software without specific prior written permission.
17 
18  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
19  IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
20  FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
24  IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
25  OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 ***************************************************************************************************/
27 /*
28 @file
29 @brief
30 Responsible to comunicate with the osrm-backend.
31 Receives the destination and returns the waypoints and instructions.
32 */
33 #include <iostream>
34 #include <stdio.h>
35 
36 #include <algorithm> // for std::find
37 #include <iterator> // for std::begin, std::end
38 
39 //INCLUDE CURL
40 #include <curl/curl.h>
41 #include <boost/asio.hpp>
42 
43 //INCLUDE JSON
44 #include "json/json.h"
45 #include <string>
46 
47 //INCLUDE GOOGLEPOLYLINE
48 #include <vector>
49 #include <math.h>
50 #include <bitset>
51 #include <utility>
52 
53 //ROS INCLUDES
54 #include <ros/ros.h>
55 #include <mission_planning/Path.h>
56 
57 using namespace std;
58 //CLASSES
59 /*
60 @brief
61 Encapsulate gps coordiantes and maneuver.
62 Creates a class of informations relative to the mission. Can be exapanded further.
63 */
65 
66 public:
67 
68  typedef boost::shared_ptr<GpsLocation> Ptr;
69 
70  double latitude;
71  double longitude;
72  //double altitude;
73  string maneuver;
74 
75  GpsLocation(double latitude,double longitude,string maneuver){
76  this->latitude = latitude;
77  this->longitude = longitude;
78  this->maneuver = maneuver;
79  }
80 };
81 /*
82 @brief
83 Operator << overload
84 Overload for opeartor << to print directly all elements of the locations vector
85 */
86 //Overload for opeartor << to print directly all elements of locations vector
87 ostream& operator<<(ostream& o, const GpsLocation::Ptr& loc){
88  if(loc->maneuver.empty())
89  o<<"Lat:" <<loc->latitude<<" Lon: "<<loc->longitude<<" Man: (none)";
90  else
91  o<<"Lat:" <<loc->latitude<<" Lon: "<<loc->longitude<<" Man: "<<loc->maneuver;
92 
93  return o;
94 }
95 /*
96 @brief
97 Function to decode the encoded polyline
98 This function decodes the polyline from the osrm-backend.
99 @param encodedPoints
100 The polyline string
101 @param precision
102 The precision of the encoded polyline, in this case it is six digits.
103 @return
104 Array containing the latitude and longitude values.
105 */
106 //FUNCTION TO DECODE ENCODED POLYLINE
107 vector<double>Decompress(string encodedPoints, int precision){
108 
109  int len = encodedPoints.length();
110  int index =0;
111  double lat =0;
112  double lng = 0;
113  vector<double> array;
114 
115  while (index < len) {
116 
117  int b;
118  int shift =0;
119  int result =0;
120  do {
121  b = (int)encodedPoints[index++] - 63; //gets ascii value of the char
122  //result |= (b & 0x1f) << shift;
123  result |= (b & 31) << shift;
124  shift +=5;
125  } while (b>=32);
126  int dlat= ((result & 1) ? ~(result >> 1) : (result >> 1));
127  lat+=dlat;
128  shift =0;
129  result =0;
130 
131  do {
132  b = (int)encodedPoints[index++]- 63; //gets ascii value of the char
133  result |= (b & 31) << shift;
134  shift +=5;
135  } while (b>=32);
136  int dlng = ((result & 1) ? ~(result >> 1) : (result >> 1));
137  lng+=dlng;
138 
139  array.push_back(lat*pow(10,-precision));
140  array.push_back(lng*pow(10,-precision));
141  }
142  return array;
143 }
144 /*
145 @brief
146 Writes curl repsonse to string format
147 */
148 //WRITE CURL RESPONSE TO STRING FORMAT
149 size_t write_to_string(void* ptr, size_t size, size_t nmemb, std::string* data){
150  data->append((const char*)ptr, size * nmemb);
151  return size * nmemb;
152 }
153 
154 /*
155 @brief
156 Function that requests a route
157 This functions decodes the information sent by the mission_planning_client module and creates a string that will be sent over curl to the osrm-backend located in the LAR, and requests a route. Decodes all the information received from the backend and builds the response that will be sent to the client. In case an error occurs the user is informed with a message.
158 @param mission_planning::Path::Request
159 contains the requested destination coordinates
160 @param mission_planning::Path::Response
161 will be the response for the client
162 @return a bool that indicates if the request was succesfully sent or not
163 */
164 //ros server function that processes request data and fills response fields (service callback)
166  mission_planning::Path::Request &req, //contains data sent from client
167  mission_planning::Path::Response &resp)
168 {
169  double startLat = req.gpsLat;
170  double startLon = req.gpsLon;
171  double destLat = req.destLat;
172  double destLon = req.destLon;
173  //Local calculations, requires that osrm-backend is installed and running on your computer
174  //string htmlquery = "http://localhost:5000/viaroute?loc="+to_string(startLat)+","+to_string(startLon)+"&loc="+to_string(destLat)+","+to_string(destLon)+"&instructions=true";
175 
176  //Remote calculations, requires that osrm-backend is installed and running on the LAR server
177  string htmlquery = "http://193.137.172.18:5000/viaroute?loc="+to_string(startLat)+","+to_string(startLon)+"&loc="+to_string(destLat)+","+to_string(destLon)+"&instructions=true";
178 
179  /*
180 }
181 int main(){
182 */
183  //STEP 1 - GET JSON VIA CURL
184  int http_code = 0;
185  string data;
186 
187  CURL *curl;
188  CURLcode res;
189 
190  //Initialize cURL
191  curl = curl_easy_init();
192 
193  if(curl){
194 
195  //Set the function to call when there is new data
196  curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION, write_to_string);
197 
198  //Set the parameter to append the new data to
199  curl_easy_setopt(curl, CURLOPT_WRITEDATA, &data);
200 
201  //Set the URL to download
202  curl_easy_setopt(curl, CURLOPT_URL, htmlquery.c_str());
203  //curl_easy_setopt(curl, CURLOPT_URL, "http://localhost:5000/viaroute?loc=40.63179,-8.65712&loc=40.64382,-8.64238&instructions=true");
204 
205  /* Follow HTTP redirection in necessary */
206  curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
207 
208  /* Perform the request, res will get the return code (Downloads content) */
209  res = curl_easy_perform(curl);
210  /* Check for errors */
211  if(res != CURLE_OK)
212  fprintf(stderr, "curl_easy_perform() failed: %s\n",
213  curl_easy_strerror(res));
214 
215  //Get the HTTP response code
216  curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE, &http_code);
217 
218  /* Always cleanup */
219  curl_easy_cleanup(curl);
220  curl_global_cleanup();
221  }
222 
223  //Output response as a string
224  // cout << "Server Response Code: "<< http_code << "\nJSON FILE:\n"<< data << endl;
225 
226  //STEP 2 - PARSE JSON USING JSONCPP LIB
227  //HTTP CODE 200 == OK
228  if (http_code == 200){
229 
230  std::cout << "\nServer OK, JSON file acquired " << std::endl;
231  // Response looks good - done using Curl now. Try to parse the results and print them out.
232  Json::Value jsonData;
233  Json::Reader jsonReader;
234 
235  if (jsonReader.parse(data, jsonData))
236 
237  std::cout << "Successfully parsed JSON data" << std::endl;
238  std::cout << "\nJSON data received:" << std::endl;
239  std::cout << jsonData.toStyledString() << std::endl;
240 
241  //In case the gps looses signal and requests a destination based from lat=0.000 lon=0.000
242  Json::Value invalid_coord = jsonData["status"];
243  if (invalid_coord == 207){printf("Error no route found between the requested points, Check Gps Signal\n");exit(0);}
244  //
245 
246  //GET encodedPolyline from json
247  Json::Value encodedLine = jsonData["route_geometry"];
248  cout << "FIELD STATUS = " << encodedLine << "\n" << endl;
249 
250  vector<double> data = Decompress(encodedLine.asString(),6);
251  vector<pair<double,double> > waypoints; //pair of lat,lon values
252 
253 
254  for ( int i = 0; i < data.size(); i+=2) {
255  waypoints.push_back(make_pair(data[i],data[i+1])); //pair of lat,lon values
256 
257  printf ("%lf , %lf \n",data[i],data[i+1]);
258  }
259 
260 
261  //GET INSTRUCTIONS
262  string turnInstruction [18]={"NoTurn","GoStraight","TurnSlightRight","TurnRight","TurnSharpRight","UTurn",
263  "TurnSharpLeft","TurnLeft","TurnSlightLeft","ReachViaLocation","HeadOn","EnterRoundAbout",
264  "LeaveRoundAbout","StayOnRoundAbout","StartAtEndOfStreet","ReachedYourDestination",
265  "EnterAgainstAllowedDirection","LeaveAgainstAllowedDirection"};
266 
267 
268  Json::Value instructions = jsonData["route_instructions"];
269  //cout << "INSTRUCTIONS = " << instructions << "\n" << endl;
270  cout << "Size of instructions = "<< instructions.size() << endl;
271 
272  //Acess the second element of the first array
273  //cout << instructions[0][1] << endl;
274 
275  //Loop through all instructions
276  std::vector<int> instPos; //instruction todo at waypoint X
277  std::vector<string>instTodo; // set of instruction
278 
279  for (int i = 0; i < instructions.size(); i++) {
280 
281 
282  instPos.push_back(instructions[i][3].asInt()); //add waypoint index that has an instruction
283 
284 
285  string dir = instructions[i][0].asString(); //convert instructions index to string
286  if(dir.find("-")!=std::string::npos) //if string contains "-" (has more than one instruction)
287  {
288  int a = dir.find("-"); //position of "-"
289  string found = dir.substr(0,a); //first instruction
290  string found2 = dir.substr(a+1,dir.size()); //second instruction
291  //cout << turnInstruction[atoi(found.c_str())] << " and "<< turnInstruction[atoi(found2.c_str())] << instructions[i][1] << endl;
292  string fullInst = (turnInstruction[atoi(found.c_str())] + " and " + turnInstruction[atoi(found2.c_str())]);
293 
294  instTodo.push_back(fullInst); //adds complex instruction to array
295 
296  }
297  else
298  {
299  int dirOK = atoi(dir.c_str()); //converts string to int
300  //prints manouver and name of the street
301  //cout << turnInstruction[dirOK] << " " << instructions[i][1] << endl;
302  instTodo.push_back(turnInstruction[dirOK]); //adds simple instruction to array
303 
304  }
305  }
306  /*
307  cout<<"TODO:"<<endl;
308  for (int i= 0; i< instTodo.size(); i++) {
309  cout << instTodo.at(i) << endl;
310  }
311 
312  cout<<"Pos"<<endl;
313  for (int i = 0; i < instPos.size(); ++i) {
314  cout << "waypoint index: "<< instPos.at(i) << endl;
315  }
316 */
317 
318  cout<<"Waypoints size: "<<waypoints.size()<<endl;
319 
320  //SET of Points UNDER CONSTRUCTION
321  std::vector<GpsLocation::Ptr> locations; //array of positions ( contains waypoints + driving instruction )
322  //GpsLocation::Ptr loc1(new GpsLocation(0,0,"0")); //add new element
323  //locations.push_back(loc1);
324 
325  //Create the mission ( Waypoints + instructions )
326  for (int i = 0; i < waypoints.size(); i++) {
327 
328  vector<int>::iterator it = find(instPos.begin(),instPos.end(),i); //get iterator where position was found
329  int index = it - instPos.begin(); //get real position
330 
331  if(it!=instPos.end()){
332  //if contains instruction
333  //printf("%d-%d %lf , %lf , %s \n",i,i+1,waypoints[i].first,waypoints[i].second,instTodo[index].c_str());
334  GpsLocation::Ptr loc1(new GpsLocation(waypoints[i].first,waypoints[i].second,instTodo[index].c_str())); //add new element
335  locations.push_back(loc1);
336  }else{
337  //printf ("%d-%d %lf , %lf \n",i,i+1,waypoints[i].first,waypoints[i].second);
338  //In case there is no instruction TODO, instead of placing "" place "Go on"
339  GpsLocation::Ptr loc1(new GpsLocation(waypoints[i].first,waypoints[i].second,"")); //add new element
340  locations.push_back(loc1);
341 
342  }
343 
344  }
345 
346  cout << "Size of locations: " << locations.size() << endl;
347  for (int i = 0; i < locations.size(); ++i) {
348  //std::cout << (*locations[i]).latitude << std::endl;
349 
350  //Print locations
351  GpsLocation::Ptr location = locations[i];
352  cout << location << endl;
353 
354  //After filling the response fields we are able to return true
355 
356  //resp.lat[i]=(*locations[i]).latitude;
357  //resp.lon[i]=(*locations[i]).longitude;
358  //resp.instruction[i]=(*locations[i]).maneuver;
359  resp.lat.push_back((*locations[i]).latitude);
360  resp.lon.push_back((*locations[i]).longitude);
361  resp.instruction.push_back((*locations[i]).maneuver);
362  }
363 
364  ROS_INFO("Request complete"); //complete with data
365  return true;
366 
367  } //if httpcode = 200
368  else
369  {
370  std::cout << "Could not parse HTTP data as JSON" << std::endl;
371  std::cout << "HTTP data was:\n" << data << std::endl;
372  ROS_ERROR("Could not parse HTTP, failed to send request");
373  return 1;
374  }//if httpcode != 200
375 
376 
377 }
378 /*
379 @brief
380 main of this program.
381 creates a new node and starts a service in which this module will be the server.
382 */
383 int main(int argc, char** argv)
384 {
385 
386  //ROS CODE
387  ros::init(argc, argv, "mission_response_server"); //name of the node
388  ros::NodeHandle nh;
389 
390  //Register the service with the master
391  ros::ServiceServer server = nh.advertiseService("return_path",&return_path);//creating a server object (service_name,pointer_to_callback_function)
392  ROS_INFO("Ready to send mission!");
393  ros::spin(); //enters a loop, pumping callbacks. All callbacks will be called from within this thread.
394  //ros::spinOnce();
395 
396  return 0;
397 
398 } //end main
399 
int main(int argc, char **argv)
bool parse(const std::string &document, Value &root, bool collectComments=true)
Read a Value from a JSON document.
Definition: jsoncpp.cpp:270
Represents a JSON value.
Definition: json.h:504
vector< double > Decompress(string encodedPoints, int precision)
GpsLocation(double latitude, double longitude, string maneuver)
boost::shared_ptr< GpsLocation > Ptr
ostream & operator<<(ostream &o, const GpsLocation::Ptr &loc)
size_t write_to_string(void *ptr, size_t size, size_t nmemb, std::string *data)
std::string asString() const
Embedded zeroes are possible.
Definition: jsoncpp.cpp:2996
std::string toStyledString() const
Definition: jsoncpp.cpp:3724
Unserialize a JSON document into a Value.
Definition: json.h:1230
ArrayIndex size() const
Number of values in array or object.
Definition: jsoncpp.cpp:3232
bool return_path(mission_planning::Path::Request &req, mission_planning::Path::Response &resp)


mission_planning
Author(s): ivan
autogenerated on Thu Nov 12 2015 19:08:20