summit_xl_robot_control_vrep.cpp
Go to the documentation of this file.
1 /*
2  * summit_xl_robot_control_vrep
3  * Copyright (c) 2014, Robotnik Automation, SLL
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * * Neither the name of the Robotnik Automation, SLL. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * \author Robotnik
31  * \brief Controller for the Summit XL robot in skid-steering / mecanum omni-drive modes.
32  * \brief simulation of 4DOF Mecanum kinematics by equivalent 8DOF Swerve drive
33  */
34 
35 #include <ros/ros.h>
36 #include <sensor_msgs/JointState.h>
37 #include <sensor_msgs/Imu.h>
38 #include <geometry_msgs/Twist.h>
39 #include <std_msgs/Float64.h>
41 #include <nav_msgs/Odometry.h>
42 #include <robotnik_msgs/set_mode.h>
43 #include <robotnik_msgs/get_mode.h>
44 #include <robotnik_msgs/set_odometry.h>
45 #include <robotnik_msgs/ptz.h>
46 
47 
48 //#include "self_test/self_test.h"
49 #include "diagnostic_msgs/DiagnosticStatus.h"
54 
55 
56 #define PI 3.1415926535
57 #define SUMMIT_XL_MIN_COMMAND_REC_FREQ 5.0
58 #define SUMMIT_XL_MAX_COMMAND_REC_FREQ 150.0
59 
60 #define SKID_STEERING 1
61 #define MECANUM_STEERING 2
62 
63 #define SUMMIT_XL_WHEEL_DIAMETER 0.25 // Default wheel diameter
64 #define SUMMIT_XL_D_TRACKS_M 1.0 // default equivalent W distance (difference is due to slippage of skid steering)
65 #define SUMMIT_XL_WHEELBASE 0.446 // default real L distance forward to rear axis
66 #define SUMMIT_XL_TRACKWIDTH 0.408 // default real W distance from left wheels to right wheels
67 
68 using namespace std;
69 
71 
72 public:
73 
74  ros::NodeHandle node_handle_;
75  ros::NodeHandle private_node_handle_;
76  double desired_freq_;
77 
78  // Diagnostics
79  diagnostic_updater::Updater diagnostic_; // General status diagnostic updater
80  diagnostic_updater::FrequencyStatus freq_diag_; // Component frequency diagnostics
81  diagnostic_updater::HeaderlessTopicDiagnostic *subs_command_freq; // Topic reception frequency diagnostics
82  ros::Time last_command_time_; // Last moment when the component received a command
84 
85  // Robot model
86  std::string robot_model_;
87 
88  // Velocity and position references to low level controllers
89  ros::Publisher ref_vel_flw_;
90  ros::Publisher ref_vel_frw_;
91  ros::Publisher ref_vel_blw_;
92  ros::Publisher ref_vel_brw_;
93  ros::Publisher ref_pos_flw_;
94  ros::Publisher ref_pos_frw_;
95  ros::Publisher ref_pos_blw_;
96  ros::Publisher ref_pos_brw_;
97  ros::Publisher ref_pos_scissor_;
98  ros::Publisher ref_pos_pan_;
99  ros::Publisher ref_pos_tilt_;
100 
101  // Joint states published by the joint_state_controller of the Controller Manager
102  ros::Subscriber joint_state_sub_;
103 
104  // High level robot command
105  ros::Subscriber cmd_sub_;
106 
107  // High level robot command
108  ros::Subscriber ptz_sub_;
109 
110  //ros::Subscriber gyro_sub_;
111 
112  // Services
113  ros::ServiceServer srv_SetOdometry_;
114  ros::ServiceServer srv_SetMode_;
115  ros::ServiceServer srv_GetMode_;
116 
117  // Topics - skid - velocity
118  std::string frw_vel_topic_;
119  std::string flw_vel_topic_;
120  std::string brw_vel_topic_;
121  std::string blw_vel_topic_;
122 
123  // Joint names - skid - velocity
124  std::string joint_front_right_wheel;
125  std::string joint_front_left_wheel;
126  std::string joint_back_left_wheel;
127  std::string joint_back_right_wheel;
128 
129  // Topics - swerve - position
130  std::string frw_pos_topic_;
131  std::string flw_pos_topic_;
132  std::string brw_pos_topic_;
133  std::string blw_pos_topic_;
134 
135  // Joint names - swerve - position
136  std::string joint_front_right_steer;
137  std::string joint_front_left_steer;
138  std::string joint_back_left_steer;
139  std::string joint_back_right_steer;
140 
141  // Topic - scissor - position
142  std::string scissor_pos_topic_;
143 
144  // Joint names - ptz - position
145  std::string joint_camera_pan;
146  std::string joint_camera_tilt;
147 
148  // Topics - ptz
149  std::string pan_pos_topic_;
150  std::string tilt_pos_topic_;
151 
152  // Joint name - scissor mechanism
153  std::string scissor_prismatic_joint;
154 
155  // Selected operation mode
156  int kinematic_modes_;
157  int active_kinematic_mode_;
158 
159  // Indexes to joint_states
160  int frw_vel_, flw_vel_, blw_vel_, brw_vel_;
161  int frw_pos_, flw_pos_, blw_pos_, brw_pos_;
162  int scissor_pos_;
163  int pan_pos_, tilt_pos_;
164 
165 
166  // Robot Speeds
167  double linearSpeedXMps_;
168  double linearSpeedYMps_;
169  double angularSpeedRads_;
170 
171  // Robot Positions
172  double robot_pose_px_;
173  double robot_pose_py_;
174  double robot_pose_pa_;
175  double robot_pose_vx_;
176  double robot_pose_vy_;
177 
178  // Robot Joint States
179  sensor_msgs::JointState joint_state_;
180 
181  // Command reference
182  geometry_msgs::Twist base_vel_msg_;
183 
184  // External speed references
185  double v_ref_x_;
186  double v_ref_y_;
187  double w_ref_;
188  double v_ref_z_;
189  double pos_ref_pan_;
190  double pos_ref_tilt_;
191 
192  // Flag to indicate if joint_state has been read
193  bool read_state_;
194 
195  // Robot configuration parameters
196  double summit_xl_wheel_diameter_;
197  double summit_xl_d_tracks_m_;
198  double summit_xl_wheelbase_;
199  double summit_xl_trackwidth_;
200 
201  // IMU values
202  double ang_vel_x_;
203  double ang_vel_y_;
204  double ang_vel_z_;
205 
206  double lin_acc_x_;
207  double lin_acc_y_;
208  double lin_acc_z_;
209 
210  double orientation_x_;
211  double orientation_y_;
212  double orientation_z_;
213  double orientation_w_;
214 
215  // Parameter that defines if odom tf is published or not
216  bool publish_odom_tf_;
217 
218  ros::Subscriber imu_sub_;
219 
220  // Publisher for odom topic
221  ros::Publisher odom_pub_;
222 
223  // Broadcaster for odom tf
224  tf::TransformBroadcaster odom_broadcaster;
225 
226 
231  node_handle_(h), private_node_handle_("~"),
232  desired_freq_(100),
233  freq_diag_(diagnostic_updater::FrequencyStatusParam(&desired_freq_, &desired_freq_, 0.05) ),
234  command_freq_("Command frequency check", boost::bind(&SummitXLControllerClass::check_command_subscriber, this, _1))
235  {
236 
237  // /summit_xl/joint_blw_velocity_controller/joint
238  ROS_INFO("summit_xl_robot_control_node - Init ");
239 
240  // 4-Axis Skid Steer Rover
241  // 8-Axis Omni-drive as 4-Axis Mecanum drive
242  kinematic_modes_ = 1;
243 
244  ros::NodeHandle summit_xl_robot_control_node_handle(node_handle_, "summit_xl_robot_control");
245 
246  // Get robot model from the parameters
247  if (!private_node_handle_.getParam("model", robot_model_)) {
248  ROS_ERROR("Robot model not defined.");
249  exit(-1);
250  }
251  else ROS_INFO("Robot Model : %s", robot_model_.c_str());
252 
253  // Skid configuration - topics
254  private_node_handle_.param<std::string>("frw_vel_topic", frw_vel_topic_, "/summit_xl/joint_frw_velocity_controller/command");
255  private_node_handle_.param<std::string>("flw_vel_topic", flw_vel_topic_, "/summit_xl/joint_flw_velocity_controller/command");
256  private_node_handle_.param<std::string>("blw_vel_topic", blw_vel_topic_, "/summit_xl/joint_blw_velocity_controller/command");
257  private_node_handle_.param<std::string>("brw_vel_topic", brw_vel_topic_, "/summit_xl/joint_brw_velocity_controller/command");
258 
259  // Skid configuration - Joint names
260  private_node_handle_.param<std::string>("joint_front_right_wheel", joint_front_right_wheel, "joint_front_right_wheel");
261  private_node_handle_.param<std::string>("joint_front_left_wheel", joint_front_left_wheel, "joint_front_left_wheel");
262  private_node_handle_.param<std::string>("joint_back_left_wheel", joint_back_left_wheel, "joint_back_left_wheel");
263  private_node_handle_.param<std::string>("joint_back_right_wheel", joint_back_right_wheel, "joint_back_right_wheel");
264 
265  // Omni configuration - topics
266  if ((robot_model_=="summit_xl_omni") || (robot_model_=="x_wam")) {
267  kinematic_modes_ = 2;
268  private_node_handle_.param<std::string>("frw_pos_topic", frw_pos_topic_, "/summit_xl/joint_frw_velocity_controller/command");
269  private_node_handle_.param<std::string>("flw_pos_topic", flw_pos_topic_, "/summit_xl/joint_flw_velocity_controller/command");
270  private_node_handle_.param<std::string>("blw_pos_topic", blw_pos_topic_, "/summit_xl/joint_blw_velocity_controller/command");
271  private_node_handle_.param<std::string>("brw_pos_topic", brw_pos_topic_, "/summit_xl/joint_brw_velocity_controller/command");
272 
273  private_node_handle_.param<std::string>("joint_front_right_steer", joint_front_right_steer, "joint_front_right_steer");
274  private_node_handle_.param<std::string>("joint_front_left_steer", joint_front_left_steer, "joint_front_left_steer");
275  private_node_handle_.param<std::string>("joint_back_left_steer", joint_back_left_steer, "joint_back_left_steer");
276  private_node_handle_.param<std::string>("joint_back_right_steer", joint_back_right_steer, "joint_back_right_steer");
277 
278  if (!private_node_handle_.getParam("summit_xl_wheelbase", summit_xl_wheelbase_))
279  summit_xl_wheelbase_ = SUMMIT_XL_WHEELBASE;
280  if (!private_node_handle_.getParam("summit_xl_trackwidth", summit_xl_trackwidth_))
281  summit_xl_trackwidth_ = SUMMIT_XL_TRACKWIDTH;
282 
283  // x-wam only configuration
284  if (robot_model_=="x_wam") {
285  private_node_handle_.param<std::string>("scissor_pos_topic", scissor_pos_topic_, "/summit_xl/joint_scissor_position_controller/command");
286  private_node_handle_.param<std::string>("scissor_prismatic_joint", scissor_prismatic_joint, "scissor_prismatic_joint");
287  }
288  }
289 
290  // PTZ topics
291  private_node_handle_.param<std::string>("pan_pos_topic", pan_pos_topic_, "/summit_xl/joint_pan_position_controller/command");
292  private_node_handle_.param<std::string>("tilt_pos_topic", tilt_pos_topic_, "/summit_xl/joint_tilt_position_controller/command");
293  private_node_handle_.param<std::string>("joint_camera_pan", joint_camera_pan, "joint_camera_pan");
294  private_node_handle_.param<std::string>("joint_camera_tilt", joint_camera_tilt, "joint_camera_tilt");
295 
296  // Robot parameters
297  if (!private_node_handle_.getParam("summit_xl_wheel_diameter", summit_xl_wheel_diameter_))
298  summit_xl_wheel_diameter_ = SUMMIT_XL_WHEEL_DIAMETER;
299  if (!private_node_handle_.getParam("summit_xl_d_tracks_m", summit_xl_d_tracks_m_))
300  summit_xl_d_tracks_m_ = SUMMIT_XL_D_TRACKS_M;
301  ROS_INFO("summit_xl_wheel_diameter_ = %5.2f", summit_xl_wheel_diameter_);
302  ROS_INFO("summit_xl_d_tracks_m_ = %5.2f", summit_xl_d_tracks_m_);
303 
304  private_node_handle_.param("publish_odom_tf", publish_odom_tf_, true);
305  if (publish_odom_tf_) ROS_INFO("PUBLISHING odom->base_footprin tf");
306  else ROS_INFO("NOT PUBLISHING odom->base_footprint tf");
307 
308  // Robot Speeds
309  linearSpeedXMps_ = 0.0;
310  linearSpeedYMps_ = 0.0;
311  angularSpeedRads_ = 0.0;
312 
313  // Robot Positions
314  robot_pose_px_ = 0.0;
315  robot_pose_py_ = 0.0;
316  robot_pose_pa_ = 0.0;
317  robot_pose_vx_ = 0.0;
318  robot_pose_vy_ = 0.0;
319 
320  // External speed references
321  v_ref_x_ = 0.0;
322  v_ref_y_ = 0.0;
323  w_ref_ = 0.0;
324  v_ref_z_ = 0.0;
325  pos_ref_pan_ = 0.0;
326  pos_ref_tilt_= 0.0;
327 
328  // Imu variables
329  ang_vel_x_ = 0.0; ang_vel_y_ = 0.0; ang_vel_z_ = 0.0;
330  lin_acc_x_ = 0.0; lin_acc_y_ = 0.0; lin_acc_z_ = 0.0;
331  orientation_x_ = 0.0; orientation_y_ = 0.0; orientation_z_ = 0.0; orientation_w_ = 0.0;
332 
333  // Active kinematic mode
334  active_kinematic_mode_ = SKID_STEERING;
335 
336  // Advertise services
337  srv_SetMode_ = summit_xl_robot_control_node_handle.advertiseService("set_mode", &SummitXLControllerClass::srvCallback_SetMode, this);
338  srv_GetMode_ = summit_xl_robot_control_node_handle.advertiseService("get_mode", &SummitXLControllerClass::srvCallback_GetMode, this);
339  srv_SetOdometry_ = summit_xl_robot_control_node_handle.advertiseService("set_odometry", &SummitXLControllerClass::srvCallback_SetOdometry, this);
340 
341  // Subscribe to joint states topic
342  joint_state_sub_ = summit_xl_robot_control_node_handle.subscribe<sensor_msgs::JointState>("/summit_xl/joint_states", 1, &SummitXLControllerClass::jointStateCallback, this);
343 
344  // Subscribe to imu data
345  imu_sub_ = summit_xl_robot_control_node_handle.subscribe("/summit_xl/imu_data", 1, &SummitXLControllerClass::imuCallback, this);
346 
347  // Adevertise reference topics for the controllers
348  ref_vel_frw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( frw_vel_topic_, 50);
349  ref_vel_flw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( flw_vel_topic_, 50);
350  ref_vel_blw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( blw_vel_topic_, 50);
351  ref_vel_brw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( brw_vel_topic_, 50);
352 
353  if ((robot_model_=="summit_xl_omni")||(robot_model_=="x_wam")) {
354  ref_pos_frw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( frw_pos_topic_, 50);
355  ref_pos_flw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( flw_pos_topic_, 50);
356  ref_pos_blw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( blw_pos_topic_, 50);
357  ref_pos_brw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( brw_pos_topic_, 50);
358 
359  if (robot_model_=="x_wam")
360  ref_pos_scissor_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( scissor_pos_topic_, 50);
361  }
362 
363  ref_pos_pan_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( pan_pos_topic_, 50);
364  ref_pos_tilt_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( tilt_pos_topic_, 50);
365 
366  // Subscribe to command topic
367  cmd_sub_ = summit_xl_robot_control_node_handle.subscribe<geometry_msgs::Twist>("command", 1, &SummitXLControllerClass::commandCallback, this);
368 
369  // Subscribe to ptz command topic
370  ptz_sub_ = summit_xl_robot_control_node_handle.subscribe<robotnik_msgs::ptz>("command_ptz", 1, &SummitXLControllerClass::command_ptzCallback, this);
371  // /summit_xl_robot_control/command_ptz
372 
373  // TODO odom topic as parameter
374  // Publish odometry
375  odom_pub_ = summit_xl_robot_control_node_handle.advertise<nav_msgs::Odometry>("/summit_xl/odom", 1000);
376 
377  // Component frequency diagnostics
378  diagnostic_.setHardwareID("summit_xl_robot_control - simulation");
379  diagnostic_.add( freq_diag_ );
380  diagnostic_.add( command_freq_ );
381 
382  // Topics freq control
383  // For /summit_xl_robot_control/command
384  double min_freq = SUMMIT_XL_MIN_COMMAND_REC_FREQ; // If you update these values, the
385  double max_freq = SUMMIT_XL_MAX_COMMAND_REC_FREQ; // HeaderlessTopicDiagnostic will use the new values.
386  subs_command_freq = new diagnostic_updater::HeaderlessTopicDiagnostic("/summit_xl_robot_control/command", diagnostic_,
387  diagnostic_updater::FrequencyStatusParam(&min_freq, &max_freq, 0.1, 10));
388  subs_command_freq->addTask(&command_freq_); // Adding an additional task to the control
389 
390  // Flag to indicate joint_state has been read
391  read_state_ = false;
392 }
393 
395 int starting()
396 {
397 
398  ROS_INFO("SummitXLControllerClass::starting");
399 
400  //name: ['joint_back_left_wheel', 'joint_back_right_wheel', 'joint_front_left_wheel', 'joint_front_right_wheel']
401  //position: [-0.04246698357387224, 0.053199274627900195, -0.04246671523622059, 0.03126368464965523]
402  //velocity: [-0.0006956167983269147, 0.0004581098383479411, -0.0013794952191663358, 0.00045523862784977847]
403 
404  // Initialize joint indexes according to joint names
405  if (read_state_) {
406  vector<string> joint_names = joint_state_.name;
407  frw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_right_wheel)) - joint_names.begin();
408  flw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_left_wheel)) - joint_names.begin();
409  blw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_left_wheel)) - joint_names.begin();
410  brw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_right_wheel)) - joint_names.begin();
411  if ((robot_model_=="summit_xl_omni")||(robot_model_=="x_wam")) {
412  frw_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_front_right_steer)) - joint_names.begin();
413  flw_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_front_left_steer)) - joint_names.begin();
414  blw_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_back_left_steer)) - joint_names.begin();
415  brw_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_back_right_steer)) - joint_names.begin();
416  }
417  if (robot_model_=="x_wam") {
418  scissor_pos_ = find (joint_names.begin(),joint_names.end(), string(scissor_prismatic_joint)) - joint_names.begin();
419  }
420  // For publishing the ptz joint state
421  //pan_pos_ = find(joint_names.begin(), joint_names.end(), string(joint_camera_pan)) - joint_names.begin();
422  //tilt_pos_ = find(joint_names.begin(), joint_names.end(), string(joint_camera_tilt)) - joint_names.begin();
423  return 0;
424  }
425  else return -1;
426 }
427 
428 
431 {
432 
433  // Depending on the robot configuration
434  if (active_kinematic_mode_ == SKID_STEERING) {
435 
436  // Inverse kinematics
437  double dUl = v_ref_x_ - 0.5 * summit_xl_d_tracks_m_ * w_ref_;
438  // sign according to urdf (if wheel model is not symetric, should be inverted)
439  double dUr = v_ref_x_ + 0.5 * summit_xl_d_tracks_m_ * w_ref_;
440 
441  // Motor control actions
442  double limit = 40.0; // 40.0;
443 
444  //ROS_INFO("epv=%5.2f, epw=%5.2f *** dUl=%5.2f dUr=%5.2f", epv, epw, dUl, dUr);
445 
446  // Axis are not reversed in the omni (swerve) configuration
447  std_msgs::Float64 frw_ref_msg;
448  std_msgs::Float64 flw_ref_msg;
449  std_msgs::Float64 blw_ref_msg;
450  std_msgs::Float64 brw_ref_msg;
451 
452  double k1 = 5.0;
453  frw_ref_msg.data = -saturation( k1 * dUr, -limit, limit);
454  flw_ref_msg.data = saturation( k1 * dUl, -limit, limit);
455  blw_ref_msg.data = saturation( k1 * dUl, -limit, limit);
456  brw_ref_msg.data = -saturation( k1 * dUr, -limit, limit);
457 
458  ref_vel_frw_.publish( frw_ref_msg );
459  ref_vel_flw_.publish( flw_ref_msg );
460  ref_vel_blw_.publish( blw_ref_msg );
461  ref_vel_brw_.publish( brw_ref_msg );
462  }
463 
464 /*
465  // Depending on the robot configuration
466  if (active_kinematic_mode_ == SKID_STEERING) {
467 
468  double v_left_mps, v_right_mps;
469 
470  // Calculate its own velocities for realize the motor control
471  v_left_mps = ((joint_state_.velocity[blw_vel_] + joint_state_.velocity[flw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0);
472  v_right_mps = -((joint_state_.velocity[brw_vel_] + joint_state_.velocity[frw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0);
473  // sign according to urdf (if wheel model is not symetric, should be inverted)
474 
475  linearSpeedXMps_ = (v_right_mps + v_left_mps) / 2.0; // m/s
476  angularSpeedRads_ = (v_right_mps - v_left_mps) / summit_xl_d_tracks_m_; // rad/s
477 
478  ROS_INFO("vleft=%5.2f vright=%5.2f linearSpeedXMps=%5.2f, linearSpeedYMps=%5.2f, angularSpeedRads=%5.4f", v_left_mps, v_right_mps,
479  linearSpeedXMps_, linearSpeedYMps_, angularSpeedRads_);
480 
481  // Current controllers close this loop allowing (v,w) references.
482  double epv=0.0;
483  double epw=0.0;
484  static double epvant =0.0;
485  static double epwant =0.0;
486 
487  // Adjusted for soft indoor office soil
488  //double kpv=2.5; double kdv=0.0;
489  //double kpw=2.5; double kdw=0.0;
490  // In order to use this controller with the move_base stack note that move_base sets the min rotation ref to 0.4 independantly of the yaml configurations!!!
491  //double kpv=2.5; double kdv=0.0;
492  //double kpw=25.0; double kdw=15.0;
493 
494  // For VREP
495  double kpv=2.5; double kdv=0.0;
496  double kpw=2.5; double kdw=0.0;
497 
498 
499  // State feedback error
500  epv = v_ref_x_ - linearSpeedXMps_;
501  epw = w_ref_ - angularSpeedRads_;
502  // ROS_INFO("v_ref_x_=%5.2f, linearSpeedXMps_=%5.2f w_ref_=%5.2f angularSpeedRads_=%5.2f", v_ref_x_, linearSpeedXMps_, w_ref_, angularSpeedRads_);
503 
504  // Compute state control actions
505  double uv= kpv * epv + kdv * (epv - epvant);
506  double uw= kpw * epw + kdw * (epw - epwant);
507  epvant = epv;
508  epwant = epw;
509 
510  // Inverse kinematics
511  double dUl = uv - 0.5 * summit_xl_d_tracks_m_ * uw;
512  // sign according to urdf (if wheel model is not symetric, should be inverted)
513  double dUr = -(uv + 0.5 * summit_xl_d_tracks_m_ * uw);
514 
515  // Motor control actions
516  double limit = 40.0;
517 
518  //ROS_INFO("epv=%5.2f, epw=%5.2f *** dUl=%5.2f dUr=%5.2f", epv, epw, dUl, dUr);
519 
520  // Axis are not reversed in the omni (swerve) configuration
521  std_msgs::Float64 frw_ref_msg;
522  std_msgs::Float64 flw_ref_msg;
523  std_msgs::Float64 blw_ref_msg;
524  std_msgs::Float64 brw_ref_msg;
525 
526  double k1 = 0.5;
527  frw_ref_msg.data = saturation( k1 * dUr, -limit, limit);
528  flw_ref_msg.data = saturation( k1 * dUl, -limit, limit);
529  blw_ref_msg.data = saturation( k1 * dUl, -limit, limit);
530  brw_ref_msg.data = saturation( k1 * dUr, -limit, limit);
531 
532  ref_vel_frw_.publish( frw_ref_msg );
533  ref_vel_flw_.publish( flw_ref_msg );
534  ref_vel_blw_.publish( blw_ref_msg );
535  ref_vel_brw_.publish( brw_ref_msg );
536  }
537  */
538 
539 /*
540  // Depending on the robot configuration
541  if (active_kinematic_mode_ == MECANUM_STEERING) {
542 
543  // Speed references for motor control
544  // double v_left_mps, v_right_mps;
545  double v_frw_mps, v_flw_mps, v_blw_mps, v_brw_mps;
546  v_frw_mps = joint_state_.velocity[frw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
547  v_flw_mps = joint_state_.velocity[flw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
548  v_blw_mps = joint_state_.velocity[blw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
549  v_brw_mps = joint_state_.velocity[brw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
550 
551  double vx = v_ref_x_;
552  double vy = v_ref_y_;
553  double w = w_ref_;
554  double L = summit_xl_wheelbase_;
555  double W = summit_xl_trackwidth_;
556 
557 
558  double x1 = L/2.0; double y1 = - W/2.0;
559  double wx1 = v_ref_x_ - w_ref_ * y1;
560  double wy1 = v_ref_y_ + w_ref_ * x1;
561  double q1 = -sqrt( wx1*wx1 + wy1*wy1 );
562  double a1 = radnorm( atan2( wy1, wx1 ) );
563  double x2 = L/2.0; double y2 = W/2.0;
564  double wx2 = v_ref_x_ - w_ref_ * y2;
565  double wy2 = v_ref_y_ + w_ref_ * x2;
566  double q2 = sqrt( wx2*wx2 + wy2*wy2 );
567  double a2 = radnorm( atan2( wy2, wx2 ) );
568  double x3 = -L/2.0; double y3 = W/2.0;
569  double wx3 = v_ref_x_ - w_ref_ * y3;
570  double wy3 = v_ref_y_ + w_ref_ * x3;
571  double q3 = sqrt( wx3*wx3 + wy3*wy3 );
572  double a3 = radnorm( atan2( wy3, wx3 ) );
573  double x4 = -L/2.0; double y4 = -W/2.0;
574  double wx4 = v_ref_x_ - w_ref_ * y4;
575  double wy4 = v_ref_y_ + w_ref_ * x4;
576  double q4 = -sqrt( wx4*wx4 + wy4*wy4 );
577  double a4 = radnorm( atan2( wy4, wx4 ) );
578 
579  //ROS_INFO("q1234=(%5.2f, %5.2f, %5.2f, %5.2f) a1234=(%5.2f, %5.2f, %5.2f, %5.2f)", q1,q2,q3,q4, a1,a2,a3,a4);
580 
581  // Motor control actions
582  double limit = 40.0;
583 
584  // Axis are not reversed in the omni (swerve) configuration
585  std_msgs::Float64 frw_ref_vel_msg;
586  std_msgs::Float64 flw_ref_vel_msg;
587  std_msgs::Float64 blw_ref_vel_msg;
588  std_msgs::Float64 brw_ref_vel_msg;
589  frw_ref_vel_msg.data = saturation(-1.0 * (joint_state_.velocity[frw_vel_] - q1), -limit, limit);
590  flw_ref_vel_msg.data = saturation(-1.0 * (joint_state_.velocity[flw_vel_] - q2), -limit, limit);
591  blw_ref_vel_msg.data = saturation(-1.0 * (joint_state_.velocity[blw_vel_] - q3), -limit, limit);
592  brw_ref_vel_msg.data = saturation(-1.0 * (joint_state_.velocity[brw_vel_] - q4), -limit, limit);
593  ref_vel_frw_.publish( frw_ref_vel_msg );
594  ref_vel_flw_.publish( flw_ref_vel_msg );
595  ref_vel_blw_.publish( blw_ref_vel_msg );
596  ref_vel_brw_.publish( brw_ref_vel_msg );
597  std_msgs::Float64 frw_ref_pos_msg;
598  std_msgs::Float64 flw_ref_pos_msg;
599  std_msgs::Float64 blw_ref_pos_msg;
600  std_msgs::Float64 brw_ref_pos_msg;
601  frw_ref_pos_msg.data = a1;
602  flw_ref_pos_msg.data = a2;
603  blw_ref_pos_msg.data = a3;
604  brw_ref_pos_msg.data = a4;
605 
606  ref_pos_frw_.publish( frw_ref_pos_msg);
607  ref_pos_flw_.publish( flw_ref_pos_msg);
608  ref_pos_blw_.publish( blw_ref_pos_msg);
609  ref_pos_brw_.publish( brw_ref_pos_msg);
610 
611  }
612 
613  // Depending on the robot model
614  if (robot_model_ == "x_wam") {
615  // Position reference for the scissor mechanism
616  static double scissor_ref_pos = 0.0;
617  scissor_ref_pos += (v_ref_z_ / desired_freq_);
618  std_msgs::Float64 scissor_ref_pos_msg;
619  // joint_state_.position[scissor_pos_] not used, just setpoint
620  scissor_ref_pos_msg.data = saturation(scissor_ref_pos, 0.0, 0.5);
621  ref_pos_scissor_.publish( scissor_ref_pos_msg );
622  }
623 
624  // PTZ
625  std_msgs::Float64 pan_ref_pos_msg, tilt_ref_pos_msg;
626  pan_ref_pos_msg.data = pos_ref_pan_; //saturation( pos_ref_pan_, 0.0, 0.5);
627  ref_pos_pan_.publish( pan_ref_pos_msg );
628  tilt_ref_pos_msg.data = pos_ref_tilt_; //saturation( pos_ref_tilt_, 0.0, 0.5);
629  ref_pos_tilt_.publish( tilt_ref_pos_msg );
630  */
631 }
632 
633 // Update robot odometry depending on kinematic configuration
635 {
636  // Depending on the robot configuration
637  if (active_kinematic_mode_ == SKID_STEERING) {
638 
639  // Compute Velocity (linearSpeedXMps_ computed in control
640  robot_pose_vx_ = linearSpeedXMps_ * cos(robot_pose_pa_);
641  robot_pose_vy_ = linearSpeedXMps_ * sin(robot_pose_pa_);
642  }
643 
644  // Depending on the robot configuration
645  if (active_kinematic_mode_ == MECANUM_STEERING) {
646 
647  // Linear speed of each wheel
648  double v1, v2, v3, v4;
649  v1 = joint_state_.velocity[frw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
650  v2 = joint_state_.velocity[flw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
651  v3 = joint_state_.velocity[blw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
652  v4 = joint_state_.velocity[brw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
653  double a1, a2, a3, a4;
654  a1 = radnorm2( joint_state_.position[frw_pos_] );
655  a2 = radnorm2( joint_state_.position[flw_pos_] );
656  a3 = radnorm2( joint_state_.position[blw_pos_] );
657  a4 = radnorm2( joint_state_.position[brw_pos_] );
658  double v1x = -v1 * cos( a1 ); double v1y = -v1 * sin( a1 );
659  double v2x = v2 * cos( a2 ); double v2y = v2 * sin( a2 );
660  double v3x = v3 * cos( a3 ); double v3y = v3 * sin( a3 );
661  double v4x = -v4 * cos( a4 ); double v4y = -v4 * sin( a4 );
662  double C = (v4y + v1y) / 2.0;
663  double B = (v2x + v1x) / 2.0;
664  double D = (v2y + v3y) / 2.0;
665  double A = (v3x + v4x) / 2.0;
666  // double W = ( (B-A)/summit_xl_wheelbase_ ); // + (D-C)/summit_xl_trackwidth_ ) / 2.0;
667  robot_pose_vx_ = (A+B) / 2.0;
668  robot_pose_vy_ = (C+D) / 2.0;
669  }
670 
671  // Compute Position
672  double fSamplePeriod = 1.0 / desired_freq_;
673  robot_pose_pa_ += ang_vel_z_ * fSamplePeriod; // this velocity comes from IMU callback
674  robot_pose_px_ += robot_pose_vx_ * fSamplePeriod;
675  robot_pose_py_ += robot_pose_vy_ * fSamplePeriod;
676  // ROS_INFO("Odom estimated x=%5.2f y=%5.2f a=%5.2f", robot_pose_px_, robot_pose_py_, robot_pose_pa_);
677 }
678 
679 // Publish robot odometry tf and topic depending
681 {
682  ros::Time current_time = ros::Time::now();
683 
684  //first, we'll publish the transform over tf
685  geometry_msgs::TransformStamped odom_trans;
686  odom_trans.header.stamp = current_time;
687  odom_trans.header.frame_id = "odom";
688  odom_trans.child_frame_id = "base_footprint";
689 
690  odom_trans.transform.translation.x = robot_pose_px_;
691  odom_trans.transform.translation.y = robot_pose_py_;
692  odom_trans.transform.translation.z = 0.0;
693  odom_trans.transform.rotation.x = orientation_x_;
694  odom_trans.transform.rotation.y = orientation_y_;
695  odom_trans.transform.rotation.z = orientation_z_;
696  odom_trans.transform.rotation.w = orientation_w_;
697 
698  // send the transform over /tf
699  // activate / deactivate with param
700  // this tf in needed when not using robot_pose_ekf
701  if (publish_odom_tf_) odom_broadcaster.sendTransform(odom_trans);
702 
703  //next, we'll publish the odometry message over ROS
704  nav_msgs::Odometry odom;
705  odom.header.stamp = current_time;
706  odom.header.frame_id = "odom";
707 
708  //set the position
709  // Position
710  odom.pose.pose.position.x = robot_pose_px_;
711  odom.pose.pose.position.y = robot_pose_py_;
712  odom.pose.pose.position.z = 0.0;
713  // Orientation
714  odom.pose.pose.orientation.x = orientation_x_;
715  odom.pose.pose.orientation.y = orientation_y_;
716  odom.pose.pose.orientation.z = orientation_z_;
717  odom.pose.pose.orientation.w = orientation_w_;
718  // Pose covariance
719  for(int i = 0; i < 6; i++)
720  odom.pose.covariance[i*6+i] = 0.1; // test 0.001
721 
722  //set the velocity
723  odom.child_frame_id = "base_footprint";
724  // Linear velocities
725  odom.twist.twist.linear.x = robot_pose_vx_;
726  odom.twist.twist.linear.y = robot_pose_vy_;
727  odom.twist.twist.linear.z = 0.0;
728  // Angular velocities
729  odom.twist.twist.angular.x = ang_vel_x_;
730  odom.twist.twist.angular.y = ang_vel_y_;
731  odom.twist.twist.angular.z = ang_vel_z_;
732  // Twist covariance
733  for(int i = 0; i < 6; i++)
734  odom.twist.covariance[6*i+i] = 0.1; // test 0.001
735 
736  //publish the message
737  odom_pub_.publish(odom);
738 }
739 
741 void stopping()
742 {}
743 
744 
745 /*
746  * \brief Checks that the robot is receiving at a correct frequency the command messages. Diagnostics
747  *
748  */
750 {
751  ros::Time current_time = ros::Time::now();
752 
753  double diff = (current_time - last_command_time_).toSec();
754 
755  if(diff > 1.0){
756  stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Topic is not receiving commands");
757  //ROS_INFO("check_command_subscriber: %lf seconds without commands", diff);
758  // TODO: Set Speed References to 0
759  }else{
760  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Topic receiving commands");
761  }
762 }
763 
764 
765 // Set the base velocity command
766 void setCommand(const geometry_msgs::Twist &cmd_vel)
767 {
768  v_ref_x_ = saturation(cmd_vel.linear.x, -10.0, 10.0);
769  v_ref_y_ = saturation(cmd_vel.linear.y, -10.0, 10.0);
770  w_ref_ = saturation(cmd_vel.angular.z, -10.0, 10.0); // -10.0 10.0
771  v_ref_z_ = saturation(cmd_vel.linear.z, -10.0, 10.0);
772 }
773 
774 // CALLBACKS
775 // Service SetMode
776 bool srvCallback_SetMode(robotnik_msgs::set_mode::Request& request, robotnik_msgs::set_mode::Response& response)
777 {
778  // Check if the selected mode is available or not
779  // 1 - SKID STEERING
780  // 2 - OMNIDRIVE
781  // (3 - SWERVE)
782 
783  ROS_INFO("SummitXLControllerClass::srvCallback_SetMode request.mode= %d", request.mode);
784  if (request.mode == 1) {
785  active_kinematic_mode_ = request.mode;
786  return true;
787  }
788  if (request.mode == 2) {
789  if (kinematic_modes_ == 2) {
790  active_kinematic_mode_ = request.mode;
791  return true;
792  }
793  else return false;
794  }
795  return false;
796 }
797 
798 // Service GetMode
799 bool srvCallback_GetMode(robotnik_msgs::get_mode::Request& request, robotnik_msgs::get_mode::Response& response)
800 {
801  response.mode = active_kinematic_mode_;
802  return true;
803 }
804 
805 
806 // Service SetOdometry
807 bool srvCallback_SetOdometry(robotnik_msgs::set_odometry::Request &request, robotnik_msgs::set_odometry::Response &response )
808 {
809  // ROS_INFO("summit_xl_odometry::set_odometry: request -> x = %f, y = %f, a = %f", req.x, req.y, req.orientation);
810  //robot_pose_px_ = req.x;
811  //robot_pose_py_ = req.y;
812  //robot_pose_pa_ = req.orientation;
813 
814  response.ret = true;
815  return true;
816 }
817 
818 
819 // Topic command
820 void jointStateCallback(const sensor_msgs::JointStateConstPtr& msg)
821 {
822  joint_state_ = *msg;
823  read_state_ = true;
824 }
825 
826 // Topic command
827 void commandCallback(const geometry_msgs::TwistConstPtr& msg)
828 {
829  // Safety check
830  last_command_time_ = ros::Time::now();
831  subs_command_freq->tick(); // For diagnostics
832 
833  base_vel_msg_ = *msg;
834  this->setCommand(base_vel_msg_);
835 }
836 
837 // Topic ptz command
838 void command_ptzCallback(const robotnik_msgs::ptzConstPtr& msg)
839 {
840  pos_ref_pan_ += msg->pan / 180.0 * PI;
841  pos_ref_tilt_ += msg->tilt / 180.0 * PI;
842 }
843 
844 // Imu callback
845 void imuCallback( const sensor_msgs::Imu& imu_msg){
846 
847  orientation_x_ = imu_msg.orientation.x;
848  orientation_y_ = imu_msg.orientation.y;
849  orientation_z_ = imu_msg.orientation.z;
850  orientation_w_ = imu_msg.orientation.w;
851 
852  ang_vel_x_ = imu_msg.angular_velocity.x;
853  ang_vel_y_ = imu_msg.angular_velocity.y;
854  ang_vel_z_ = imu_msg.angular_velocity.z;
855 
856  lin_acc_x_ = imu_msg.linear_acceleration.x;
857  lin_acc_y_ = imu_msg.linear_acceleration.y;
858  lin_acc_z_ = imu_msg.linear_acceleration.z;
859 }
860 
861 double saturation(double u, double min, double max)
862 {
863  if (u>max) u=max;
864  if (u<min) u=min;
865  return u;
866 }
867 
868 double radnorm( double value )
869 {
870  while (value > PI) value -= PI;
871  while (value < -PI) value += PI;
872  return value;
873 }
874 
875 double radnorm2( double value )
876 {
877  while (value > 2.0*PI) value -= 2.0*PI;
878  while (value < -2.0*PI) value += 2.0*PI;
879  return value;
880 }
881 
882 bool spin()
883 {
884  ROS_INFO("summit_xl_robot_control::spin()");
885  ros::Rate r(desired_freq_); // 50.0
886 
887  while (!ros::isShuttingDown()) // Using ros::isShuttingDown to avoid restarting the node during a shutdown.
888  {
889  if (starting() == 0)
890  {
891  while(ros::ok() && node_handle_.ok()) {
892  UpdateControl();
893  UpdateOdometry();
894  PublishOdometry();
895  diagnostic_.update();
896  ros::spinOnce();
897  r.sleep();
898  }
899  ROS_INFO("END OF ros::ok() !!!");
900  } else {
901  // No need for diagnostic here since a broadcast occurs in start
902  // when there is an error.
903  usleep(1000000);
904  ros::spinOnce();
905  }
906  }
907 
908  ROS_INFO("summit_xl_robot_control::spin() - end");
909  return true;
910 }
911 
912 }; // Class SummitXLControllerClass
913 
914 int main(int argc, char** argv)
915 {
916  ros::init(argc, argv, "summit_xl_robot_control");
917 
918  ros::NodeHandle n;
919  SummitXLControllerClass sxlrc(n);
920 
921 
922  // ros::ServiceServer service = n.advertiseService("set_odometry", &summit_xl_node::set_odometry, &sxlc);
923  sxlrc.spin();
924 
925  return (0);
926 
927 
928 }
929 
void publish(const boost::shared_ptr< M > &message) const
void check_command_subscriber(diagnostic_updater::DiagnosticStatusWrapper &stat)
void summary(unsigned char lvl, const std::string s)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
#define SUMMIT_XL_WHEEL_DIAMETER
#define SUMMIT_XL_WHEELBASE
void setHardwareID(const std::string &hwid)
void jointStateCallback(const sensor_msgs::JointStateConstPtr &msg)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void imuCallback(const sensor_msgs::Imu &imu_msg)
void commandCallback(const geometry_msgs::TwistConstPtr &msg)
void add(const std::string &name, TaskFunction f)
#define MECANUM_STEERING
int starting()
Controller startup in realtime.
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
double saturation(double u, double min, double max)
bool srvCallback_SetOdometry(robotnik_msgs::set_odometry::Request &request, robotnik_msgs::set_odometry::Response &response)
bool srvCallback_SetMode(robotnik_msgs::set_mode::Request &request, robotnik_msgs::set_mode::Response &response)
void command_ptzCallback(const robotnik_msgs::ptzConstPtr &msg)
#define SUMMIT_XL_MIN_COMMAND_REC_FREQ
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
void UpdateControl()
Controller update loop.
bool srvCallback_GetMode(robotnik_msgs::get_mode::Request &request, robotnik_msgs::get_mode::Response &response)
ROSCPP_DECL bool ok()
void sendTransform(const StampedTransform &transform)
ROSCPP_DECL bool isShuttingDown()
void setCommand(const geometry_msgs::Twist &cmd_vel)
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void stopping()
Controller stopping.
#define SUMMIT_XL_TRACKWIDTH
#define SUMMIT_XL_MAX_COMMAND_REC_FREQ
bool sleep()
bool getParam(const std::string &key, std::string &s) const
int main(int argc, char **argv)
static Time now()
#define SUMMIT_XL_D_TRACKS_M
bool ok() const
ROSCPP_DECL void spinOnce()
#define ROS_ERROR(...)
#define SKID_STEERING


summit_x_robot_control
Author(s): Roberto Guzman
autogenerated on Mon Jun 10 2019 15:17:30