haptic_feedback.cpp
Go to the documentation of this file.
1 
15 
16 using namespace std;
17 
18 int simulator_state(4);
19 
20 
21 geometry_msgs::Vector3 operator-(const geometry_msgs::Point p0, const geometry_msgs::Point p1)
22 {
23  geometry_msgs::Vector3 v;
24 
25  v.x = p0.x - p1.x;
26  v.y = p0.y - p1.y;
27  v.z = p0.z - p1.z;
28 
29  return v;
30 }
31 
32 
33 geometry_msgs::Vector3 operator*(const double s, const geometry_msgs::Vector3 v)
34 {
35  geometry_msgs::Vector3 u;
36 
37  u.x = s*v.x;
38  u.y = s*v.y;
39  u.z = s*v.z;
40 
41  return u;
42 }
43 
44 
45 geometry_msgs::Point operator+(const geometry_msgs::Point p, const geometry_msgs::Vector3 v)
46 {
47  geometry_msgs::Point pb;
48 
49  pb.x = p.x + v.x;
50  pb.y = p.y + v.y;
51  pb.z = p.z + v.z;
52 
53  return pb;
54 }
55 
56 
57 geometry_msgs::Point FIR_cop(const geometry_msgs::Point cop_prev, const geometry_msgs::Point cop_new)
58 {
59  geometry_msgs::Point cop_filtered;
60  double beta = 0.2;
61 
62  cop_filtered.x = (1-beta)*cop_prev.x + beta*cop_new.x;
63  cop_filtered.y = (1-beta)*cop_prev.y + beta*cop_new.y;
64 
65  return cop_filtered;
66 }
67 
68 
69 /* Float-point filter implemented "on the fly" to compute the final force value,
70  * based on the current and the previous calculated values. */
71 geometry_msgs::Vector3 FIR_force(const geometry_msgs::Vector3 force_prev, const geometry_msgs::Vector3 force_new)
72 {
73  geometry_msgs::Vector3 force_filtered;
74  double beta = 0.4;
75 
76  force_filtered.x = (1-beta)*force_prev.x + beta*force_new.x;
77  force_filtered.y = (1-beta)*force_prev.y + beta*force_new.y;
78 
79  return force_filtered;
80 }
81 
82 
83 class Feedback
84 {
85  private:
86  ros::NodeHandle nh_;
87 
88  ros::Subscriber simulation_state_sub;
89  ros::Subscriber cop_global_position_sub;
90  ros::Subscriber support_base_position_sub;
91  ros::Subscriber phua_position_sub;
92 
93  ros::Publisher cop_global_filtered_pub;
96  ros::Publisher feedback_force_pub;
98 
99  geometry_msgs::PoseStamped phua_position;
100  geometry_msgs::PointStamped cop_global;
101  geometry_msgs::PolygonStamped support_base;
102 
103  geometry_msgs::PointStamped cop_filtered;
104  geometry_msgs::Vector3Stamped force;
105 
106  double distance_min;
108 
109  geometry_msgs::Vector3Stamped force_stability_prev, force_instability_prev;
110 
111 
112  public:
113  Feedback(ros::NodeHandle nh) : nh_(nh)
114  {
115  simulation_state_sub = nh_.subscribe("/vrep/info", 1000, &Feedback::simulationState, this);
116 
117  phua_position_sub = nh_.subscribe("/phua_position", 1000, &Feedback::phuaPosition, this);
118  cop_global_position_sub = nh_.subscribe("/cop_global_position", 1000, &Feedback::copPosition, this);
119  support_base_position_sub = nh_.subscribe("support_base_position", 1000, &Feedback::supportBaseDefinition, this);
120 
121  cop_global_filtered_pub = nh_.advertise<geometry_msgs::PointStamped>("/cop_global_filtered",1000);
122  feedback_force_stability_pub = nh_.advertise<geometry_msgs::Vector3Stamped>("/feedback_force_stability",1000);
123  feedback_force_instability_pub = nh_.advertise<geometry_msgs::Vector3Stamped>("/feedback_force_instability",1000);
124  feedback_force_pub = nh_.advertise<geometry_msgs::Vector3Stamped>("/feedback_force",1000);
125  feedback_force_filtered_pub = nh_.advertise<geometry_msgs::Vector3Stamped>("/feedback_force_filtered",1000);
126  }
127 
128 
129  void simulationState(const vrep_common::VrepInfo& msg)
130  {
131  if (simulator_state == 5 && msg.simulatorState.data == 4) /* Simulation stopped. */
132  ros::shutdown();
133 
134  simulator_state = msg.simulatorState.data;
135  simulationTime = msg.simulationTime.data;
136  }
137 
138 
139  void phuaPosition(const geometry_msgs::PoseStamped& msg)
140  {
141  phua_position.pose.position.x = msg.pose.position.x;
142  phua_position.pose.position.y = msg.pose.position.y;
143  phua_position.pose.position.z = msg.pose.position.z;
144  }
145 
146 
147  void copPosition(const geometry_msgs::PointStamped& msg)
148  {
149  geometry_msgs::PointStamped cop_global_new;
150 
151  cop_global_new.point.x = msg.point.x*1000;
152  cop_global_new.point.y = msg.point.y*1000;
153 
154  /* Chooese here if CoP position is filtered. */
155  /*cop_global.point = FIR_cop(cop_global.point, cop_global_new.point);*/
156  cop_global.point = cop_global_new.point;
157 
158  cop_global.header.stamp.sec = simulationTime*100000;
159  cop_global_filtered_pub.publish(cop_global);
160  }
161 
162 
163  /* Tests if CoP is within the support polygon. If so, the feedback force is calculated. */
164  void supportBaseDefinition(const geometry_msgs::PolygonStamped& msg)
165  {
166  support_base.polygon.points.clear();
167 
168  for (uint i=0; i<msg.polygon.points.size(); i++)
169  {
170  geometry_msgs::Point32 p;
171 
172  p.x = msg.polygon.points[i].x*1000;
173  p.y = msg.polygon.points[i].y*1000;
174  p.z = msg.polygon.points[i].z*1000;
175 
176  support_base.polygon.points.push_back(p);
177  }
178 
179  if (wn_PnPoly(cop_global.point, support_base.polygon) != 0)
180  {
181  vector<double> distance;
182 
183  for (uint i=0; i<support_base.polygon.points.size()-1; i++)
184  {
185  vector<geometry_msgs::Point> segment(2);
186 
187  segment[0].x = support_base.polygon.points[i].x;
188  segment[0].y = support_base.polygon.points[i].y;
189 
190  segment[1].x = support_base.polygon.points[i+1].x;
191  segment[1].y = support_base.polygon.points[i+1].y;
192 
193  distance.push_back(dist_PointSegment(cop_global.point, segment));
194  }
195 
196  distance_min = *min_element(distance.begin(), distance.end());
197 
198  /*cout << "Minimum distance to boundary: " << distance_min << endl;*/
199 
200  calculateFeedback(cop_global, distance_min);
201  }
202  else
203  ROS_ERROR("Center of Pressure is beyond support polygon boundary. System unstable!");
204  }
205 
206 
207  /* Implementation of the force rendering algorithm that compares the CoP position with the real support polygon size
208  * and establishes a metric of stability/instability. The force vector synthesized is determined by a function that expresses
209  * simultaneously the CoP approximation to the robot's feet edges (F2), and its separation from the most stable position (F1). */
210  void calculateFeedback(geometry_msgs::PointStamped cop, double distance)
211  {
212  geometry_msgs::Vector3Stamped force_stability, force_instability, force_new;
213 
214  double cop_s = sqrt(cop.point.x*cop.point.x + cop.point.y*cop.point.y);
215 
216  /*cout << "Minimum distance from origin: " << cop_s << endl;*/
217 
218  double a1 = 0.35, b1 = 40, c1=0.2;
219  double a2 = 0.35, b2 = 16.89733, c2=0.2;
220 
221  double force_f1, force_f2;
222 
223  if (cop_s < 5)
224  force_f1 = 0;
225  else if (cop_s >= 5 && cop_s < 28.4490)
226  force_f1 = (0.025*cop_s - 0.125);
227  else if (cop_s >= 28.4490 && cop_s < 40)
228  force_f1 = (1/(c1*(1+exp(-a1*(cop_s - b1)))) + 0.5);
229  else if (cop_s >= 40)
230  force_f1 = 3;
231 
232  if (distance > 51.8972)
233  force_f2 = 0;
234  else if (distance <= 51.8972 && distance > 28.4490)
235  force_f2 = (-(0.025)*(distance) + (1.29743));
236  else if (distance <= 28.4490 && distance > 16.89733)
237  force_f2 = (1/(c2*(1+exp(a2*((distance) - b2)))) + 0.5);
238  else if (distance <= 16.89733)
239  force_f2 = 3;
240 
241  double r1 = (1*force_f1)/cop_s;
242  double r2 = (1*force_f2)/cop_s;
243 
244  force_stability.vector.x = (cop.point.x * r1);
245  force_stability.vector.y = cop.point.y * r1;
246  force_stability.vector.z = 0;
247 
248  force_instability.vector.x = cop.point.x * r2;
249  force_instability.vector.y = cop.point.y * r2;
250  force_instability.vector.z = 0;
251 
252  /*if (force_stability.vector.x < 0 && phua_position.pose.position.x < 0)
253  force_stability.vector.x = force_stability.vector.x;
254  else if (force_stability.vector.x < 0 && phua_position.pose.position.x > 0)
255  force_stability.vector.x = -force_stability.vector.x;
256  else if (force_stability.vector.x > 0 && phua_position.pose.position.x > 0)
257  force_stability.vector.x = force_stability.vector.x;
258  else if (force_stability.vector.x > 0 && phua_position.pose.position.x < 0)
259  force_stability.vector.x = -force_stability.vector.x;
260 
261  if (force_stability.vector.y < 0 && phua_position.pose.position.y < 0)
262  force_stability.vector.y = force_stability.vector.y;
263  else if (force_stability.vector.y < 0 && phua_position.pose.position.y > 0)
264  force_stability.vector.y = -force_stability.vector.y;
265  else if (force_stability.vector.y > 0 && phua_position.pose.position.y > 0)
266  force_stability.vector.y = force_stability.vector.y;
267  else if (force_stability.vector.y > 0 && phua_position.pose.position.y < 0)
268  force_stability.vector.y = -force_stability.vector.y;*/
269 
270  force_stability.header.stamp.sec = simulationTime*100000;
271  feedback_force_stability_pub.publish(force_stability);
272 
273  force_instability.header.stamp.sec = simulationTime*100000;
274  feedback_force_instability_pub.publish(force_instability);
275 
276  double vm_stability_x, vm_stability_y;
277  double vm_instability_x, vm_instability_y;
278 
279  if (force_stability.vector.x - force_stability_prev.vector.x != 0)
280  vm_stability_x = (force_stability.vector.x - force_stability_prev.vector.x) / 0.05;
281  else
282  vm_stability_x = (force_stability.vector.x) / 0.05;
283 
284  if (force_instability.vector.x - force_instability_prev.vector.x != 0)
285  vm_instability_x = (force_instability.vector.x - force_instability_prev.vector.x) / 0.05;
286  else
287  vm_instability_x = (force_instability.vector.x) / 0.05;
288 
289  if (force_stability.vector.y - force_stability_prev.vector.y != 0)
290  vm_stability_y = (force_stability.vector.y - force_stability_prev.vector.y) / 0.05;
291  else
292  vm_stability_y = (force_stability.vector.y) / 0.05;
293 
294  if (force_instability.vector.y - force_instability_prev.vector.y != 0)
295  vm_instability_y = (force_instability.vector.y - force_instability_prev.vector.y) / 0.05;
296  else
297  vm_instability_y = (force_instability.vector.y) / 0.05;
298 
299  double rvm_x, rvm_y;
300 
301  rvm_x = abs(vm_instability_x / vm_stability_x);
302  rvm_y = abs(vm_instability_y / vm_stability_y);
303 
304  force_new.vector.x = (rvm_x/(rvm_x+1)) * force_instability.vector.x + (1/(rvm_x+1)) * force_stability.vector.x;
305  force_new.vector.y = (rvm_y/(rvm_y+1)) * force_instability.vector.y + (1/(rvm_y+1)) * force_stability.vector.y;
306  force_new.vector.z = 0;
307 
308  if (force_instability.vector.x == 0 || force_stability.vector.x == 0)
309  force_new.vector.x = force_instability.vector.x + force_stability.vector.x;
310 
311  if (force_instability.vector.y == 0 || force_stability.vector.y == 0)
312  force_new.vector.y = force_instability.vector.y + force_stability.vector.y;
313 
314  force_new.header.stamp.sec = simulationTime*100000;
315  feedback_force_pub.publish(force_new);
316 
317  /* Chooese here if force is filtered */
318  force.vector = FIR_force(force.vector, force_new.vector);
319  /* force.vector = force_new.vector; */
320 
321  cout << "Force vector filtered = " << '(' << force.vector.x << ", " << force.vector.y << ')' << endl;
322  cout << "--------------------------------------" << endl;
323 
324  force.header.stamp.sec = simulationTime*100000;
325  feedback_force_filtered_pub.publish(force);
326 
327  force_stability_prev = force_stability;
328  force_instability_prev = force_instability;
329  }
330 
331 
332  /* Tests if a point is Left|On|Right of an infinite line. */
333  int isLeft(geometry_msgs::Point32 p0, geometry_msgs::Point32 p1, geometry_msgs::Point p2)
334  {
335  return ((p1.x - p0.x)*(p2.y - p0.y) - (p2.x - p0.x)*(p1.y - p0.y));
336  }
337 
338 
339  /* Winding number test for a point in a polygon. */
340  int wn_PnPoly(geometry_msgs::Point p, geometry_msgs::Polygon poly)
341  {
342  int n = poly.points.size()-1; /* polygon size */
343 
344  int wn = 0; /* the winding number counter */
345 
346  /* Loop through all edges of the polygon. */
347  for (int i=0; i<n; i++) /* edge from poly[i] to poly[i+1] */
348  {
349  if (poly.points[i].y <= p.y)
350  {
351  if (poly.points[i+1].y > p.y)
352  {
353  if (isLeft(poly.points[i], poly.points[i+1], p) > 0)
354  ++wn;
355  }
356  }
357  else
358  {
359  if (poly.points[i+1].y <= p.y)
360  {
361  if (isLeft(poly.points[i], poly.points[i+1], p) < 0)
362  --wn;
363  }
364  }
365  }
366 
367  return wn;
368  }
369 
370 
371  double dot(geometry_msgs::Vector3 u, geometry_msgs::Vector3 v)
372  {
373  return (u.x*v.x + u.y*v.y + u.z*v.z);
374  }
375 
376 
377  double norm(geometry_msgs::Vector3 v)
378  {
379  return (sqrt(dot(v,v)));
380  }
381 
382 
383  double d(geometry_msgs::Point p0, geometry_msgs::Point p1)
384  {
385  return (norm(p0-p1));
386  }
387 
388 
389  /* Calculates the distance from a 2D-point to a line segment. */
390  double dist_PointSegment(geometry_msgs::Point p, vector<geometry_msgs::Point> seg_point)
391  {
392  geometry_msgs::Vector3 v = seg_point[1] - seg_point[0];
393 
394  geometry_msgs::Vector3 w = p - seg_point[0];
395 
396  double c1 = dot(w,v);
397  if (c1 <= 0)
398  return d(p, seg_point[0]);
399 
400  double c2 = dot(v,v);
401  if (c2 <= c1)
402  return d(p, seg_point[1]);
403 
404  double b = c1/c2;
405  geometry_msgs::Point pb = seg_point[0] + b*v;
406  return d(p, pb);
407  }
408 
409 };
410 
411 
412 int main(int argc, char **argv)
413 {
414  ros::init(argc, argv, "haptic_feedback");
415  ros::NodeHandle n;
416 
417  Feedback phantom(n);
418 
419  ros::spin();
420 
421  return 0;
422 }
ros::Publisher feedback_force_filtered_pub
geometry_msgs::Vector3 FIR_force(const geometry_msgs::Vector3 force_prev, const geometry_msgs::Vector3 force_new)
ros::Publisher cop_global_filtered_pub
ros::Subscriber simulation_state_sub
geometry_msgs::Vector3 operator*(const double s, const geometry_msgs::Vector3 v)
geometry_msgs::Point operator+(const geometry_msgs::Point p, const geometry_msgs::Vector3 v)
geometry_msgs::PointStamped cop_global
geometry_msgs::Vector3Stamped force_stability_prev
geometry_msgs::Vector3 operator-(const geometry_msgs::Point p0, const geometry_msgs::Point p1)
geometry_msgs::PolygonStamped support_base
void phuaPosition(const geometry_msgs::PoseStamped &msg)
ros::Subscriber support_base_position_sub
Feedback(ros::NodeHandle nh)
geometry_msgs::PoseStamped phua_position
int simulator_state(4)
geometry_msgs::Point FIR_cop(const geometry_msgs::Point cop_prev, const geometry_msgs::Point cop_new)
ros::Subscriber simulation_state_sub
double dot(geometry_msgs::Vector3 u, geometry_msgs::Vector3 v)
double simulationTime
ros::Publisher feedback_force_instability_pub
ros::Publisher feedback_force_stability_pub
geometry_msgs::Vector3Stamped force
ros::Subscriber phua_position_sub
int main(int argc, char **argv)
void copPosition(const geometry_msgs::PointStamped &msg)
void supportBaseDefinition(const geometry_msgs::PolygonStamped &msg)
ros::Publisher feedback_force_pub
double distance_min
int isLeft(geometry_msgs::Point32 p0, geometry_msgs::Point32 p1, geometry_msgs::Point p2)
double simulationTime(0)
void simulationState(const vrep_common::VrepInfo &msg)
ros::Subscriber cop_global_position_sub
geometry_msgs::PointStamped cop_filtered
void calculateFeedback(geometry_msgs::PointStamped cop, double distance)
int wn_PnPoly(geometry_msgs::Point p, geometry_msgs::Polygon poly)
ros::NodeHandle nh_
double d(geometry_msgs::Point p0, geometry_msgs::Point p1)
double norm(geometry_msgs::Vector3 v)
double dist_PointSegment(geometry_msgs::Point p, vector< geometry_msgs::Point > seg_point)


humanoid_simulation
Author(s): João Barros
autogenerated on Mon Mar 2 2015 01:31:43