CGR Localization
 All Classes Namespaces Files Functions Variables Macros Pages
vector_display_main.cpp
Go to the documentation of this file.
1 //========================================================================
2 // This software is free: you can redistribute it and/or modify
3 // it under the terms of the GNU Lesser General Public License Version 3,
4 // as published by the Free Software Foundation.
5 //
6 // This software is distributed in the hope that it will be useful,
7 // but WITHOUT ANY WARRANTY; without even the implied warranty of
8 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9 // GNU Lesser General Public License for more details.
10 //
11 // You should have received a copy of the GNU Lesser General Public License
12 // Version 3 in the file COPYING that came with this distribution.
13 // If not, see <http://www.gnu.org/licenses/>.
14 //========================================================================
20 //========================================================================
21 
22 #include "stdio.h"
23 
24 #include <QtGui/QApplication>
25 #include <QObject>
26 #include <QThread>
27 #include <vector>
28 
29 #include "vector_display.h"
30 #include "proghelp.h"
31 #include "timer.h"
32 #include "ros/ros.h"
33 #include "ros/package.h"
34 #include "popt_pp.h"
35 #include "cgr_localization/DisplayMsg.h"
36 #include "cgr_localization/LocalizationInterfaceSrv.h"
37 #include "cgr_localization/LocalizationMsg.h"
38 #include "sensor_msgs/LaserScan.h"
39 
40 #include "util.h"
41 #include "geometry.h"
42 #include "terminal_utils.h"
43 #include "vector_map.h"
44 
45 using namespace std;
46 using namespace ros;
47 using namespace cgr_localization;
48 
49 ros::NodeHandle *n;
50 
51 bool runApp = true;
52 bool testMode = false;
53 bool saveLocs = false;
54 bool saveOrientations = false;
55 bool liveView = false;
56 bool persistentDisplay = true;
57 
58 VectorDisplay* display;
59 QApplication* app;
60 ros::ServiceClient client;
61 ros::ServiceClient localizationClient;
62 char* map_name;
63 
64 void callback(vector2d loc,vector2d loc2,double orientation,int type)
65 {
66  static const bool debug = false;
67  static FILE* fid=NULL;
68  if(saveLocs && fid==NULL)
69  fid = fopen("savedLocs.txt","aw");
70  if(saveLocs){
71  if(saveOrientations){
72  fprintf(fid, "%f,%f,%f\n",V2COMP(loc),(loc2-loc).angle());
73  printf("Saved location: %f,%f,%f\n",V2COMP(loc),(loc2-loc).angle());
74  }else{
75  fprintf(fid, "%f,%f,%f,%f\n",V2COMP(loc),V2COMP(loc2));
76  printf("Saved location: %f,%f,%f,%f\n",V2COMP(loc),V2COMP(loc2));
77  }
78 
79  }
80  LocalizationInterfaceSrv srv;
81  srv.request.loc_x = loc.x;
82  srv.request.loc_y = loc.y;
83  srv.request.orientation = orientation;
84  srv.request.map = map_name;
85  switch(type){
86  case 3:{
87  //Set Position
88  if(debug) printf("SetPosition: %7.3f,%7.3f %6.1f\u00b0\n",V2COMP(loc),DEG(orientation));
89  client = localizationClient;
90  }break;
91  case 2:{
92  //Set Target
93  if(debug) printf("SetTarget: %7.3f,%7.3f %6.1f\u00b0\n",V2COMP(loc),DEG(orientation));
94  //client = navigationClient;
95  }break;
96  }
97  if(type==2 || type==3){
98  if(client.call(srv)){
99 
100  }else{
101  printf("Failed to send command!\n");
102  }
103  }
104 }
105 
106 class MyThread : public QThread
107 {
108  //Q_OBJECT
109  string mapsFolder;
110  VectorMap vectorMap;
111  vector<vector2d> pathPlan;
112  vector2d robotLoc;
113  double robotAngle;
114  sensor_msgs::LaserScan laserScanMsg;
115  vector<DisplayMsg> displayMsgs;
116  vector<string> displayProviders;
117  double tPathPlan, tDisplay, tLaser;
118 
119  vector<line2f> lines;
120  vector<vector2f> points;
121  vector<vector2f> circles;
122  vector<VectorDisplay::Color> circleColors;
123  vector<VectorDisplay::Color> lineColors;
124  vector<VectorDisplay::Color> pointColors;
125 
126 public:
127  void drawMap(vector<line2f> &lines, vector<VectorDisplay::Color> &lineColors)
128  {
129  int numLines = vectorMap.lines.size();
130  for(int i=0; i<numLines; i++){
131  lines.push_back(line2f(vectorMap.lines[i].P0().x,vectorMap.lines[i].P0().y,
132  vectorMap.lines[i].P1().x,vectorMap.lines[i].P1().y));
133  lineColors.push_back(VectorDisplay::Color(0.32, 0.49, 0.91));
134  }
135  }
136 
137  void localizationCallback(const LocalizationMsg& msg)
138  {
139  static const bool debug = false;
140  if(debug) printf("Localization update: %f,%f, %f\u00b0, %s\n",msg.x,msg.y,DEG(msg.angle),msg.map.c_str());
141  robotLoc = vector2d(msg.x, msg.y);
142  robotAngle = msg.angle;
143  snprintf(map_name, 4095, "%s",msg.map.c_str());
144  if(msg.map.compare(vectorMap.mapName)!=0){
145  vectorMap.loadMap(msg.map.c_str(), false);
146  }
147  }
148 
149  void laserCallback(const sensor_msgs::LaserScan& msg)
150  {
151  laserScanMsg = msg;
152  tLaser = GetTimeSec();
153  }
154 
155  void statusCallback(const ros::MessageEvent<DisplayMsg const>& msgEvent)
156  {
157  static const bool debug = false;
158  const DisplayMsgConstPtr &msg = msgEvent.getConstMessage();
159  bool duplicate = false;
160  unsigned int i=0;
161  for(;i<displayProviders.size() && !duplicate; i++){
162  if(displayProviders[i].compare(msgEvent.getPublisherName())==0)
163  duplicate = true;
164  }
165  if(duplicate){
166  i--;
167  displayMsgs[i] = *msg;
168  if(debug) printf("Duplicate message from %s\n",displayProviders[i].c_str());
169  }else{
170  displayMsgs.push_back(*msg);
171  displayProviders.push_back(msgEvent.getPublisherName());
172  if(debug) printf("New message from %s\n",displayProviders[i].c_str());
173  }
174  }
175 
176  void compileDisplay()
177  {
178  static double tLast = 0.0;
179  static const double MessageTimeout = 1.0;
180  static const int LidarPointColor = 0xF0761F;
181  static const bool debug = false;
182  if(debug) printf("GUI updated!\n");
183 
184  if(GetTimeSec()-tLast<0.016)
185  return;
186  tLast = GetTimeSec();
187 
188  lines.clear();
189  points.clear();
190  circles.clear();
191  circleColors.clear();
192  lineColors.clear();
193  pointColors.clear();
194 
195  drawMap(lines, lineColors);
196  for(unsigned int j=0; j<displayMsgs.size(); j++){
197  DisplayMsg displayMsg = displayMsgs[j];
198  if(GetTimeSec()-tDisplay<MessageTimeout || persistentDisplay){
199  unsigned int numLines = min(min((int)displayMsg.lines_p1x.size(),(int)displayMsg.lines_p1y.size()),min((int)displayMsg.lines_p2x.size(),(int)displayMsg.lines_p2y.size()));
200  for(unsigned int i=0; i<numLines; i++){
201  lines.push_back(line2f(displayMsg.lines_p1x[i],displayMsg.lines_p1y[i],displayMsg.lines_p2x[i],displayMsg.lines_p2y[i]));
202  if(i<displayMsg.lines_col.size())
203  lineColors.push_back(displayMsg.lines_col[i]);
204  }
205  unsigned int numPoints = min(displayMsg.points_x.size(),displayMsg.points_y.size());
206  for(unsigned int i=0; i<numPoints; i++){
207  points.push_back(vector2f(displayMsg.points_x[i],displayMsg.points_y[i]));
208  if(i<displayMsg.points_col.size())
209  pointColors.push_back(VectorDisplay::Color(displayMsg.points_col[i]));
210  }
211  unsigned int numCircles = min(displayMsg.circles_x.size(),displayMsg.circles_y.size());
212  for(unsigned int i=0; i<numCircles; i++){
213  circles.push_back(vector2f(displayMsg.circles_x[i],displayMsg.circles_y[i]));
214  if(i<displayMsg.circles_col.size())
215  circleColors.push_back(VectorDisplay::Color(displayMsg.circles_col[i]));
216  }
217  }
218  }
219  if(debug){
220  printf("lines: %d points: %d circles: %d\n",int(lines.size()), int(points.size()), int(circles.size()));
221  }
222  //displayMsgs.clear();
223  //displayProviders.clear();
224 
225  if((GetTimeSec()-tLaser<MessageTimeout || persistentDisplay) && liveView){
226  unsigned int i=0;
227  float a=0.0;
228  vector2f laserLoc(0.145,0.0), p(0.0,0.0);
229  laserLoc = vector2f(V2COMP(robotLoc)) + laserLoc.rotate(robotAngle);
230  for(i=0, a = robotAngle + laserScanMsg.angle_min; i<laserScanMsg.ranges.size(); i++, a+=laserScanMsg.angle_increment){
231  if(laserScanMsg.ranges[i]<=laserScanMsg.range_min || laserScanMsg.ranges[i]>=laserScanMsg.range_max)
232  continue;
233  p.heading(a);
234  p = p*laserScanMsg.ranges[i]+laserLoc;
235  points.push_back(p);
236  pointColors.push_back(LidarPointColor);
237  }
238  }
239 
240  if(GetTimeSec()-tPathPlan<MessageTimeout || persistentDisplay){
241  if(pathPlan.size()>0){
242  lines.push_back(line2f(pathPlan[0].x, pathPlan[0].y, robotLoc.x, robotLoc.y));
243  lineColors.push_back(0x00FF00);
244  points.push_back(vector2f(V2COMP(pathPlan[0])));
245  pointColors.push_back(0xFF0000);
246  }
247  for(int i=0; i<int(pathPlan.size())-1; i++){
248  lines.push_back(line2f(pathPlan[i].x, pathPlan[i].y, pathPlan[i+1].x, pathPlan[i+1].y));
249  lineColors.push_back(0x00FF00);
250  points.push_back(vector2f(V2COMP(pathPlan[i])));
251  points.push_back(vector2f(V2COMP(pathPlan[i+1])));
252  pointColors.push_back(0xFF0000);
253  pointColors.push_back(0xFF0000);
254  }
255  }
256 
257  display->updateDisplay(robotLoc,robotAngle, 100.0, lines, points, circles, lineColors, pointColors, circleColors);
258  }
259 
260 protected:
261  void run()
262  {
263  static const bool debug = false;
264 
265  if(testMode){
266  while(runApp && ros::ok()){
267  float scale = 0.005;
268  int numLines = 10;
269  int numPoints = 800;
270  vector<line2f> lines;
271  vector<vector2f> points;
272  double dTheta = 2.0*M_PI/double(numLines);
273  vector2d offset(1000.0,0.0);
274  double theta = 0.0;
275  double omega = RAD(30.0);
276  for(int i=0; i<numLines; i++){
277  vector2d p(1000.0,0.0), p1,p2;
278  p1 = p.rotate(theta+omega*GetTimeSec());
279  p2 = p.rotate(theta+dTheta+omega*GetTimeSec());
280  p1 *= scale;
281  p2 *= scale;
282  lines.push_back(line2f(p1.x,p1.y,p2.x,p2.y));
283  theta += dTheta;
284  }
285  dTheta = 2.0*M_PI/double(numPoints);
286  theta = 0.0;
287  for(int i=0;i<numPoints;i++){
288  vector2d p(3500.0,0.0);
289  p = p*max(0.0,1.1+sin(sin(2.0*theta)*M_PI))/2.0;
290  p = p.rotate(theta+omega*GetTimeSec())+offset;
291  p *= scale;
292  points.push_back(vector2f(p.x,p.y));
293  theta += dTheta;
294  }
295  display->updateLines(lines);
296  display->updatePoints(points);
297  Sleep(0.016);
298  }
299  if(debug) printf("Terminating testMode thread. runApp:%d ok():%d\n",runApp?1:0,ros::ok()?1:0);
300  }else{
301 
302  vectorMap = VectorMap(map_name,mapsFolder.c_str(), false);
303 
304  ros::Subscriber guiSub;
305  ros::Subscriber statusSub;
306  ros::Subscriber laserSub;
307  ros::Subscriber localizationSub;
308 
309  laserSub = n->subscribe("laser", 1, &MyThread::laserCallback, this);
310  localizationSub = n->subscribe("localization", 1, &MyThread::localizationCallback, this);
311  guiSub = n->subscribe("localization_gui", 1, &MyThread::statusCallback, this);
312 
313  drawMap(lines, lineColors);
314  display->updateLines(lines, lineColors);
315 
316  while(runApp && ros::ok()){
317  spinOnce();
318  compileDisplay();
319  Sleep(0.001);
320  }
321  if(debug) printf("Terminating thread. runApp:%d ok():%d\n",runApp?1:0,ros::ok()?1:0);
322  }
323  app->quit();
324  }
325  public:
326  MyThread(const char* _mapsFolder, QObject* parent = 0) : vectorMap(_mapsFolder)
327  {
328  mapsFolder = string(_mapsFolder);
329  pathPlan.clear();
330  }
331  ~MyThread(){}
332 };
333 
334 
335 int main(int argc, char *argv[])
336 {
337  static const bool debug = false;
338  ColourTerminal(TerminalUtils::TERMINAL_COL_GREEN,TerminalUtils::TERMINAL_COL_BLACK,TerminalUtils::TERMINAL_ATTR_BRIGHT);
339  printf("\nVector LIDAR Localization GUI\n\n");
340  ResetTerminal();
341 
342  if(debug) printf("Starting up...\n");
343 
344  ros::init(argc, argv, "vector_LIDAR_GUI");
345  map_name = (char*) malloc(4096);
346  snprintf(map_name, 4095, "GHC7");
347  // option table
348  static struct poptOption options[] = {
349  { "test-mode", 't', POPT_ARG_NONE , &testMode, 0, "Test Drawing Capabilities", "NONE"},
350  { "map-name", 'm', POPT_ARG_STRING , &map_name, 0, "Map name", "STRING"},
351  { "save-locs", 's', POPT_ARG_NONE, &saveLocs, 0, "Save Locations", "NONE"},
352  { "live-view", 'l', POPT_ARG_NONE, &liveView, 0, "Live View of Robot", "NONE"},
353  { "persistent-display",'p', POPT_ARG_NONE, &persistentDisplay, 0, "Persistent Display", "NONE"},
354  { "save-orientation", 'S', POPT_ARG_NONE, &saveOrientations, 0, "Save Orientations", "NONE"},
355 
356  POPT_AUTOHELP
357  { NULL, 0, 0, NULL, 0, NULL, NULL }
358  };
359  // parse options
360  POpt popt(NULL,argc,(const char**)argv,options,0);
361  int c;
362  while((c = popt.getNextOpt()) >= 0){
363  }
364  if(saveOrientations)
365  saveLocs = true;
366 
367  app = new QApplication(argc, argv);
368  display = new VectorDisplay();
369 
370  display->setCallback(&callback);
371 
372  n = new ros::NodeHandle();
373  localizationClient = n->serviceClient<LocalizationInterfaceSrv>("localization_interface");
374 
375  InitHandleStop(&runApp);
376  display->show();
377  MyThread thread(ros::package::getPath("cgr_localization").append("/maps/").c_str());
378  thread.start();
379  int retVal = app->exec();
380  runApp = false;
381  if(debug) printf("Waiting for thread termination... ");
382  thread.wait();
383  if(debug) printf("Done. Bye Bye!\n");
384  return retVal;
385 }
Subroutines to spice up stdout.
A GUI for Vector Localization; C++ Interface: VectorDisplay.
C++ Interfaces: VectorMap, LineSection.
void setCallback(void(*_ptrCallback)(vector2d, vector2d, double, int))
Definition: line.h:33
Definition: popt_pp.h:6
vector2d< num > rotate(const double a) const MustUseResult
return vector rotated by angle a
Definition: gvector.h:975
bool loadMap(const char *name, bool usePreRender)
Load map by name.
Definition: vector_map.cpp:28
void heading(num angle)
make a unit vector at given angle
Definition: gvector.h:802