tuw_marker_slam_node.cpp
Go to the documentation of this file.
2 
3 #include "tuw_marker_slam_node.h"
5 
6 using namespace tuw;
7 
8 int main ( int argc, char **argv ) {
9  ros::init ( argc, argv, "slam" );
11  SLAMNode slam ( n );
12  ros::Rate rate ( 10 );
13 
14  while ( ros::ok() ) {
16  slam.cycle();
17 
19  slam.publish();
20 
22  ros::spinOnce();
23 
25  rate.sleep();
26  }
27  return 0;
28 }
29 
34  : SLAM (),
35  n_ ( n ),
36  n_param_ ( "~" ) {
37  int mode;
38  std::vector<double> beta;
39 
40  // read in common parameters
41  n_param_.param<int> ( "mode", mode, 0 );
42  n_param_.param<bool> ( "xzplane", xzplane_, false );
43  n_param_.param<std::string> ( "frame_id_map", frame_id_map_, "map" );
44  n_param_.param<std::string> ( "frame_id_odom", frame_id_odom_, "odom" );
45  n_param_.param<std::string> ( "frame_id_base", frame_id_base_, "base_link" );
49 
50  switch ( mode ) {
51  case SLAMTechnique::EKF:
52  // read in EKF specific parameters
53  beta = std::vector<double> ( 18 ) ;
54 
55  n_param_.getParam ( "beta_1", beta[0] );
56  n_param_.getParam ( "beta_2", beta[1] );
57  n_param_.getParam ( "beta_3", beta[2] );
58  n_param_.getParam ( "beta_4", beta[3] );
59  n_param_.getParam ( "beta_5", beta[4] );
60  n_param_.getParam ( "beta_6", beta[5] );
61  n_param_.getParam ( "beta_7", beta[6] );
62  n_param_.getParam ( "beta_8", beta[7] );
63  n_param_.getParam ( "beta_9", beta[8] );
64  n_param_.getParam ( "beta_10", beta[9] );
65  n_param_.getParam ( "beta_11", beta[10] );
66  n_param_.getParam ( "beta_12", beta[11] );
67  n_param_.getParam ( "beta_13", beta[12] );
68  n_param_.getParam ( "beta_14", beta[13] );
69  n_param_.getParam ( "beta_15", beta[14] );
70  n_param_.getParam ( "beta_16", beta[15] );
71  n_param_.getParam ( "beta_17", beta[16] );
72  n_param_.getParam ( "beta_18", beta[17] );
73 
74  zt_ = std::make_shared<tuw::MeasurementMarker>();
75  slam_technique_ = std::make_shared<tuw::EKFSLAM> ( beta );
76  break;
77  default:
78  ROS_ERROR ( "[%s] mode %i is not supported", ros::this_node::getName().c_str(), mode );
79  return;
80  }
81  ROS_INFO ( "[%s] mode: %s (%i)", ros::this_node::getName().c_str(), slam_technique_->getTypeName().c_str(), ( int ) slam_technique_->getType() );
82 
84  sub_cmd_ = n.subscribe ( "cmd", 1, &SLAMNode::callbackCmd, this );
85 
87  pub_xt_ = n_param_.advertise<geometry_msgs::PoseWithCovarianceStamped> ( "xt", 1 );
88  xt_.header.frame_id = frame_id_map_;
89  xt_.header.seq = 0;
90 
92  pub_mt_ = n_param_.advertise<marker_msgs::MarkerWithCovarianceArray> ( "mt", 1 );
93  mt_.header.frame_id = frame_id_map_;
94  mt_.header.seq = 0;
95 
97  tf_listener_ = std::make_shared<tf::TransformListener>();
98 
100  reconfigureFncSLAM_ = boost::bind ( &SLAMNode::callbackConfigSLAM, this, _1, _2 );
101  reconfigureServerSLAM_.setCallback ( reconfigureFncSLAM_ );
102 
103  switch ( slam_technique_->getType() ) {
104  case SLAMTechnique::EKF:
106  sub_marker_ = n.subscribe ( "marker", 1, &SLAMNode::callbackMarker, this );
107 
109  reconfigureServerEKFSLAM_ = std::make_shared< dynamic_reconfigure::Server<tuw_marker_slam::EKFSLAMConfig> > ( ros::NodeHandle ( "~/" + slam_technique_->getTypeName() ) );
110  reconfigureFncEKFSLAM_ = boost::bind ( &SLAMNode::callbackConfigEKFSLAM, this, _1, _2 );
112  break;
113  default:
114  assert ( 0 );
115  }
116 }
117 
119  if ( config_.reset ) {
120  slam_technique_->reset();
121  }
122 
123  SLAM::cycle ();
124 }
125 
130  if ( slam_technique_->time_last_update().is_not_a_date_time() ) return;
131 
132  // Broadast transformation map to odom
133  tf::Transform base_to_map;
134  tf::Stamped<tf::Pose> map_to_base;
135  tf::Stamped<tf::Pose> odom_to_map;
136  tf::StampedTransform map_to_odom;
137 
138  // subtracting base to odom from map to base (cp. http://wiki.ros.org/amcl)
139  try {
140  base_to_map = tf::Transform ( tf::createQuaternionFromYaw ( yt_[0].theta() ), tf::Point ( yt_[0].x(), yt_[0].y(), 0 ) );
141  map_to_base = tf::Stamped<tf::Pose> ( base_to_map.inverse(), ros::Time::fromBoost ( slam_technique_->time_last_update() ), frame_id_base_ );
142  tf_listener_->transformPose ( frame_id_odom_, map_to_base, odom_to_map );
143  map_to_odom = tf::StampedTransform ( odom_to_map.inverse(), odom_to_map.stamp_, frame_id_map_, frame_id_odom_ );
144 
145  tf_broadcaster_.sendTransform ( map_to_odom );
146  }
147  catch (std::exception &ex) {
148  ROS_ERROR ( "[%s publish] subtracting base-to-odom from map-to-base failed: %s", ros::this_node::getName().c_str(), ex.what() );
149  }
150 
151  assert ( yt_.size() > 0 && C_Yt_.rows == 3*yt_.size() && C_Yt_.cols == 3*yt_.size() );
152 
153  // publish estimated robot pose and its variance
154  xt_.header.stamp = ros::Time::fromBoost ( slam_technique_->time_last_update() );
155  xt_.header.seq++;
156 
157  xt_.pose.pose.position.x = yt_[0].x();
158  xt_.pose.pose.position.y = yt_[0].y();
159  xt_.pose.pose.position.z = 0;
160  xt_.pose.pose.orientation = tf::createQuaternionMsgFromYaw ( yt_[0].theta() );
161 
162  cv::Matx<double, 3, 3> C_X2 = cv::Mat_<double> ( C_Yt_, cv::Range ( 0, 3 ), cv::Range ( 0, 3 ) );
163  xt_.pose.covariance[6*0 + 0] = C_X2 ( 0, 0 );
164  xt_.pose.covariance[6*0 + 1] = C_X2 ( 0, 1 );
165  xt_.pose.covariance[6*0 + 5] = C_X2 ( 0, 2 );
166  xt_.pose.covariance[6*1 + 0] = C_X2 ( 1, 0 );
167  xt_.pose.covariance[6*1 + 1] = C_X2 ( 1, 1 );
168  xt_.pose.covariance[6*1 + 5] = C_X2 ( 1, 2 );
169  xt_.pose.covariance[6*5 + 0] = C_X2 ( 2, 0 );
170  xt_.pose.covariance[6*5 + 1] = C_X2 ( 2, 1 );
171  xt_.pose.covariance[6*5 + 5] = C_X2 ( 2, 2 );
172 
173  pub_xt_.publish ( xt_ );
174 
175  // publish estimated landmark poses and their variance
176  mt_.header.stamp = ros::Time::fromBoost ( slam_technique_->time_last_update() );
177  mt_.header.seq++;
178 
179  mt_.markers.resize ( yt_.size() - 1 );
180  for ( size_t i = 0; i < mt_.markers.size(); i++ ) {
181  mt_.markers[i].marker.ids.resize(1);
182  mt_.markers[i].marker.ids_confidence.resize(1);
183  mt_.markers[i].marker.ids[0] = i + 1;
184  mt_.markers[i].marker.ids_confidence[0] = 1.0;
185 
186  mt_.markers[i].marker.pose.position.x = yt_[i+1].x();
187  mt_.markers[i].marker.pose.position.y = yt_[i+1].y();
188  mt_.markers[i].marker.pose.position.z = 0;
189  mt_.markers[i].marker.pose.orientation = tf::createQuaternionMsgFromYaw ( yt_[i+1].theta() );
190 
191  cv::Matx<double, 3, 3> C_Mi2 = cv::Mat_<double> ( C_Yt_, cv::Range ( 3* ( i+1 ), 3* ( i+1 ) + 3 ), cv::Range ( 3* ( i+1 ), 3* ( i+1 ) + 3 ) );
192  mt_.markers[i].covariance[6*0 + 0] = C_Mi2 ( 0, 0 );
193  mt_.markers[i].covariance[6*0 + 1] = C_Mi2 ( 0, 1 );
194  mt_.markers[i].covariance[6*0 + 5] = C_Mi2 ( 0, 2 );
195  mt_.markers[i].covariance[6*1 + 0] = C_Mi2 ( 1, 0 );
196  mt_.markers[i].covariance[6*1 + 1] = C_Mi2 ( 1, 1 );
197  mt_.markers[i].covariance[6*1 + 5] = C_Mi2 ( 1, 2 );
198  mt_.markers[i].covariance[6*5 + 0] = C_Mi2 ( 2, 0 );
199  mt_.markers[i].covariance[6*5 + 1] = C_Mi2 ( 2, 1 );
200  mt_.markers[i].covariance[6*5 + 5] = C_Mi2 ( 2, 2 );
201  }
202 
203  pub_mt_.publish ( mt_ );
204 }
205 
210 void SLAMNode::callbackCmd ( const geometry_msgs::Twist& cmd ) {
211  ut_.v() = cmd.linear.x;
212  ut_.w() = cmd.angular.z;
213 }
214 
219 void SLAMNode::callbackMarker ( const marker_msgs::MarkerDetection &_marker ) {
220  assert ( zt_->getType() == tuw::Measurement::Type::MARKER );
221  MeasurementMarkerPtr zt = std::static_pointer_cast<MeasurementMarker> ( zt_ );
222 
223  try {
224  tf::StampedTransform transform;
225  tf_listener_->lookupTransform ( frame_id_base_, _marker.header.frame_id, ros::Time ( 0 ), transform );
226  double yaw = tf::getYaw(transform.getRotation());
227  zt->pose2d() = Pose2D ( transform.getOrigin().getX(),
228  transform.getOrigin().getY(),
229  ( xzplane_ ) ? yaw + M_PI/2 : yaw );
230  } catch ( tf::TransformException &ex ) {
231  ROS_ERROR ( "[%s callbackMarker] %s", ros::this_node::getName().c_str(), ex.what() );
232  zt->pose2d() = Pose2D ( 0.225, 0, 0 );
233  }
234 
235  if ( ( _marker.view_direction.x == 0 ) && ( _marker.view_direction.y == 0 ) && ( _marker.view_direction.z == 0 ) && ( _marker.view_direction.w == 1 ) ) {
236  zt->angle_min() = -_marker.fov_horizontal/2.;
237  zt->angle_max() = _marker.fov_horizontal/2.;
238  } else {
239  ROS_ERROR ( "[%s callbackMarker] %s", ros::this_node::getName().c_str(), "This node only deals with straight forward looking view directions" );
240  }
241 
242  zt->range_min() = _marker.distance_min;
243  zt->range_max() = _marker.distance_max;
244  zt->range_max_id() = _marker.distance_max_id;
245  zt->stamp() = _marker.header.stamp.toBoost();
246  zt->resize ( 0 );
247 
248  for ( size_t i = 0; i < _marker.markers.size(); i++ ) {
249  double x, y, z, roll, pitch, yaw, length, angle, theta;
250  tf::Vector3 v;
251  tf::Quaternion q;
252 
253  tf::pointMsgToTF ( _marker.markers[i].pose.position, v );
254  tf::quaternionMsgToTF(_marker.markers[i].pose.orientation, q);
255  tf::Matrix3x3(q).getRPY(roll, pitch, yaw);
256 
257  if ( xzplane_ ) { // gazebo
258  x = v.getZ();
259  y = -v.getX();
260  theta = angle_difference(M_PI, pitch);
261  } else { //stage
262  x = v.getX();
263  y = v.getY();
264  theta = yaw;
265  }
266 
267  length = sqrt( x*x + y*y );
268  angle = atan2 ( y, x );
269 
270  if (length < zt->range_min() || length > zt->range_max() ||
271  angle < zt->angle_min() || angle > zt->angle_max())
272  continue;
273 
275  zt_i.ids = _marker.markers[i].ids;
276  zt_i.ids_confidence = _marker.markers[i].ids_confidence;
277  zt_i.length = length;
278  zt_i.angle = angle;
279  zt_i.orientation = theta;
280  zt_i.pose = Pose2D ( x, y, theta );
281  zt->push_back( zt_i );
282  }
283 }
284 
285 void SLAMNode::callbackConfigSLAM ( tuw_marker_slam::SLAMConfig &config, uint32_t level ) {
286  ROS_INFO ( "callbackConfigSLAM!" );
287  config_ = config;
288 }
289 
290 void SLAMNode::callbackConfigEKFSLAM ( tuw_marker_slam::EKFSLAMConfig &config, uint32_t level ) {
291  ROS_INFO ( "callbackConfigEKFSLAM!" );
292  slam_technique_->setConfig ( &config );
293 }
void cycle()
constructor
std::string frame_id_map_
measurements are in x-z-plane (gazebo) instead of x-y-plane (stage)
std::vector< double > ids_confidence
ros::Subscriber sub_marker_
subscriber to the command
static void pointMsgToTF(const geometry_msgs::Point &msg_v, Point &bt_v)
void publish(const boost::shared_ptr< M > &message) const
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
static double getYaw(const Quaternion &bt_q)
std::shared_ptr< tf::TransformListener > tf_listener_
broadcasts transformation messages
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void callbackConfigSLAM(tuw_marker_slam::SLAMConfig &config, uint32_t level)
parameter server stuff general use
ros::Subscriber sub_cmd_
node handler to the current node
ROSCPP_DECL const std::string & getName()
TFSIMD_FORCE_INLINE const tfScalar & getY() const
void callbackConfigEKFSLAM(tuw_marker_slam::EKFSLAMConfig &config, uint32_t level)
parameter server stuff for the EKF SLAM
int main(int argc, char **argv)
SLAMTechniquePtr slam_technique_
counter for the triggered cycles
TFSIMD_FORCE_INLINE const tfScalar & y() const
TFSIMD_FORCE_INLINE const tfScalar & getZ() const
TFSIMD_FORCE_INLINE tfScalar angle(const Quaternion &q1, const Quaternion &q2)
std::string resolve(const std::string &prefix, const std::string &frame_name)
tuw_marker_slam::SLAMConfig config_
technique used to estimate landmark map and the vehicles pose in it
ros::Publisher pub_xt_
subscriber to the marker detector
bool xzplane_
listener to receive transformation messages
ros::Publisher pub_mt_
publisher for the estimated vehicle pose and its covariance
Definition: ekf_slam.h:8
static Quaternion createQuaternionFromYaw(double yaw)
static void quaternionMsgToTF(const geometry_msgs::Quaternion &msg, Quaternion &bt)
void getRPY(tfScalar &roll, tfScalar &pitch, tfScalar &yaw, unsigned int solution_number=1) const
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
std::string frame_id_base_
frame id of odom (for transformations)
cv::Mat_< double > C_Yt_
combined state yt = (xt, mt_1, ..., mt_n) with xt = (x, y, alpha), mt_i = (x_i, y_i, alpha_i)
ROSCPP_DECL bool ok()
void sendTransform(const StampedTransform &transform)
const std::string & getNamespace() const
void publish()
triggers the SLAM cycle
TFSIMD_FORCE_INLINE const tfScalar & x() const
Transform inverse() const
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
marker_msgs::MarkerWithCovarianceArray mt_
estimated vehicle pose and its covariance to publish
TFSIMD_FORCE_INLINE Vector3 & getOrigin()
TFSIMD_FORCE_INLINE const tfScalar & z() const
bool sleep()
SLAMNode(ros::NodeHandle &n)
std::shared_ptr< MeasurementMarker > MeasurementMarkerPtr
Prototype.
ros::Time stamp_
Command ut_
combined covariance matrix of combined state
void callbackCmd(const geometry_msgs::Twist &)
frame id of base (for transformations)
static geometry_msgs::Quaternion createQuaternionMsgFromYaw(double yaw)
Quaternion getRotation() const
MeasurementPtr zt_
motion commands v, w at time t
geometry_msgs::PoseWithCovarianceStamped xt_
publisher for the estimated landmark poses and their covariances
bool getParam(const std::string &key, std::string &s) const
TFSIMD_FORCE_INLINE const tfScalar & getX() const
static Time fromBoost(const boost::posix_time::ptime &t)
TFSIMD_FORCE_INLINE tfScalar length(const Quaternion &q)
std::string frame_id_odom_
frame id of map (for transformations)
dynamic_reconfigure::Server< tuw_marker_slam::SLAMConfig >::CallbackType reconfigureFncSLAM_
parameter server stuff general use
ros::NodeHandle n_param_
node handler to the root node
ros::NodeHandle n_
publishes the estimated landmark map and the estimated vehicle pose in it
ROSCPP_DECL void spinOnce()
#define ROS_ERROR(...)
dynamic_reconfigure::Server< tuw_marker_slam::SLAMConfig > reconfigureServerSLAM_
callback function to catch incoming marker data
std::vector< Pose2D > yt_
constructor
dynamic_reconfigure::Server< tuw_marker_slam::EKFSLAMConfig >::CallbackType reconfigureFncEKFSLAM_
parameter server stuff for the EKF SLAM
void callbackMarker(const marker_msgs::MarkerDetection &)
callback function to catch motion commands
tf::TransformBroadcaster tf_broadcaster_
estimated landmark poses and their covariances to publish
std::shared_ptr< dynamic_reconfigure::Server< tuw_marker_slam::EKFSLAMConfig > > reconfigureServerEKFSLAM_
callback function on incoming parameter changes for general use


tuw_marker_slam
Author(s): Markus Macsek
autogenerated on Mon Jun 10 2019 15:39:09