ADORe
ADORe is a modular open source software library and toolkit for decision making, planning, control and simulation of automated vehicles
sumotraffic2ros.h
Go to the documentation of this file.
1 /********************************************************************************
2  * Copyright (C) 2017-2022 German Aerospace Center (DLR).
3  * Eclipse ADORe, Automated Driving Open Research https://eclipse.org/adore
4  *
5  * This program and the accompanying materials are made available under the
6  * terms of the Eclipse Public License 2.0 which is available at
7  * http://www.eclipse.org/legal/epl-2.0.
8  *
9  * SPDX-License-Identifier: EPL-2.0
10  *
11  * Contributors:
12  * Daniel Heß - initial API and implementation
13  * Matthias Nichting
14  ********************************************************************************/
15 #pragma once
16 
17 #define _USE_MATH_DEFINES
18 #include <math.h>
19 #include <tf2/LinearMath/Quaternion.h>
20 #include <tf2/LinearMath/Matrix3x3.h>
21 #include <geometry_msgs/Pose.h>
22 #include "sumotls2ros.h"
23 #include <iostream>
24 #include <libsumo/libsumo.h>
25 #include <ros/ros.h>
26 #include <std_msgs/Float64.h>
27 #include <adore_if_ros_msg/TrafficParticipantSetSimulation.h>
28 #include <adore_if_ros_msg/TrafficParticipantSimulation.h>
29 #include <ros/console.h>
30 #include <chrono>
31 #include <thread>
32 #include <unordered_set>
33 #include <unordered_map>
34 
35 namespace adore
36 {
37  namespace sumo_if_ros
38  {
39  struct Timer
40  {
41  public:
42  double tUTC_;
43  Timer() : tUTC_(0.0)
44  {
45  }
46  void receive(const std_msgs::Float64ConstPtr& msg)
47  {
48  tUTC_ = msg->data;
49  }
50  };
51 
53  {
54  public:
55  std::unordered_map<int, adore_if_ros_msg::TrafficParticipantSimulation> data_;
58  void receive(adore_if_ros_msg::TrafficParticipantSimulationConstPtr msg)
59  {
60  // data_.push_back(*msg);
61  if (data_.find(msg->simulationID) == data_.end())
62  {
63  data_.emplace(msg->simulationID, *msg);
64  }
65  else
66  {
67  data_[msg->simulationID] = *msg;
68  }
69  }
70  };
71 
73  {
74  public:
76  {
77  delta_t_ = 0;
78  min_update_period_ = 0.01;
81  }
83  {
84  delete nh_;
85  }
86 
87  protected:
89  ros::NodeHandle* nh_;
90  ros::Publisher publisher_;
91  ros::Publisher mapem_publisher_;
92  ros::Publisher spatem_publisher_;
95  ros::Subscriber subscriber1_;
96  ros::Subscriber subscriber2_;
97  std::string sumo_rosveh_prefix_;
98  std::string sumo_rosped_prefix_;
99  std::vector<ros::Timer> rostimers_;
100 
101  std::unordered_map<std::string, int> sumovehid2int_;
102  std::unordered_map<std::string, int> sumopedid2int_;
104  std::map<int, std::string> replacement_ids_;
105 
106  std::vector<std::string> vehidlist_;
107  std::vector<std::string> pedidlist_;
108  std::vector<std::string> sumo_to_ros_ignore_list_;
109  std::vector<int> ros_to_sumo_ignore_list_;
110 
112  double tSUMO0;
113  double tSUMO;
114  double delta_t_;
117 
118  public:
119  ros::NodeHandle* getRosNodeHandle()
120  {
121  return nh_;
122  }
123  void run()
124  {
125  while (nh_->ok())
126  {
127  ros::spin();
128  }
129  }
130 
131  protected:
133  {
135  {
136  last_assigned_int_id_ = 1000;
137  }
138  return ++last_assigned_int_id_;
139  }
140  void removeVehicle(std::string& id)
141  {
142  try
143  {
144  libsumo::Vehicle::remove(id);
145  }
146  catch (...)
147  {
148  std::cout << "Error: removal of sumo vehicle failed" << std::endl;
149  }
150  }
151  void addVehicle(std::string& id)
152  {
153  try
154  {
155  libsumo::Vehicle::add(id, "");
156  }
157  catch (...)
158  {
159  std::cout << "Error: adding a sumo vehicle failed" << std::endl;
160  }
161  }
162  void setMaxSpeed(std::string& id, double val)
163  {
164  try
165  {
166  libsumo::Vehicle::setMaxSpeed(id, val);
167  }
168  catch (...)
169  {
170  std::cout << "Error: setMaxSpeed for sumo vehicle failed" << std::endl;
171  }
172  }
173  void setSpeed(std::string& id, double val)
174  {
175  try
176  {
177  libsumo::Vehicle::setSpeed(id, val);
178  }
179  catch (...)
180  {
181  std::cout << "Error: setSpeed for sumo vehicle failed" << std::endl;
182  }
183  }
184  void moveToXY(std::string& id, std::string z, int a, double x, double y, double heading, int b)
185  {
186  try
187  {
188  libsumo::Vehicle::moveToXY(id, z, a, x, y, heading, b);
189  }
190  catch (...)
191  {
192  std::cout << "Error: moveToXY for sumo vehicle failed" << std::endl;
193  }
194  }
195 
196  public:
197  void runCallback(const ros::TimerEvent& te)
198  {
199  if (newStep())
200  {
203  }
204  }
205 
206  bool newStep()
207  {
208  // synchronize SUMO:
211  {
212  libsumo::Simulation::step(timer_.tUTC_ + tSUMO0);
213  double tSUMO_new = libsumo::Simulation::getTime();
214 
215  if (tSUMO_new <= tSUMO)
216  {
217  return false;
218  }
219  tSUMO = tSUMO_new;
220  // get vehicles from sumo
221  vehidlist_ = libsumo::Vehicle::getIDList();
222  pedidlist_ = libsumo::Person::getIDList();
223  return true;
224  }
225  return false;
226  }
228  {
229  // traffic light information
231  {
232  auto v2x_mapem = sumotls2ros.getMAPEMFromSUMO(timer_.tUTC_);
233  auto spatems = sumotls2ros.getSPATEMFromSUMO(timer_.tUTC_);
234 
235  // resend static mapem data
236  for (auto&& mapem_item : v2x_mapem)
237  mapem_publisher_.publish(mapem_item.second);
238 
239  // send non-static spatem data
240  for (auto&& spat : spatems)
241  spatem_publisher_.publish(spat);
242 
244  }
245  // traffic participant information
246  if (vehidlist_.size() > 0 || pedidlist_.size() > 0)
247  {
248  // message for set of traffic participants
249  adore_if_ros_msg::TrafficParticipantSetSimulation tpset;
250  tpset.simulator = "SUMO";
251 
252  for (auto& id : vehidlist_)
253  {
254  if (id.find(sumo_rosveh_prefix_) == std::string::npos)
255  {
256  // id translation
257  int intid = 0;
258  auto idtranslation = sumovehid2int_.find(id);
259  if (idtranslation == sumovehid2int_.end())
260  {
261  intid = getNewIntID();
262  sumovehid2int_.emplace(id, intid);
263  }
264  else
265  {
266  intid = idtranslation->second;
267  }
268  if (std::find(sumo_to_ros_ignore_list_.begin(), sumo_to_ros_ignore_list_.end(), id) !=
270  {
271  continue;
272  }
273  try
274  {
275  libsumo::TraCIPosition tracipos = libsumo::Vehicle::getPosition(id);
276  double heading = M_PI * 0.5 - libsumo::Vehicle::getAngle(id) / 180.0 * M_PI;
277  double v = libsumo::Vehicle::getSpeed(id);
278  std::string type = libsumo::Vehicle::getTypeID(id);
279  double L = libsumo::Vehicle::getLength(id);
280  double w = libsumo::Vehicle::getWidth(id);
281  double H = libsumo::Vehicle::getHeight(id);
282  int signals = libsumo::Vehicle::getSignals(id);
284 
285  // ros message for single traffic participant
286  adore_if_ros_msg::TrafficParticipantSimulation tp;
287  tp.simulationID = intid;
288  tp.data.v2xStationID = intid;
289  tp.data.time = tSUMO - tSUMO0;
290  tp.data.classification.type_id =
291  adore_if_ros_msg::TrafficClassification::CAR; //@TODO: parse sumo type string
292  tp.data.shape.type = 1;
293  tp.data.shape.dimensions.push_back(L);
294  tp.data.shape.dimensions.push_back(w);
295  tp.data.shape.dimensions.push_back(H);
296  auto geopos = libsumo::Simulation::convertGeo(tracipos.x, tracipos.y, false);
297  tp.data.motion_state.pose.pose.position.x = geopos.x;
298  tp.data.motion_state.pose.pose.position.y = geopos.y;
299  tp.data.motion_state.pose.pose.position.z = 0;
300  tf2::Quaternion q;
301  q.setRPY(0.0, 0.0, heading);
302  tp.data.motion_state.pose.pose.orientation.x = q.getX();
303  tp.data.motion_state.pose.pose.orientation.y = q.getY();
304  tp.data.motion_state.pose.pose.orientation.z = q.getZ();
305  tp.data.motion_state.pose.pose.orientation.w = q.getW();
306  tp.data.motion_state.twist.twist.linear.x = v;
307  // add the traffic participant to the set
308  tpset.data.push_back(tp);
309  }
310  catch (...)
311  {
312  std::cout << "Error: failed to get information with libsumo::Vehicle" << std::endl;
313  }
314  }
315  }
316 
317  for (auto& id : pedidlist_)
318  {
319  // ignore pedestrians controlled by other simulator
320  if (id.find(sumo_rosped_prefix_) == std::string::npos)
321  {
322  // id translation
323  int intid = 0;
324  auto idtranslation = sumopedid2int_.find(id);
325  if (idtranslation == sumopedid2int_.end())
326  {
327  intid = getNewIntID();
328  sumopedid2int_.emplace(id, intid);
329  }
330  else
331  {
332  intid = idtranslation->second;
333  }
334 
335  // retrieve person data
336  libsumo::TraCIPosition tracipos = libsumo::Person::getPosition(id);
337  double heading = M_PI * 0.5 - libsumo::Person::getAngle(id) / 180.0 * M_PI;
338  double v = libsumo::Person::getSpeed(id);
339  std::string type = libsumo::Person::getTypeID(id);
340  double L = libsumo::Person::getLength(id);
341  double w = libsumo::Person::getLength(id);
342  double H = 1.75;
343  // not in libsumo? int signals = libtraci::Person::getSignals(id); ///<- bit array!
344  // see TraciAPI:669, todo int signals = libsumo::Person::getSignals(id); ///<- bit
345  // array! see TraciAPI:669, VehicleSignal
346 
347  // ros message for single traffic participant
348  adore_if_ros_msg::TrafficParticipantSimulation tp;
349  tp.simulationID = intid;
350  tp.data.time = tSUMO - tSUMO0;
351  tp.data.classification.type_id = adore_if_ros_msg::TrafficClassification::PEDESTRIAN;
352  tp.data.shape.type = 1;
353  tp.data.shape.dimensions.push_back(L);
354  tp.data.shape.dimensions.push_back(w);
355  tp.data.shape.dimensions.push_back(H);
356  auto geopos = libsumo::Simulation::convertGeo(tracipos.x, tracipos.y, false);
357  tp.data.motion_state.pose.pose.position.x = geopos.x;
358  tp.data.motion_state.pose.pose.position.y = geopos.y;
359  tp.data.motion_state.pose.pose.position.z = 0;
360  tf2::Quaternion q;
361  q.setRPY(0.0, 0.0, heading);
362  tp.data.motion_state.pose.pose.orientation.x = q.getX();
363  tp.data.motion_state.pose.pose.orientation.y = q.getY();
364  tp.data.motion_state.pose.pose.orientation.z = q.getZ();
365  tp.data.motion_state.pose.pose.orientation.w = q.getW();
366  tp.data.motion_state.twist.twist.linear.x = v;
367  // add the traffic participant to the set
368  tpset.data.push_back(tp);
369  }
370  }
371 
372  // write the message
373  publisher_.publish(tpset);
374  }
375  }
377  {
378  // update sumo with new information from ros
379  // TODO std::vector<int> delete_from_rosvehicleset;
380  for (auto pair : rosVehicleSet_.data_)
381  {
382  auto msg = pair.second;
383  if (std::find(ros_to_sumo_ignore_list_.begin(), ros_to_sumo_ignore_list_.end(), msg.simulationID) !=
385  {
386  continue;
387  }
388  std::string sumoid;
389  auto replacement_id = replacement_ids_.find(msg.simulationID);
390  if (replacement_id == replacement_ids_.end())
391  {
392  std::stringstream ss;
393  ss << sumo_rosveh_prefix_ << msg.simulationID;
394  sumoid = ss.str();
395  }
396  else
397  {
398  sumoid = replacement_id->second;
399  }
400  if (std::find(vehidlist_.begin(), vehidlist_.end(), sumoid) == vehidlist_.end())
401  {
402  addVehicle(sumoid);
403  setMaxSpeed(sumoid, 100.0);
404  }
405 
406  auto p = msg.data.motion_state.pose.pose;
407  tf2::Quaternion q;
408  q.setValue(p.orientation.x, p.orientation.y, p.orientation.z, p.orientation.w);
409  tf2::Matrix3x3 m(q);
410  double roll, pitch, yaw;
411  m.getRPY(roll, pitch, yaw);
412  const double heading = (M_PI * 0.5 - yaw) * 180.0 / M_PI;
413 
414  auto sumopos = libsumo::Simulation::convertGeo(p.position.x, p.position.y, true);
415  // following line: keepRoute=2. see
416  // https://sumo.dlr.de/docs/TraCI/Change_Vehicle_State.html#move_to_xy_0xb4 for details
417  moveToXY(sumoid, "", 0, sumopos.x, sumopos.y, heading, 2);
418  setSpeed(sumoid, msg.data.motion_state.twist.twist.linear.x);
419  }
420  }
421 
422  void init_rosconnection(int argc, char** argv, double rate, std::string nodename)
423  {
424  ros::init(argc, argv, nodename);
425  nh_ = new ros::NodeHandle();
426  ros::Timer rostimer = nh_->createTimer(ros::Duration(1.0 / rate), &SUMOTrafficToROS::runCallback, this);
427  rostimers_.push_back(rostimer);
428  }
429  void init_sumo()
430  {
431  int port = -1;
432  double step_length = 0.05;
433  std::string cfg_file;
434  nh_->getParam("/sumo/port", port); //relevant only for libtraci
435  nh_->getParam("/sumo/cfg_file", cfg_file);
436  nh_->getParam("/sumo/step_length", step_length);
437  if (cfg_file.empty())
438  {
439  throw std::runtime_error("Error: No config file for sumo provided.");
440  }
441  // cfg_file_ = "/home/fascar/catkin_ws/src/adore/adore_if_ros_demos/demo005.sumocfg";
442  std::vector<std::string> sumoargs;
443  sumoargs.push_back("-c");
444  sumoargs.push_back(cfg_file);
445  sumoargs.push_back("--step-length");
446  sumoargs.push_back(std::to_string(step_length));
447  if (port > -1)
448  {
449  sumoargs.push_back("--remote-port");
450  sumoargs.push_back(std::to_string(port));
451  }
452 
453  while (nh_->ok())
454  {
455  try
456  {
457  std::cout << "load sumo ..." << std::flush;
458  libsumo::Simulation::load(sumoargs);
459  std::cout << " done." << std::endl;
460  break;
461  }
462  catch (const std::exception& exc)
463  {
464  std::cout << exc.what() << std::endl;
465  std::cout << "Arguments for sumo:" << std::endl;
466  for (auto a : sumoargs)
467  {
468  std::cout << a << std::endl;
469  }
470  std::cout << "try again ..." << std::endl;
471  }
472  std::this_thread::sleep_for(std::chrono::milliseconds(500));
473  }
474  std::cout << "started sumo with config file " << cfg_file << " and step length " << step_length
475  << std::endl;
476  tSUMO0 = libsumo::Simulation::getTime();
477  tSUMO = tSUMO0;
478  publisher_ = nh_->advertise<adore_if_ros_msg::TrafficParticipantSetSimulation>("/SIM/"
479  "traffic/"
480  "agg",
481  5);
482  nh_->getParam("PARAMS/V2X_TL/UTMZone", sumotls2ros.utm_zone_);
483  nh_->getParam("PARAMS/V2X_TL/SouthHemi", sumotls2ros.is_south_hemi_);
484  nh_->getParam("PARAMS/V2X_TL/UseSystemTime", sumotls2ros._use_system_time);
485  nh_->getParam("PARAMS/V2X_TL/EnableSPATTiming", sumotls2ros._generate_spat_timing);
486  ROS_INFO_STREAM_ONCE("SPAT/MAP Generation Parameters");
487  ROS_INFO_STREAM_ONCE("-- UTM-Zone: " << sumotls2ros.utm_zone_);
488  ROS_INFO_STREAM_ONCE("-- South. Hemi.: " << sumotls2ros.is_south_hemi_);
489  ROS_INFO_STREAM_ONCE("-- use system time: " << sumotls2ros._use_system_time);
490  ROS_INFO_STREAM_ONCE("-- enable spat timing: " << sumotls2ros._generate_spat_timing);
491  ROS_INFO_STREAM_ONCE("-------------------------------");
493  nh_->advertise<adore_v2x_sim::SimMAPEM>("/SIM/v2x/MAPEM",100);
495  nh_->advertise<adore_v2x_sim::SimSPATEM>("/SIM/v2x/SPATEM",100);
496  subscriber1_ = nh_->subscribe<std_msgs::Float64>("/SIM/utc", 1, &Timer::receive, &timer_);
497  subscriber2_ = nh_->subscribe<adore_if_ros_msg::TrafficParticipantSimulationConstPtr>(
498  "/SIM/traffic", 100, &ROSVehicleSet::receive, &rosVehicleSet_);
499  sumo_rosveh_prefix_ = "rosvehicle";
500  sumo_rosped_prefix_ = "rospedestrian";
501  last_assigned_int_id_ = 1000;
502  }
503  void setRosNodeHandle(ros::NodeHandle* nh)
504  {
505  nh_ = nh;
506  }
507 
508  void closeSumo()
509  {
510  libsumo::Simulation::close();
511  }
512  };
513  } // namespace sumo_if_ros
514 } // namespace adore
#define M_PI
Definition: arraymatrixtools.h:24
Definition: sumotraffic2ros.h:73
SUMOTrafficToROS()
Definition: sumotraffic2ros.h:75
~SUMOTrafficToROS()
Definition: sumotraffic2ros.h:82
void init_sumo()
Definition: sumotraffic2ros.h:429
void moveToXY(std::string &id, std::string z, int a, double x, double y, double heading, int b)
Definition: sumotraffic2ros.h:184
std::vector< ros::Timer > rostimers_
Definition: sumotraffic2ros.h:99
std::vector< std::string > vehidlist_
Definition: sumotraffic2ros.h:106
ROSVehicleSet rosVehicleSet_
Definition: sumotraffic2ros.h:88
void closeSumo()
Definition: sumotraffic2ros.h:508
std::vector< int > ros_to_sumo_ignore_list_
Definition: sumotraffic2ros.h:109
double min_update_period_
Definition: sumotraffic2ros.h:115
std::vector< std::string > sumo_to_ros_ignore_list_
Definition: sumotraffic2ros.h:108
double tSUMO
Definition: sumotraffic2ros.h:113
void setRosNodeHandle(ros::NodeHandle *nh)
Definition: sumotraffic2ros.h:503
std::string sumo_rosped_prefix_
Definition: sumotraffic2ros.h:98
ros::Subscriber subscriber1_
Definition: sumotraffic2ros.h:95
void setSpeed(std::string &id, double val)
Definition: sumotraffic2ros.h:173
std::vector< std::string > pedidlist_
Definition: sumotraffic2ros.h:107
std::map< int, std::string > replacement_ids_
Definition: sumotraffic2ros.h:104
std::unordered_map< std::string, int > sumopedid2int_
Definition: sumotraffic2ros.h:102
ros::Publisher mapem_publisher_
Definition: sumotraffic2ros.h:91
double tSUMO0
Definition: sumotraffic2ros.h:112
void transferDataSumoToRos()
Definition: sumotraffic2ros.h:227
bool newStep()
Definition: sumotraffic2ros.h:206
int last_assigned_int_id_
Definition: sumotraffic2ros.h:103
double last_tl_update_time_
Definition: sumotraffic2ros.h:94
ros::Publisher publisher_
Definition: sumotraffic2ros.h:90
void run()
Definition: sumotraffic2ros.h:123
double delta_t_
Definition: sumotraffic2ros.h:114
int getNewIntID()
Definition: sumotraffic2ros.h:132
void runCallback(const ros::TimerEvent &te)
Definition: sumotraffic2ros.h:197
ros::NodeHandle * nh_
Definition: sumotraffic2ros.h:89
double min_tl_update_period_
Definition: sumotraffic2ros.h:116
void removeVehicle(std::string &id)
Definition: sumotraffic2ros.h:140
SumoTLs2Ros sumotls2ros
Definition: sumotraffic2ros.h:93
ros::Publisher spatem_publisher_
Definition: sumotraffic2ros.h:92
std::unordered_map< std::string, int > sumovehid2int_
Definition: sumotraffic2ros.h:101
ros::Subscriber subscriber2_
Definition: sumotraffic2ros.h:96
void setMaxSpeed(std::string &id, double val)
Definition: sumotraffic2ros.h:162
Timer timer_
Definition: sumotraffic2ros.h:111
void transferDataRosToSumo()
Definition: sumotraffic2ros.h:376
ros::NodeHandle * getRosNodeHandle()
Definition: sumotraffic2ros.h:119
void init_rosconnection(int argc, char **argv, double rate, std::string nodename)
Definition: sumotraffic2ros.h:422
void addVehicle(std::string &id)
Definition: sumotraffic2ros.h:151
std::string sumo_rosveh_prefix_
Definition: sumotraffic2ros.h:97
Definition: sumotls2ros.h:36
bool _generate_spat_timing
Definition: sumotls2ros.h:113
std::vector< adore_v2x_sim::SimSPATEM > getSPATEMFromSUMO(double time, double power=23)
Definition: sumotls2ros.cpp:546
bool is_south_hemi_
Definition: sumotls2ros.h:109
std::unordered_map< int, adore_v2x_sim::SimMAPEM > getMAPEMFromSUMO(double time, double power=23)
Definition: sumotls2ros.cpp:95
int utm_zone_
Definition: sumotls2ros.h:105
bool _use_system_time
Definition: sumotls2ros.h:111
ALFunction< T, T > * heading(AScalarToN< T, 2 > *df)
Definition: heading.h:114
ALFunction< DT, CT > * add(ALFunction< DT, CT > *a, ALFunction< DT, CT > *b)
Definition: alfunction.h:742
adoreMatrix< T, N, M > max(adoreMatrix< T, N, M > a, const adoreMatrix< T, N, M > &b)
Definition: adoremath.h:686
x
Definition: adore_set_goal.py:30
y
Definition: adore_set_goal.py:31
z
Definition: adore_set_goal.py:32
yaw
Definition: adore_set_pose.py:36
w
Definition: adore_set_pose.py:40
Definition: areaofeffectconverter.h:20
Definition: sumotraffic2ros.h:53
std::unordered_map< int, adore_if_ros_msg::TrafficParticipantSimulation > data_
Definition: sumotraffic2ros.h:55
void receive(adore_if_ros_msg::TrafficParticipantSimulationConstPtr msg)
Definition: sumotraffic2ros.h:58
Definition: sumotraffic2ros.h:40
double tUTC_
Definition: sumotraffic2ros.h:42
void receive(const std_msgs::Float64ConstPtr &msg)
Definition: sumotraffic2ros.h:46
Timer()
Definition: sumotraffic2ros.h:43