kinematics_exchanger.cpp
Go to the documentation of this file.
1 #include "kinematics_exchanger.h"
2 
9 float acc_sin (float x, float y) {
10  return x + sin(y);
11 }
12 
19 float acc_cos (float x, float y) {
20  return x + cos(y);
21 }
22 
27 double get_yaw ()
28 {
29  tf2::Quaternion orientation;
30  tf2::fromMsg(pose.orientation, orientation);
31  return tf2::getYaw(orientation);
32 }
33 
39 cpswarm_msgs::Vector rel_velocity (geometry_msgs::Vector3 v)
40 {
41  // compute relative velocity
42  double dx = v.x - velo.linear.x;
43  double dy = v.y - velo.linear.y;
44  double mag = hypot(dx, dy);
45  double dir = atan2(dy, dx);
46 
47  // return relative velocity
48  cpswarm_msgs::Vector rel_vel;
49  rel_vel.magnitude = mag;
50  rel_vel.direction = dir;
51  return rel_vel;
52 }
53 
58 void pose_callback (const geometry_msgs::PoseStamped::ConstPtr& msg)
59 {
60  // valid pose received
61  if (msg->header.stamp.isValid())
62  pose_valid = true;
63 
64  // store new position and orientation in class variables
65  pose = msg->pose;
66 }
67 
72 void vel_callback (const geometry_msgs::TwistStamped::ConstPtr& msg)
73 {
74  // valid pose received
75  if (msg->header.stamp.isValid())
76  vel_valid = true;
77 
78  velo = msg->twist;
79 }
80 
85 void swarm_position_callback (cpswarm_msgs::Position msg) {
86  // the first messages are inaccurate, drop them
87  if (pos_init > 0) {
88  pos_init -= 1;
89  return;
90  }
91 
92  // uuid of the sending swarm member
93  string uuid = msg.swarmio.node;
94 
95  // add new swarm member
96  if (swarm_positions.count(uuid) <= 0) {
97  cartesian_vector_t data;
98  data.uuid = uuid;
99  swarm_positions.emplace(uuid, data);
100  }
101  if (swarm_positions_rel.count(uuid) <= 0) {
102  polar_vector_t data;
103  data.uuid = uuid;
104  swarm_positions_rel.emplace(uuid, data);
105  }
106 
107  // update swarm member
108  swarm_positions[uuid].x.push_back(msg.pose.position.x);
109  swarm_positions[uuid].y.push_back(msg.pose.position.y);
110  swarm_positions[uuid].stamp = Time::now();
111  swarm_positions_rel[uuid].mag.push_back(hypot(msg.pose.position.x - pose.position.x, msg.pose.position.y - pose.position.y));
112  swarm_positions_rel[uuid].dir.push_back(remainder((atan2(msg.pose.position.y - pose.position.y, msg.pose.position.x - pose.position.x) - get_yaw()), 2*M_PI));
113  swarm_positions_rel[uuid].stamp = Time::now();
114 
115  // remove old samples
116  while (swarm_positions[uuid].x.size() > sample_size)
117  swarm_positions[uuid].x.erase(swarm_positions[uuid].x.begin());
118  while(swarm_positions[uuid].y.size() > sample_size)
119  swarm_positions[uuid].y.erase(swarm_positions[uuid].y.begin());
120  while (swarm_positions_rel[uuid].mag.size() > sample_size)
121  swarm_positions_rel[uuid].mag.erase(swarm_positions_rel[uuid].mag.begin());
122  while(swarm_positions_rel[uuid].dir.size() > sample_size)
123  swarm_positions_rel[uuid].dir.erase(swarm_positions_rel[uuid].dir.begin());
124 }
125 
130 void swarm_velocity_callback (cpswarm_msgs::Velocity msg) {
131  // the first messages are inaccurate, drop them
132  if (vel_init > 0) {
133  vel_init -= 1;
134  return;
135  }
136 
137  // uuid of the sending swarm member
138  string uuid = msg.swarmio.node;
139 
140  // add new swarm member
141  if (swarm_velocities.count(uuid) <= 0) {
142  polar_vector_t data;
143  data.uuid = uuid;
144  swarm_velocities.emplace(uuid, data);
145  }
146 
147  // update swarm member
148  cpswarm_msgs::Vector velocity = rel_velocity(msg.velocity.linear);
149  swarm_velocities[uuid].mag.push_back(velocity.magnitude);
150  swarm_velocities[uuid].dir.push_back(velocity.direction);
151  swarm_velocities[uuid].stamp = Time::now();
152 
153  // remove old samples
154  while (swarm_velocities[uuid].mag.size() > sample_size)
155  swarm_velocities[uuid].mag.erase(swarm_velocities[uuid].mag.begin());
156  while(swarm_velocities[uuid].dir.size() > sample_size)
157  swarm_velocities[uuid].dir.erase(swarm_velocities[uuid].dir.begin());
158 }
159 
166 int main (int argc, char **argv)
167 {
168  // init ros node
169  init(argc, argv, "kinematics_exchanger");
170  NodeHandle nh;
171 
172  // read parameters
173  double loop_rate;
174  nh.param(this_node::getName() + "/loop_rate", loop_rate, 1.5);
175  int queue_size;
176  nh.param(this_node::getName() + "/queue_size", queue_size, 10);
177  double timeout;
178  nh.param(this_node::getName() + "/timeout", timeout, 20.0);
179  nh.param(this_node::getName() + "/sample_size", sample_size, 5);
180  nh.param(this_node::getName() + "/init", pos_init, 30);
181  nh.param(this_node::getName() + "/init", vel_init, 30);
182 
183  // publishers and subscribers
184  Subscriber pose_subscriber = nh.subscribe("pos_provider/pose", queue_size, pose_callback);
185  Subscriber vel_subscriber = nh.subscribe("vel_provider/velocity", queue_size, vel_callback);
186  Subscriber incoming_position_subscriber = nh.subscribe("bridge/events/position", queue_size, swarm_position_callback);
187  Subscriber incoming_velocity_subscriber = nh.subscribe("bridge/events/velocity", queue_size, swarm_velocity_callback);
188  Publisher outgoing_position_publisher = nh.advertise<cpswarm_msgs::Position>("position", queue_size);
189  Publisher outgoing_velocity_publisher = nh.advertise<cpswarm_msgs::Velocity>("velocity", queue_size);
190  Publisher incoming_position_publisher = nh.advertise<cpswarm_msgs::ArrayOfPositions>("swarm_position", queue_size);
191  Publisher incoming_rel_position_publisher = nh.advertise<cpswarm_msgs::ArrayOfVectors>("swarm_position_rel", queue_size);
192  Publisher incoming_rel_velocity_publisher = nh.advertise<cpswarm_msgs::ArrayOfVectors>("swarm_velocity_rel", queue_size);
193 
194  // init loop rate
195  Rate rate(loop_rate);
196 
197  // init position and velocity
198  pose_valid = false;
199  vel_valid = false;
200  while (ok() && (pose_valid == false || vel_valid == false)) {
201  ROS_DEBUG_ONCE("Waiting for valid pose and velocity ...");
202  rate.sleep();
203  spinOnce();
204  }
205 
206  // init swarm kinematics messages
207  cpswarm_msgs::ArrayOfPositions swarm_position;
208  cpswarm_msgs::ArrayOfVectors swarm_position_rel;
209  cpswarm_msgs::ArrayOfVectors swarm_velocity_rel;
210 
211  // continuously exchange kinematics between swarm members
212  while (ok()) {
213  // reset swarm kinematics messages
214  swarm_position.positions.clear();
215  swarm_position_rel.vectors.clear();
216  swarm_velocity_rel.vectors.clear();
217 
218  // update absolute swarm position
219  for (auto member=swarm_positions.begin(); member!=swarm_positions.end();) {
220  // delete members that haven't updated their position lately
221  if ((Time::now() - member->second.stamp) > Duration(timeout)) {
222  member = swarm_positions.erase(member);
223  continue;
224  }
225 
226  // only consider members with enough samples
227  if (member->second.x.size() >= sample_size) {
228  // calculate average of swarm member position data
229  cpswarm_msgs::Position position;
230  position.header.stamp = Time::now();
231  position.swarmio.node = member->first;
232 
233  // average coordinates
234  position.pose.position.x = accumulate(member->second.x.begin(), member->second.x.end(), 0.0) / member->second.x.size();
235  position.pose.position.y = accumulate(member->second.y.begin(), member->second.y.end(), 0.0) / member->second.y.size();
236 
237  // store averaged position of swarm member
238  swarm_position.positions.push_back(position);
239  }
240 
241  // next member
242  ++member;
243  }
244 
245  // update relative swarm position
246  for (auto member=swarm_positions_rel.begin(); member!=swarm_positions_rel.end();) {
247  // delete members that haven't updated their position lately
248  if ((Time::now() - member->second.stamp) > Duration(timeout)) {
249  member = swarm_positions_rel.erase(member);
250  continue;
251  }
252 
253  // only consider members with enough samples
254  if (member->second.mag.size() >= sample_size) {
255  // calculate average of swarm member position data
256  cpswarm_msgs::VectorStamped position;
257  position.header.stamp = Time::now();
258  position.swarmio.node = member->first;
259 
260  // average magnitude
261  position.vector.magnitude = accumulate(member->second.mag.begin(), member->second.mag.end(), 0.0) / member->second.mag.size();
262 
263  // average direction correctly using sines and cosines (avoid jump from 2π to 0)
264  float sines = accumulate(member->second.dir.begin(), member->second.dir.end(), 0.0, acc_sin) / member->second.dir.size();
265  float cosines = accumulate(member->second.dir.begin(), member->second.dir.end(), 0.0, acc_cos) / member->second.dir.size();
266  position.vector.direction = atan2(sines, cosines);
267 
268  // store averaged position of swarm member
269  swarm_position_rel.vectors.push_back(position);
270  }
271 
272  // next member
273  ++member;
274  }
275 
276  // update swarm velocity
277  for (auto member=swarm_velocities.begin(); member!=swarm_velocities.end();) {
278  // delete members that haven't updated their velocity lately
279  if ((Time::now() - member->second.stamp) > Duration(timeout)) {
280  member = swarm_velocities.erase(member);
281  continue;
282  }
283 
284  // only consider members with enough samples
285  if (member->second.mag.size() >= sample_size) {
286  // calculate average of swarm member velocity data
287  cpswarm_msgs::VectorStamped velocity;
288  velocity.header.stamp = Time::now();
289  velocity.swarmio.node = member->first;
290 
291  // average magnitude
292  velocity.vector.magnitude = accumulate(member->second.mag.begin(), member->second.mag.end(), 0.0) / member->second.mag.size();
293 
294  // average direction correctly using sines and cosines (avoid jump from 2π to 0)
295  float sines = accumulate(member->second.dir.begin(), member->second.dir.end(), 0.0, acc_sin) / member->second.dir.size();
296  float cosines = accumulate(member->second.dir.begin(), member->second.dir.end(), 0.0, acc_cos) / member->second.dir.size();
297  velocity.vector.direction = atan2(sines, cosines);
298 
299  // store averaged velocity of swarm member
300  swarm_velocity_rel.vectors.push_back(velocity);
301  }
302 
303  // next member
304  ++member;
305  }
306 
307  // publish swarm kinematics locally
308  incoming_position_publisher.publish(swarm_position);
309  incoming_rel_position_publisher.publish(swarm_position_rel);
310  incoming_rel_velocity_publisher.publish(swarm_velocity_rel);
311 
312  // publish local kinematics to swarm
313  cpswarm_msgs::Position position;
314  position.header.stamp = Time::now();
315  position.swarmio.name = "position";
316  position.pose = pose;
317  outgoing_position_publisher.publish(position);
318  cpswarm_msgs::Velocity velocity;
319  velocity.header.stamp = Time::now();
320  velocity.swarmio.name = "velocity";
321  velocity.velocity = velo;
322  outgoing_velocity_publisher.publish(velocity);
323 
324  rate.sleep();
325  spinOnce();
326  }
327 }
geometry_msgs::Pose pose
Current position of the CPS.
float acc_sin(float x, float y)
Accumulate sines.
void swarm_velocity_callback(cpswarm_msgs::Velocity msg)
Callback function for velocity updates from other swarm members.
double get_yaw()
Get the yaw orientation of the current pose.
int sample_size
The number of data samples to average over for reliable results.
int pos_init
The number of position messages to ignore during initialization. This is because the first messages a...
int main(int argc, char **argv)
A ROS node that exchanges relative kinematics between CPSs in a swarm.
A vector type in polar format containing UUID of the corresponding CPS together with last updated tim...
void swarm_position_callback(cpswarm_msgs::Position msg)
Callback function for position updates from other swarm members.
bool vel_valid
Whether a valid velocity has been received.
map< string, polar_vector_t > swarm_positions_rel
The relative positions of all known swarm members.
geometry_msgs::Twist velo
Current velocity of the CPS.
bool pose_valid
Whether a valid position has been received.
map< string, polar_vector_t > swarm_velocities
The velocities of all known swarm members.
float acc_cos(float x, float y)
Accumulate cosines.
void vel_callback(const geometry_msgs::TwistStamped::ConstPtr &msg)
Callback function for velocity updates.
A vector type in Cartesian format containing UUID of the corresponding CPS together with last updated...
int vel_init
The number of velocity messages to ignore during initialization. This is because the first messages a...
void pose_callback(const geometry_msgs::PoseStamped::ConstPtr &msg)
Callback function for position updates.
map< string, cartesian_vector_t > swarm_positions
The absolute positions of all known swarm members.
cpswarm_msgs::Vector rel_velocity(geometry_msgs::Vector3 v)
Compute the velocity difference of the CPS to a given velocity.


kinematics_exchanger
Author(s): Micha Sende
autogenerated on Thu Oct 31 2019 10:52:41