summit_xl_robot_control.cpp
Go to the documentation of this file.
1 /*
2  * summit_xl_robot_control
3  * Copyright (c) 2013, 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 
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
100 
101  // Joint states published by the joint_state_controller of the Controller Manager
103 
104  // High level robot command
106 
107  // High level robot command
109 
110  //ros::Subscriber gyro_sub_;
111 
112  // Services
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
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
140 
141  // Topic - scissor - position
142  std::string scissor_pos_topic_;
143 
144  // Topic - odom
145  std::string odom_topic_;
146 
147  // Joint names - ptz - position
148  std::string joint_camera_pan;
149  std::string joint_camera_tilt;
150 
151  // Topics - ptz
152  std::string pan_pos_topic_;
153  std::string tilt_pos_topic_;
154 
155  // Joint name - scissor mechanism
157 
158  // Selected operation mode
161 
162  // Indexes to joint_states
163  int frw_vel_, flw_vel_, blw_vel_, brw_vel_;
164  int frw_pos_, flw_pos_, blw_pos_, brw_pos_;
166  int pan_pos_, tilt_pos_;
167 
168 
169  // Robot Speeds
173 
174  // Robot Positions
180 
181  // Robot Joint States
182  sensor_msgs::JointState joint_state_;
183 
184  // Command reference
185  geometry_msgs::Twist base_vel_msg_;
186 
187  // External speed references
188  double v_ref_x_;
189  double v_ref_y_;
190  double w_ref_;
191  double v_ref_z_;
192  double pos_ref_pan_;
194 
195  // Flag to indicate if joint_state has been read
196  bool read_state_;
197 
198  // Robot configuration parameters
203 
204  // IMU values
205  double ang_vel_x_;
206  double ang_vel_y_;
207  double ang_vel_z_;
208 
209  double lin_acc_x_;
210  double lin_acc_y_;
211  double lin_acc_z_;
212 
217 
218  // Parameter that defines if odom tf is published or not
220 
222 
223  // Publisher for odom topic
225 
226  // Broadcaster for odom tf
228 
229 
234  node_handle_(h), private_node_handle_("~"),
235  desired_freq_(100),
236  freq_diag_(diagnostic_updater::FrequencyStatusParam(&desired_freq_, &desired_freq_, 0.05) ),
237  command_freq_("Command frequency check", boost::bind(&SummitXLControllerClass::check_command_subscriber, this, _1))
238  {
239 
240  // /summit_xl/joint_blw_velocity_controller/joint
241  ROS_INFO("summit_xl_robot_control_node - Init ");
242 
243  // 4-Axis Skid Steer Rover
244  // 8-Axis Omni-drive as 4-Axis Mecanum drive
245  kinematic_modes_ = 1;
246 
247  ros::NodeHandle summit_xl_robot_control_node_handle(node_handle_, "summit_xl_robot_control");
248 
249  // Get robot model from the parameters
250  if (!private_node_handle_.getParam("model", robot_model_)) {
251  ROS_ERROR("Robot model not defined.");
252  exit(-1);
253  }
254  else ROS_INFO("Robot Model : %s", robot_model_.c_str());
255 
256  // Skid configuration - topics
257  private_node_handle_.param<std::string>("frw_vel_topic", frw_vel_topic_, "/summit_xl/joint_frw_velocity_controller/command");
258  private_node_handle_.param<std::string>("flw_vel_topic", flw_vel_topic_, "/summit_xl/joint_flw_velocity_controller/command");
259  private_node_handle_.param<std::string>("blw_vel_topic", blw_vel_topic_, "/summit_xl/joint_blw_velocity_controller/command");
260  private_node_handle_.param<std::string>("brw_vel_topic", brw_vel_topic_, "/summit_xl/joint_brw_velocity_controller/command");
261 
262  // Skid configuration - Joint names
263  private_node_handle_.param<std::string>("joint_front_right_wheel", joint_front_right_wheel, "joint_front_right_wheel");
264  private_node_handle_.param<std::string>("joint_front_left_wheel", joint_front_left_wheel, "joint_front_left_wheel");
265  private_node_handle_.param<std::string>("joint_back_left_wheel", joint_back_left_wheel, "joint_back_left_wheel");
266  private_node_handle_.param<std::string>("joint_back_right_wheel", joint_back_right_wheel, "joint_back_right_wheel");
267 
268  // Omni configuration - topics
269  if ((robot_model_=="summit_xl_omni") || (robot_model_=="x_wam")) {
270  kinematic_modes_ = 2;
271  private_node_handle_.param<std::string>("frw_pos_topic", frw_pos_topic_, "/summit_xl/joint_frw_velocity_controller/command");
272  private_node_handle_.param<std::string>("flw_pos_topic", flw_pos_topic_, "/summit_xl/joint_flw_velocity_controller/command");
273  private_node_handle_.param<std::string>("blw_pos_topic", blw_pos_topic_, "/summit_xl/joint_blw_velocity_controller/command");
274  private_node_handle_.param<std::string>("brw_pos_topic", brw_pos_topic_, "/summit_xl/joint_brw_velocity_controller/command");
275 
276  private_node_handle_.param<std::string>("joint_front_right_steer", joint_front_right_steer, "joint_front_right_steer");
277  private_node_handle_.param<std::string>("joint_front_left_steer", joint_front_left_steer, "joint_front_left_steer");
278  private_node_handle_.param<std::string>("joint_back_left_steer", joint_back_left_steer, "joint_back_left_steer");
279  private_node_handle_.param<std::string>("joint_back_right_steer", joint_back_right_steer, "joint_back_right_steer");
280 
281  if (!private_node_handle_.getParam("summit_xl_wheelbase", summit_xl_wheelbase_))
282  summit_xl_wheelbase_ = SUMMIT_XL_WHEELBASE;
283  if (!private_node_handle_.getParam("summit_xl_trackwidth", summit_xl_trackwidth_))
284  summit_xl_trackwidth_ = SUMMIT_XL_TRACKWIDTH;
285 
286  // x-wam only configuration
287  if (robot_model_=="x_wam") {
288  private_node_handle_.param<std::string>("scissor_pos_topic", scissor_pos_topic_, "/summit_xl/joint_scissor_position_controller/command");
289  private_node_handle_.param<std::string>("scissor_prismatic_joint", scissor_prismatic_joint, "scissor_prismatic_joint");
290  }
291  }
292 
293  // PTZ topics
294  private_node_handle_.param<std::string>("pan_pos_topic", pan_pos_topic_, "/summit_xl/joint_pan_position_controller/command");
295  private_node_handle_.param<std::string>("tilt_pos_topic", tilt_pos_topic_, "/summit_xl/joint_tilt_position_controller/command");
296  private_node_handle_.param<std::string>("joint_camera_pan", joint_camera_pan, "joint_camera_pan");
297  private_node_handle_.param<std::string>("joint_camera_tilt", joint_camera_tilt, "joint_camera_tilt");
298 
299  // Odom topic
300  private_node_handle_.param<std::string>("odom_topic", odom_topic_, "/summit_xl/odom_robot_control");
301 
302  // Robot parameters
303  if (!private_node_handle_.getParam("summit_xl_wheel_diameter", summit_xl_wheel_diameter_))
304  summit_xl_wheel_diameter_ = SUMMIT_XL_WHEEL_DIAMETER;
305  if (!private_node_handle_.getParam("summit_xl_d_tracks_m", summit_xl_d_tracks_m_))
306  summit_xl_d_tracks_m_ = SUMMIT_XL_D_TRACKS_M;
307  ROS_INFO("summit_xl_wheel_diameter_ = %5.2f", summit_xl_wheel_diameter_);
308  ROS_INFO("summit_xl_d_tracks_m_ = %5.2f", summit_xl_d_tracks_m_);
309 
310  private_node_handle_.param("publish_odom_tf", publish_odom_tf_, true);
311  if (publish_odom_tf_) ROS_INFO("PUBLISHING odom->base_footprin tf");
312  else ROS_INFO("NOT PUBLISHING odom->base_footprint tf");
313 
314  // Robot Speeds
315  linearSpeedXMps_ = 0.0;
316  linearSpeedYMps_ = 0.0;
317  angularSpeedRads_ = 0.0;
318 
319  // Robot Positions
320  robot_pose_px_ = 0.0;
321  robot_pose_py_ = 0.0;
322  robot_pose_pa_ = 0.0;
323  robot_pose_vx_ = 0.0;
324  robot_pose_vy_ = 0.0;
325 
326  // External speed references
327  v_ref_x_ = 0.0;
328  v_ref_y_ = 0.0;
329  w_ref_ = 0.0;
330  v_ref_z_ = 0.0;
331  pos_ref_pan_ = 0.0;
332  pos_ref_tilt_= 0.0;
333 
334  // Imu variables
335  ang_vel_x_ = 0.0; ang_vel_y_ = 0.0; ang_vel_z_ = 0.0;
336  lin_acc_x_ = 0.0; lin_acc_y_ = 0.0; lin_acc_z_ = 0.0;
337  orientation_x_ = 0.0; orientation_y_ = 0.0; orientation_z_ = 0.0; orientation_w_ = 0.0;
338 
339  // Active kinematic mode
340  active_kinematic_mode_ = SKID_STEERING;
341 
342  // Advertise services
343  srv_SetMode_ = summit_xl_robot_control_node_handle.advertiseService("set_mode", &SummitXLControllerClass::srvCallback_SetMode, this);
344  srv_GetMode_ = summit_xl_robot_control_node_handle.advertiseService("get_mode", &SummitXLControllerClass::srvCallback_GetMode, this);
345  srv_SetOdometry_ = summit_xl_robot_control_node_handle.advertiseService("set_odometry", &SummitXLControllerClass::srvCallback_SetOdometry, this);
346 
347  // Subscribe to joint states topic
348  joint_state_sub_ = summit_xl_robot_control_node_handle.subscribe<sensor_msgs::JointState>("/summit_xl/joint_states", 1, &SummitXLControllerClass::jointStateCallback, this);
349 
350  // Subscribe to imu data
351  // imu_sub_ = summit_xl_robot_control_node_handle.subscribe("/summit_xl/imu_data", 1, &SummitXLControllerClass::imuCallback, this);
352  imu_sub_ = summit_xl_robot_control_node_handle.subscribe("/imu_data", 1, &SummitXLControllerClass::imuCallback, this);
353 
354 
355  // Adevertise reference topics for the controllers
356  ref_vel_frw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( frw_vel_topic_, 50);
357  ref_vel_flw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( flw_vel_topic_, 50);
358  ref_vel_blw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( blw_vel_topic_, 50);
359  ref_vel_brw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( brw_vel_topic_, 50);
360 
361  if ((robot_model_=="summit_xl_omni")||(robot_model_=="x_wam")) {
362  ref_pos_frw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( frw_pos_topic_, 50);
363  ref_pos_flw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( flw_pos_topic_, 50);
364  ref_pos_blw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( blw_pos_topic_, 50);
365  ref_pos_brw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( brw_pos_topic_, 50);
366 
367  if (robot_model_=="x_wam")
368  ref_pos_scissor_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( scissor_pos_topic_, 50);
369  }
370 
371  ref_pos_pan_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( pan_pos_topic_, 50);
372  ref_pos_tilt_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( tilt_pos_topic_, 50);
373 
374  // Subscribe to command topic
375  cmd_sub_ = summit_xl_robot_control_node_handle.subscribe<geometry_msgs::Twist>("/summit_xl/robot_control/command", 1, &SummitXLControllerClass::commandCallback, this);
376 
377  // Subscribe to ptz command topic
378  ptz_sub_ = summit_xl_robot_control_node_handle.subscribe<robotnik_msgs::ptz>("/summit_xl/robot_control/command_ptz", 1, &SummitXLControllerClass::command_ptzCallback, this);
379  // /summit_xl_robot_control/command_ptz
380 
381  // Publish odometry
382  odom_pub_ = summit_xl_robot_control_node_handle.advertise<nav_msgs::Odometry>(odom_topic_, 1000);
383 
384  // Component frequency diagnostics
385  diagnostic_.setHardwareID("summit_xl_robot_control - simulation");
386  diagnostic_.add( freq_diag_ );
387  diagnostic_.add( command_freq_ );
388 
389  // Topics freq control
390  // For /summit_xl_robot_control/command
391  double min_freq = SUMMIT_XL_MIN_COMMAND_REC_FREQ; // If you update these values, the
392  double max_freq = SUMMIT_XL_MAX_COMMAND_REC_FREQ; // HeaderlessTopicDiagnostic will use the new values.
393  subs_command_freq = new diagnostic_updater::HeaderlessTopicDiagnostic("/summit_xl_robot_control/command", diagnostic_,
394  diagnostic_updater::FrequencyStatusParam(&min_freq, &max_freq, 0.1, 10));
395  subs_command_freq->addTask(&command_freq_); // Adding an additional task to the control
396 
397  // Flag to indicate joint_state has been read
398  read_state_ = false;
399 }
400 
402 int starting()
403 {
404 
405  ROS_INFO("SummitXLControllerClass::starting");
406 
407  //name: ['joint_back_left_wheel', 'joint_back_right_wheel', 'joint_front_left_wheel', 'joint_front_right_wheel']
408  //position: [-0.04246698357387224, 0.053199274627900195, -0.04246671523622059, 0.03126368464965523]
409  //velocity: [-0.0006956167983269147, 0.0004581098383479411, -0.0013794952191663358, 0.00045523862784977847]
410 
411  // Initialize joint indexes according to joint names
412  if (read_state_) {
413  vector<string> joint_names = joint_state_.name;
414  frw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_right_wheel)) - joint_names.begin();
415  flw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_left_wheel)) - joint_names.begin();
416  blw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_left_wheel)) - joint_names.begin();
417  brw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_right_wheel)) - joint_names.begin();
418  if ((robot_model_=="summit_xl_omni")||(robot_model_=="x_wam")) {
419  frw_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_front_right_steer)) - joint_names.begin();
420  flw_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_front_left_steer)) - joint_names.begin();
421  blw_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_back_left_steer)) - joint_names.begin();
422  brw_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_back_right_steer)) - joint_names.begin();
423  }
424  if (robot_model_=="x_wam") {
425  scissor_pos_ = find (joint_names.begin(),joint_names.end(), string(scissor_prismatic_joint)) - joint_names.begin();
426  }
427  // For publishing the ptz joint state
428  //pan_pos_ = find(joint_names.begin(), joint_names.end(), string(joint_camera_pan)) - joint_names.begin();
429  //tilt_pos_ = find(joint_names.begin(), joint_names.end(), string(joint_camera_tilt)) - joint_names.begin();
430  return 0;
431  }
432  else return -1;
433 }
434 
435 
438 {
439  // Depending on the robot configuration
440  if (active_kinematic_mode_ == SKID_STEERING) {
441 
442  double v_left_mps, v_right_mps;
443 
444  // Calculate its own velocities for realize the motor control
445  v_left_mps = ((joint_state_.velocity[blw_vel_] + joint_state_.velocity[flw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0);
446  v_right_mps = -((joint_state_.velocity[brw_vel_] + joint_state_.velocity[frw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0);
447  // sign according to urdf (if wheel model is not symetric, should be inverted)
448 
449  linearSpeedXMps_ = (v_right_mps + v_left_mps) / 2.0; // m/s
450  angularSpeedRads_ = (v_right_mps - v_left_mps) / summit_xl_d_tracks_m_; // rad/s
451 
452  //ROS_INFO("vleft=%5.2f vright=%5.2f linearSpeedXMps=%5.2f, linearSpeedYMps=%5.2f, angularSpeedRads=%5.4f", v_left_mps, v_right_mps,
453  // linearSpeedXMps_, linearSpeedYMps_, angularSpeedRads_);
454 
455  // Current controllers close this loop allowing (v,w) references.
456  double epv=0.0;
457  double epw=0.0;
458  static double epvant =0.0;
459  static double epwant =0.0;
460 
461  // Adjusted for soft indoor office soil
462  //double kpv=2.5; double kdv=0.0;
463  //double kpw=2.5; double kdw=0.0;
464  // 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!!!
465  double kpv=2.5; double kdv=0.0;
466  double kpw=25.0; double kdw=15.0;
467 
468  // State feedback error
469  epv = v_ref_x_ - linearSpeedXMps_;
470  epw = w_ref_ - angularSpeedRads_;
471  // ROS_INFO("v_ref_x_=%5.2f, linearSpeedXMps_=%5.2f w_ref_=%5.2f angularSpeedRads_=%5.2f", v_ref_x_, linearSpeedXMps_, w_ref_, angularSpeedRads_);
472 
473  // Compute state control actions
474  double uv= kpv * epv + kdv * (epv - epvant);
475  double uw= kpw * epw + kdw * (epw - epwant);
476  epvant = epv;
477  epwant = epw;
478 
479  // Inverse kinematics
480  double dUl = uv - 0.5 * summit_xl_d_tracks_m_ * uw;
481  // sign according to urdf (if wheel model is not symetric, should be inverted)
482  double dUr = -(uv + 0.5 * summit_xl_d_tracks_m_ * uw);
483 
484  // Motor control actions
485  double limit = 40.0;
486 
487  //ROS_INFO("epv=%5.2f, epw=%5.2f *** dUl=%5.2f dUr=%5.2f", epv, epw, dUl, dUr);
488 
489  // Axis are not reversed in the omni (swerve) configuration
490  std_msgs::Float64 frw_ref_msg;
491  std_msgs::Float64 flw_ref_msg;
492  std_msgs::Float64 blw_ref_msg;
493  std_msgs::Float64 brw_ref_msg;
494 
495  double k1 = 0.5;
496  frw_ref_msg.data = saturation( k1 * dUr, -limit, limit);
497  flw_ref_msg.data = saturation( k1 * dUl, -limit, limit);
498  blw_ref_msg.data = saturation( k1 * dUl, -limit, limit);
499  brw_ref_msg.data = saturation( k1 * dUr, -limit, limit);
500 
501  ref_vel_frw_.publish( frw_ref_msg );
502  ref_vel_flw_.publish( flw_ref_msg );
503  ref_vel_blw_.publish( blw_ref_msg );
504  ref_vel_brw_.publish( brw_ref_msg );
505  }
506 
507 
508  // Depending on the robot configuration
509  if (active_kinematic_mode_ == MECANUM_STEERING) {
510 
511  // Speed references for motor control
512  // double v_left_mps, v_right_mps;
513  double v_frw_mps, v_flw_mps, v_blw_mps, v_brw_mps;
514  v_frw_mps = joint_state_.velocity[frw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
515  v_flw_mps = joint_state_.velocity[flw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
516  v_blw_mps = joint_state_.velocity[blw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
517  v_brw_mps = joint_state_.velocity[brw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
518 
519  double vx = v_ref_x_;
520  double vy = v_ref_y_;
521  double w = w_ref_;
522  double L = summit_xl_wheelbase_;
523  double W = summit_xl_trackwidth_;
524 
525 
526  double x1 = L/2.0; double y1 = - W/2.0;
527  double wx1 = v_ref_x_ - w_ref_ * y1;
528  double wy1 = v_ref_y_ + w_ref_ * x1;
529  double q1 = -sqrt( wx1*wx1 + wy1*wy1 );
530  double a1 = radnorm( atan2( wy1, wx1 ) );
531  double x2 = L/2.0; double y2 = W/2.0;
532  double wx2 = v_ref_x_ - w_ref_ * y2;
533  double wy2 = v_ref_y_ + w_ref_ * x2;
534  double q2 = sqrt( wx2*wx2 + wy2*wy2 );
535  double a2 = radnorm( atan2( wy2, wx2 ) );
536  double x3 = -L/2.0; double y3 = W/2.0;
537  double wx3 = v_ref_x_ - w_ref_ * y3;
538  double wy3 = v_ref_y_ + w_ref_ * x3;
539  double q3 = sqrt( wx3*wx3 + wy3*wy3 );
540  double a3 = radnorm( atan2( wy3, wx3 ) );
541  double x4 = -L/2.0; double y4 = -W/2.0;
542  double wx4 = v_ref_x_ - w_ref_ * y4;
543  double wy4 = v_ref_y_ + w_ref_ * x4;
544  double q4 = -sqrt( wx4*wx4 + wy4*wy4 );
545  double a4 = radnorm( atan2( wy4, wx4 ) );
546 
547  //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);
548 
549  // Motor control actions
550  double limit = 40.0;
551 
552  // Axis are not reversed in the omni (swerve) configuration
553  std_msgs::Float64 frw_ref_vel_msg;
554  std_msgs::Float64 flw_ref_vel_msg;
555  std_msgs::Float64 blw_ref_vel_msg;
556  std_msgs::Float64 brw_ref_vel_msg;
557  frw_ref_vel_msg.data = saturation(-1.0 * (joint_state_.velocity[frw_vel_] - q1), -limit, limit);
558  flw_ref_vel_msg.data = saturation(-1.0 * (joint_state_.velocity[flw_vel_] - q2), -limit, limit);
559  blw_ref_vel_msg.data = saturation(-1.0 * (joint_state_.velocity[blw_vel_] - q3), -limit, limit);
560  brw_ref_vel_msg.data = saturation(-1.0 * (joint_state_.velocity[brw_vel_] - q4), -limit, limit);
561  ref_vel_frw_.publish( frw_ref_vel_msg );
562  ref_vel_flw_.publish( flw_ref_vel_msg );
563  ref_vel_blw_.publish( blw_ref_vel_msg );
564  ref_vel_brw_.publish( brw_ref_vel_msg );
565  std_msgs::Float64 frw_ref_pos_msg;
566  std_msgs::Float64 flw_ref_pos_msg;
567  std_msgs::Float64 blw_ref_pos_msg;
568  std_msgs::Float64 brw_ref_pos_msg;
569  frw_ref_pos_msg.data = a1;
570  flw_ref_pos_msg.data = a2;
571  blw_ref_pos_msg.data = a3;
572  brw_ref_pos_msg.data = a4;
573 
574  ref_pos_frw_.publish( frw_ref_pos_msg);
575  ref_pos_flw_.publish( flw_ref_pos_msg);
576  ref_pos_blw_.publish( blw_ref_pos_msg);
577  ref_pos_brw_.publish( brw_ref_pos_msg);
578 
579  }
580 
581  // Depending on the robot model
582  if (robot_model_ == "x_wam") {
583  // Position reference for the scissor mechanism
584  static double scissor_ref_pos = 0.0;
585  scissor_ref_pos += (v_ref_z_ / desired_freq_);
586  std_msgs::Float64 scissor_ref_pos_msg;
587  // joint_state_.position[scissor_pos_] not used, just setpoint
588  scissor_ref_pos_msg.data = saturation(scissor_ref_pos, 0.0, 0.5);
589  ref_pos_scissor_.publish( scissor_ref_pos_msg );
590  }
591 
592  // PTZ
593  std_msgs::Float64 pan_ref_pos_msg, tilt_ref_pos_msg;
594  pan_ref_pos_msg.data = pos_ref_pan_; //saturation( pos_ref_pan_, 0.0, 0.5);
595  ref_pos_pan_.publish( pan_ref_pos_msg );
596  tilt_ref_pos_msg.data = pos_ref_tilt_; //saturation( pos_ref_tilt_, 0.0, 0.5);
597  ref_pos_tilt_.publish( tilt_ref_pos_msg );
598 }
599 
600 // Update robot odometry depending on kinematic configuration
602 {
603  // Depending on the robot configuration
604  if (active_kinematic_mode_ == SKID_STEERING) {
605 
606  // Compute Velocity (linearSpeedXMps_ computed in control
607  robot_pose_vx_ = linearSpeedXMps_ * cos(robot_pose_pa_);
608  robot_pose_vy_ = linearSpeedXMps_ * sin(robot_pose_pa_);
609  }
610 
611  // Depending on the robot configuration
612  if (active_kinematic_mode_ == MECANUM_STEERING) {
613 
614  // Linear speed of each wheel
615  double v1, v2, v3, v4;
616  v1 = joint_state_.velocity[frw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
617  v2 = joint_state_.velocity[flw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
618  v3 = joint_state_.velocity[blw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
619  v4 = joint_state_.velocity[brw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
620  double a1, a2, a3, a4;
621  a1 = radnorm2( joint_state_.position[frw_pos_] );
622  a2 = radnorm2( joint_state_.position[flw_pos_] );
623  a3 = radnorm2( joint_state_.position[blw_pos_] );
624  a4 = radnorm2( joint_state_.position[brw_pos_] );
625  double v1x = -v1 * cos( a1 ); double v1y = -v1 * sin( a1 );
626  double v2x = v2 * cos( a2 ); double v2y = v2 * sin( a2 );
627  double v3x = v3 * cos( a3 ); double v3y = v3 * sin( a3 );
628  double v4x = -v4 * cos( a4 ); double v4y = -v4 * sin( a4 );
629  double C = (v4y + v1y) / 2.0;
630  double B = (v2x + v1x) / 2.0;
631  double D = (v2y + v3y) / 2.0;
632  double A = (v3x + v4x) / 2.0;
633  // double W = ( (B-A)/summit_xl_wheelbase_ ); // + (D-C)/summit_xl_trackwidth_ ) / 2.0;
634  robot_pose_vx_ = (A+B) / 2.0;
635  robot_pose_vy_ = (C+D) / 2.0;
636  }
637 
638  // Compute Position
639  double fSamplePeriod = 1.0 / desired_freq_;
640  robot_pose_pa_ += ang_vel_z_ * fSamplePeriod; // this velocity comes from IMU callback
641  robot_pose_px_ += robot_pose_vx_ * fSamplePeriod;
642  robot_pose_py_ += robot_pose_vy_ * fSamplePeriod;
643  // ROS_INFO("Odom estimated x=%5.2f y=%5.2f a=%5.2f", robot_pose_px_, robot_pose_py_, robot_pose_pa_);
644 }
645 
646 // Publish robot odometry tf and topic depending
648 {
649  ros::Time current_time = ros::Time::now();
650 
651  //first, we'll publish the transform over tf
652  geometry_msgs::TransformStamped odom_trans;
653  odom_trans.header.stamp = current_time;
654  odom_trans.header.frame_id = "odom";
655  odom_trans.child_frame_id = "base_footprint";
656 
657  odom_trans.transform.translation.x = robot_pose_px_;
658  odom_trans.transform.translation.y = robot_pose_py_;
659  odom_trans.transform.translation.z = 0.0;
660  odom_trans.transform.rotation.x = orientation_x_;
661  odom_trans.transform.rotation.y = orientation_y_;
662  odom_trans.transform.rotation.z = orientation_z_;
663  odom_trans.transform.rotation.w = orientation_w_;
664 
665  // send the transform over /tf
666  // activate / deactivate with param
667  // this tf in needed when not using robot_pose_ekf
668  if (publish_odom_tf_) odom_broadcaster.sendTransform(odom_trans);
669 
670  //next, we'll publish the odometry message over ROS
671  nav_msgs::Odometry odom;
672  odom.header.stamp = current_time;
673  odom.header.frame_id = "odom";
674 
675  //set the position
676  // Position
677  odom.pose.pose.position.x = robot_pose_px_;
678  odom.pose.pose.position.y = robot_pose_py_;
679  odom.pose.pose.position.z = 0.0;
680  // Orientation
681  odom.pose.pose.orientation.x = orientation_x_;
682  odom.pose.pose.orientation.y = orientation_y_;
683  odom.pose.pose.orientation.z = orientation_z_;
684  odom.pose.pose.orientation.w = orientation_w_;
685  // Pose covariance
686  for(int i = 0; i < 6; i++)
687  odom.pose.covariance[i*6+i] = 0.1; // test 0.001
688 
689  //set the velocity
690  odom.child_frame_id = "base_footprint";
691  // Linear velocities
692  odom.twist.twist.linear.x = robot_pose_vx_;
693  odom.twist.twist.linear.y = robot_pose_vy_;
694  odom.twist.twist.linear.z = 0.0;
695  // Angular velocities
696  odom.twist.twist.angular.x = ang_vel_x_;
697  odom.twist.twist.angular.y = ang_vel_y_;
698  odom.twist.twist.angular.z = ang_vel_z_;
699  // Twist covariance
700  for(int i = 0; i < 6; i++)
701  odom.twist.covariance[6*i+i] = 0.1; // test 0.001
702 
703  //publish the message
704  odom_pub_.publish(odom);
705 }
706 
708 void stopping()
709 {}
710 
711 
712 /*
713  * \brief Checks that the robot is receiving at a correct frequency the command messages. Diagnostics
714  *
715  */
717 {
718  ros::Time current_time = ros::Time::now();
719 
720  double diff = (current_time - last_command_time_).toSec();
721 
722  if(diff > 1.0){
723  stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Topic is not receiving commands");
724  //ROS_INFO("check_command_subscriber: %lf seconds without commands", diff);
725  // TODO: Set Speed References to 0
726  }else{
727  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Topic receiving commands");
728  }
729 }
730 
731 
732 // Set the base velocity command
733 void setCommand(const geometry_msgs::Twist &cmd_vel)
734 {
735  v_ref_x_ = saturation(cmd_vel.linear.x, -10.0, 10.0);
736  v_ref_y_ = saturation(cmd_vel.linear.y, -10.0, 10.0);
737  w_ref_ = saturation(cmd_vel.angular.z, -10.0, 10.0); // -10.0 10.0
738  v_ref_z_ = saturation(cmd_vel.linear.z, -10.0, 10.0);
739 }
740 
741 // CALLBACKS
742 // Service SetMode
743 bool srvCallback_SetMode(robotnik_msgs::set_mode::Request& request, robotnik_msgs::set_mode::Response& response)
744 {
745  // Check if the selected mode is available or not
746  // 1 - SKID STEERING
747  // 2 - OMNIDRIVE
748  // (3 - SWERVE)
749 
750  ROS_INFO("SummitXLControllerClass::srvCallback_SetMode request.mode= %d", request.mode);
751  if (request.mode == 1) {
752  active_kinematic_mode_ = request.mode;
753  return true;
754  }
755  if (request.mode == 2) {
756  if (kinematic_modes_ == 2) {
757  active_kinematic_mode_ = request.mode;
758  return true;
759  }
760  else return false;
761  }
762  return false;
763 }
764 
765 // Service GetMode
766 bool srvCallback_GetMode(robotnik_msgs::get_mode::Request& request, robotnik_msgs::get_mode::Response& response)
767 {
768  response.mode = active_kinematic_mode_;
769  return true;
770 }
771 
772 
773 // Service SetOdometry
774 bool srvCallback_SetOdometry(robotnik_msgs::set_odometry::Request &request, robotnik_msgs::set_odometry::Response &response )
775 {
776  // ROS_INFO("summit_xl_odometry::set_odometry: request -> x = %f, y = %f, a = %f", req.x, req.y, req.orientation);
777  //robot_pose_px_ = req.x;
778  //robot_pose_py_ = req.y;
779  //robot_pose_pa_ = req.orientation;
780 
781  response.ret = true;
782  return true;
783 }
784 
785 
786 // Topic command
787 void jointStateCallback(const sensor_msgs::JointStateConstPtr& msg)
788 {
789  joint_state_ = *msg;
790  read_state_ = true;
791 }
792 
793 // Topic command
794 void commandCallback(const geometry_msgs::TwistConstPtr& msg)
795 {
796  // Safety check
797  last_command_time_ = ros::Time::now();
798  subs_command_freq->tick(); // For diagnostics
799 
800  base_vel_msg_ = *msg;
801  this->setCommand(base_vel_msg_);
802 }
803 
804 // Topic ptz command
805 void command_ptzCallback(const robotnik_msgs::ptzConstPtr& msg)
806 {
807  pos_ref_pan_ += msg->pan / 180.0 * PI;
808  pos_ref_tilt_ += msg->tilt / 180.0 * PI;
809 }
810 
811 // Imu callback
812 void imuCallback( const sensor_msgs::Imu& imu_msg){
813 
814  orientation_x_ = imu_msg.orientation.x;
815  orientation_y_ = imu_msg.orientation.y;
816  orientation_z_ = imu_msg.orientation.z;
817  orientation_w_ = imu_msg.orientation.w;
818 
819  ang_vel_x_ = imu_msg.angular_velocity.x;
820  ang_vel_y_ = imu_msg.angular_velocity.y;
821  ang_vel_z_ = imu_msg.angular_velocity.z;
822 
823  lin_acc_x_ = imu_msg.linear_acceleration.x;
824  lin_acc_y_ = imu_msg.linear_acceleration.y;
825  lin_acc_z_ = imu_msg.linear_acceleration.z;
826 }
827 
828 double saturation(double u, double min, double max)
829 {
830  if (u>max) u=max;
831  if (u<min) u=min;
832  return u;
833 }
834 
835 double radnorm( double value )
836 {
837  while (value > PI) value -= PI;
838  while (value < -PI) value += PI;
839  return value;
840 }
841 
842 double radnorm2( double value )
843 {
844  while (value > 2.0*PI) value -= 2.0*PI;
845  while (value < -2.0*PI) value += 2.0*PI;
846  return value;
847 }
848 
849 bool spin()
850 {
851  ROS_INFO("summit_xl_robot_control::spin()");
852  ros::Rate r(desired_freq_); // 50.0
853 
854  while (!ros::isShuttingDown()) // Using ros::isShuttingDown to avoid restarting the node during a shutdown.
855  {
856  if (starting() == 0)
857  {
858  while(ros::ok() && node_handle_.ok()) {
859  UpdateControl();
860  UpdateOdometry();
861  PublishOdometry();
862  diagnostic_.update();
863  ros::spinOnce();
864  r.sleep();
865  }
866  ROS_INFO("END OF ros::ok() !!!");
867  } else {
868  // No need for diagnostic here since a broadcast occurs in start
869  // when there is an error.
870  usleep(1000000);
871  ros::spinOnce();
872  }
873  }
874 
875  ROS_INFO("summit_xl_robot_control::spin() - end");
876  return true;
877 }
878 
879 }; // Class SummitXLControllerClass
880 
881 int main(int argc, char** argv)
882 {
883  ros::init(argc, argv, "summit_xl_robot_control");
884 
885  ros::NodeHandle n;
886  SummitXLControllerClass sxlrc(n);
887 
888 
889  // ros::ServiceServer service = n.advertiseService("set_odometry", &summit_xl_node::set_odometry, &sxlc);
890  sxlrc.spin();
891 
892  return (0);
893 
894 
895 }
896 
int main(int argc, char **argv)
SummitXLControllerClass(ros::NodeHandle h)
#define SUMMIT_XL_MAX_COMMAND_REC_FREQ
void publish(const boost::shared_ptr< M > &message) const
void check_command_subscriber(diagnostic_updater::DiagnosticStatusWrapper &stat)
#define SUMMIT_XL_WHEELBASE
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())
tf::TransformBroadcaster odom_broadcaster
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)
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)
#define SUMMIT_XL_MIN_COMMAND_REC_FREQ
bool srvCallback_SetMode(robotnik_msgs::set_mode::Request &request, robotnik_msgs::set_mode::Response &response)
void command_ptzCallback(const robotnik_msgs::ptzConstPtr &msg)
#define SKID_STEERING
diagnostic_updater::FunctionDiagnosticTask command_freq_
#define MECANUM_STEERING
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
#define PI
void UpdateControl()
Controller update loop.
geometry_msgs::Twist base_vel_msg_
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()
#define SUMMIT_XL_TRACKWIDTH
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.
diagnostic_updater::HeaderlessTopicDiagnostic * subs_command_freq
bool sleep()
TFSIMD_FORCE_INLINE const tfScalar & w() const
sensor_msgs::JointState joint_state_
bool getParam(const std::string &key, std::string &s) const
diagnostic_updater::FrequencyStatus freq_diag_
static Time now()
bool ok() const
#define SUMMIT_XL_WHEEL_DIAMETER
ROSCPP_DECL void spinOnce()
#define ROS_ERROR(...)
diagnostic_updater::Updater diagnostic_
#define SUMMIT_XL_D_TRACKS_M


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