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 #include <gazebo_msgs/ModelState.h>
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 
102 
103  // Joint states published by the joint_state_controller of the Controller Manager
105 
106  // High level robot command
108 
109  // High level robot command
111 
112  //ros::Subscriber gyro_sub_;
113 
114  // Services
118 
119  // Topics - skid - velocity
120  std::string frw_vel_topic_;
121  std::string flw_vel_topic_;
122  std::string brw_vel_topic_;
123  std::string blw_vel_topic_;
124 
125  // Joint names - skid - velocity
130 
131  // Topics - swerve - position
132  std::string frw_pos_topic_;
133  std::string flw_pos_topic_;
134  std::string brw_pos_topic_;
135  std::string blw_pos_topic_;
136 
137  // Joint names - swerve - position
142 
143  // Topic - scissor - position
144  std::string scissor_pos_topic_;
145 
146  // Topic - odom
147  std::string odom_topic_;
148 
149  // Joint names - ptz - position
150  std::string joint_camera_pan;
151  std::string joint_camera_tilt;
152 
153  // Topics - ptz
154  std::string pan_pos_topic_;
155  std::string tilt_pos_topic_;
156 
157  // Joint name - scissor mechanism
159 
160  // Selected operation mode
163 
164  // Indexes to joint_states
165  int frw_vel_, flw_vel_, blw_vel_, brw_vel_;
166  int frw_pos_, flw_pos_, blw_pos_, brw_pos_;
168  int pan_pos_, tilt_pos_;
169 
170 
171  // Robot Speeds
175 
176  // Robot Positions
182 
183  // Robot Joint States
184  sensor_msgs::JointState joint_state_;
185 
186  // Command reference
187  geometry_msgs::Twist base_vel_msg_;
188 
189  // External speed references
190  double v_ref_x_;
191  double v_ref_y_;
192  double w_ref_;
193  double v_ref_z_;
194  double pos_ref_pan_;
196 
197  // Flag to indicate if joint_state has been read
198  bool read_state_;
199 
200  // Robot configuration parameters
205 
206  // IMU values
207  double ang_vel_x_;
208  double ang_vel_y_;
209  double ang_vel_z_;
210 
211  double lin_acc_x_;
212  double lin_acc_y_;
213  double lin_acc_z_;
214 
219 
220  // Parameter that defines if odom tf is published or not
223 
225 
226  // Publisher for odom topic
228 
229  // Broadcaster for odom tf
231 
232 
237  node_handle_(h), private_node_handle_("~"),
238  desired_freq_(100),
239  freq_diag_(diagnostic_updater::FrequencyStatusParam(&desired_freq_, &desired_freq_, 0.05) ),
240  command_freq_("Command frequency check", boost::bind(&SummitXLControllerClass::check_command_subscriber, this, _1))
241  {
242 
243  // /summit_xl/joint_blw_velocity_controller/joint
244  ROS_INFO("summit_xl_robot_control_node - Init ");
245 
246  // 4-Axis Skid Steer Rover
247  // 8-Axis Omni-drive as 4-Axis Mecanum drive
248  kinematic_modes_ = 1;
249 
250  // Get robot model from the parameters
251  if (!private_node_handle_.getParam("model", robot_model_)) {
252  ROS_ERROR("Robot model not defined.");
253  exit(-1);
254  }
255  else ROS_INFO("Robot Model : %s", robot_model_.c_str());
256 
257  // Skid configuration - topics
258  private_node_handle_.param<std::string>("frw_vel_topic", frw_vel_topic_, "joint_frw_velocity_controller/command");
259  private_node_handle_.param<std::string>("flw_vel_topic", flw_vel_topic_, "joint_flw_velocity_controller/command");
260  private_node_handle_.param<std::string>("blw_vel_topic", blw_vel_topic_, "joint_blw_velocity_controller/command");
261  private_node_handle_.param<std::string>("brw_vel_topic", brw_vel_topic_, "joint_brw_velocity_controller/command");
262 
263  // Skid configuration - Joint names
264  private_node_handle_.param<std::string>("joint_front_right_wheel", joint_front_right_wheel, "joint_front_right_wheel");
265  private_node_handle_.param<std::string>("joint_front_left_wheel", joint_front_left_wheel, "joint_front_left_wheel");
266  private_node_handle_.param<std::string>("joint_back_left_wheel", joint_back_left_wheel, "joint_back_left_wheel");
267  private_node_handle_.param<std::string>("joint_back_right_wheel", joint_back_right_wheel, "joint_back_right_wheel");
268 
269  if (!private_node_handle_.getParam("summit_xl_wheelbase", summit_xl_wheelbase_))
270  summit_xl_wheelbase_ = SUMMIT_XL_WHEELBASE;
271  if (!private_node_handle_.getParam("summit_xl_trackwidth", summit_xl_trackwidth_))
272  summit_xl_trackwidth_ = SUMMIT_XL_TRACKWIDTH;
273 
274  // Omni configuration - topics
275  if ((robot_model_=="summit_xl_omni") || (robot_model_=="x_wam")) {
276  kinematic_modes_ = 2;
277 
278  // x-wam only configuration
279  if (robot_model_=="x_wam") {
280  private_node_handle_.param<std::string>("scissor_pos_topic", scissor_pos_topic_, "joint_scissor_position_controller/command");
281  private_node_handle_.param<std::string>("scissor_prismatic_joint", scissor_prismatic_joint, "scissor_prismatic_joint");
282  }
283  }
284 
285  // PTZ topics
286  private_node_handle_.param<std::string>("pan_pos_topic", pan_pos_topic_, "joint_pan_position_controller/command");
287  private_node_handle_.param<std::string>("tilt_pos_topic", tilt_pos_topic_, "joint_tilt_position_controller/command");
288  private_node_handle_.param<std::string>("joint_camera_pan", joint_camera_pan, "joint_camera_pan");
289  private_node_handle_.param<std::string>("joint_camera_tilt", joint_camera_tilt, "joint_camera_tilt");
290 
291  // Odom topic
292  node_handle_.param<std::string>("odom_topic", odom_topic_, "/odom"); // to match that from summit_xl_controller (real robot), which uses an absolute defined name (/odom)
293 
294  // Robot parameters
295  if (!private_node_handle_.getParam("summit_xl_wheel_diameter", summit_xl_wheel_diameter_))
296  summit_xl_wheel_diameter_ = SUMMIT_XL_WHEEL_DIAMETER;
297  if (!private_node_handle_.getParam("summit_xl_d_tracks_m", summit_xl_d_tracks_m_))
298  summit_xl_d_tracks_m_ = SUMMIT_XL_D_TRACKS_M;
299 
300  ROS_INFO("summit_xl_wheel_diameter_ = %5.2f", summit_xl_wheel_diameter_);
301  ROS_INFO("summit_xl_d_tracks_m_ = %5.2f", summit_xl_d_tracks_m_);
302 
303  private_node_handle_.param("publish_odom_tf", publish_odom_tf_, true);
304  private_node_handle_.param("publish_odom_msg", publish_odom_msg_, true);
305 
306  if (publish_odom_tf_) ROS_INFO("PUBLISHING odom->base_footprint tf");
307  else ROS_INFO("NOT PUBLISHING odom->base_footprint tf");
308 
309  if (publish_odom_msg_) ROS_INFO("PUBLISHING odom->base_footprint msg");
310  else ROS_INFO("NOT PUBLISHING odom->base_footprint msg");
311 
312  // Robot Speeds
313  linearSpeedXMps_ = 0.0;
314  linearSpeedYMps_ = 0.0;
315  angularSpeedRads_ = 0.0;
316 
317  // Robot Positions
318  robot_pose_px_ = 0.0;
319  robot_pose_py_ = 0.0;
320  robot_pose_pa_ = 0.0;
321  robot_pose_vx_ = 0.0;
322  robot_pose_vy_ = 0.0;
323 
324  // External speed references
325  v_ref_x_ = 0.0;
326  v_ref_y_ = 0.0;
327  w_ref_ = 0.0;
328  v_ref_z_ = 0.0;
329  pos_ref_pan_ = 0.0;
330  pos_ref_tilt_= 0.0;
331 
332  // Imu variables
333  ang_vel_x_ = 0.0; ang_vel_y_ = 0.0; ang_vel_z_ = 0.0;
334  lin_acc_x_ = 0.0; lin_acc_y_ = 0.0; lin_acc_z_ = 0.0;
335  orientation_x_ = 0.0; orientation_y_ = 0.0; orientation_z_ = 0.0; orientation_w_ = 1.0;
336 
337  // Active kinematic mode
338  active_kinematic_mode_ = SKID_STEERING;
339 
340  // Advertise services
341  srv_SetMode_ = node_handle_.advertiseService("/summit_xl_controller/set_mode", &SummitXLControllerClass::srvCallback_SetMode, this);
342  srv_GetMode_ = node_handle_.advertiseService("get_mode", &SummitXLControllerClass::srvCallback_GetMode, this);
343  srv_SetOdometry_ = node_handle_.advertiseService("set_odometry", &SummitXLControllerClass::srvCallback_SetOdometry, this);
344 
345  // Subscribe to joint states topic
346  joint_state_sub_ = node_handle_.subscribe<sensor_msgs::JointState>("/joint_states", 1, &SummitXLControllerClass::jointStateCallback, this); // to match that from summit_xl_controller (real robot), which uses a absolute defined name (/joint_states)
347 
348  // Subscribe to imu data
349  imu_sub_ = node_handle_.subscribe("/imu/data", 1, &SummitXLControllerClass::imuCallback, this); // to match that from summit_xl_controller (real robot), which uses a absolute defined name (/imu/data)
350 
351 
352  // Adevertise reference topics for the controllers
353  ref_vel_frw_ = node_handle_.advertise<std_msgs::Float64>( frw_vel_topic_, 50);
354  ref_vel_flw_ = node_handle_.advertise<std_msgs::Float64>( flw_vel_topic_, 50);
355  ref_vel_blw_ = node_handle_.advertise<std_msgs::Float64>( blw_vel_topic_, 50);
356  ref_vel_brw_ = node_handle_.advertise<std_msgs::Float64>( brw_vel_topic_, 50);
357 
358 
359  if (robot_model_=="x_wam") {
360  ref_pos_scissor_ = node_handle_.advertise<std_msgs::Float64>( scissor_pos_topic_, 50);
361  }
362 
363  ref_pos_pan_ = node_handle_.advertise<std_msgs::Float64>( pan_pos_topic_, 50);
364  ref_pos_tilt_ = node_handle_.advertise<std_msgs::Float64>( tilt_pos_topic_, 50);
365 
366  // Subscribe to command topic
367  cmd_sub_ = node_handle_.subscribe<geometry_msgs::Twist>("/summit_xl_control/cmd_vel", 1, &SummitXLControllerClass::commandCallback, this); // to match that from summit_xl_controller (real robot), which publishes through /summit_xl_controller/command, but in the summit_xl_controller is remapped to /summit_xl_control/cmd_vel
368 
369  // Subscribe to ptz command topic
370  ptz_sub_ = node_handle_.subscribe<robotnik_msgs::ptz>("/axis_camera/ptz_command", 1, &SummitXLControllerClass::command_ptzCallback, this); // to match that from summit_xl_controller (real robot), which uses a absolute defined name (/imu/data)
371 
372  // Publish odometry
373  odom_pub_ = node_handle_.advertise<nav_msgs::Odometry>(odom_topic_, 1000);
374 
375  // Component frequency diagnostics
376  diagnostic_.setHardwareID("summit_xl_robot_control - simulation");
377  diagnostic_.add( freq_diag_ );
378  diagnostic_.add( command_freq_ );
379 
380  gazebo_set_model_ = node_handle_.advertise<gazebo_msgs::ModelState>("/gazebo/set_model_state", 1);
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_control/cmd_vel", diagnostic_, // to match that from summit_xl_controller (real robot), which publishes through /summit_xl_controller/command, but in the summit_xl_controller launch file is remapped to /summit_xl_control/cmd_vel
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  // Initialize joint indexes according to joint names
401  if (read_state_) {
402  vector<string> joint_names = joint_state_.name;
403  frw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_right_wheel)) - joint_names.begin();
404  flw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_left_wheel)) - joint_names.begin();
405  blw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_left_wheel)) - joint_names.begin();
406  brw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_right_wheel)) - joint_names.begin();
407  if (robot_model_=="x_wam") {
408  scissor_pos_ = find (joint_names.begin(),joint_names.end(), string(scissor_prismatic_joint)) - joint_names.begin();
409  }
410  // For publishing the ptz joint state
411  //pan_pos_ = find(joint_names.begin(), joint_names.end(), string(joint_camera_pan)) - joint_names.begin();
412  //tilt_pos_ = find(joint_names.begin(), joint_names.end(), string(joint_camera_tilt)) - joint_names.begin();
413  return 0;
414  }
415  else return -1;
416 }
417 
418 
421 {
422  // Depending on the robot configuration
423  if (active_kinematic_mode_ == SKID_STEERING) {
424  double v_left_mps, v_right_mps;
425 
426  // Calculate its own velocities for realize the motor control
427  v_left_mps = ((joint_state_.velocity[blw_vel_] + joint_state_.velocity[flw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0);
428  v_right_mps = ((joint_state_.velocity[brw_vel_] + joint_state_.velocity[frw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0);
429  // sign according to urdf (if wheel model is not symetric, should be inverted)
430 
431  linearSpeedXMps_ = (v_right_mps + v_left_mps) / 2.0; // m/s
432  angularSpeedRads_ = (v_right_mps - v_left_mps) / summit_xl_d_tracks_m_; // rad/s
433 
434  std_msgs::Float64 frw_ref_msg;
435  std_msgs::Float64 flw_ref_msg;
436  std_msgs::Float64 blw_ref_msg;
437  std_msgs::Float64 brw_ref_msg;
438 
439  frw_ref_msg.data = (v_ref_x_ + w_ref_* summit_xl_d_tracks_m_/2.0) / (summit_xl_wheel_diameter_ / 2.0);
440  brw_ref_msg.data = (v_ref_x_ + w_ref_* summit_xl_d_tracks_m_/2.0) / (summit_xl_wheel_diameter_ / 2.0);
441  flw_ref_msg.data = (v_ref_x_ - w_ref_* summit_xl_d_tracks_m_/2.0) / (summit_xl_wheel_diameter_ / 2.0);
442  blw_ref_msg.data = (v_ref_x_ - w_ref_* summit_xl_d_tracks_m_/2.0) / (summit_xl_wheel_diameter_ / 2.0);
443 
444  ref_vel_frw_.publish( frw_ref_msg );
445  ref_vel_flw_.publish( flw_ref_msg );
446  ref_vel_blw_.publish( blw_ref_msg );
447  ref_vel_brw_.publish( brw_ref_msg );
448  }
449 
450 
451  // Depending on the robot configuration
452  if (active_kinematic_mode_ == MECANUM_STEERING) {
453 
454  // Speed references for motor control
455  // double v_left_mps, v_right_mps;
456  double v_frw_mps, v_flw_mps, v_blw_mps, v_brw_mps;
457  v_frw_mps = joint_state_.velocity[frw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
458  v_flw_mps = joint_state_.velocity[flw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
459  v_blw_mps = joint_state_.velocity[blw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
460  v_brw_mps = joint_state_.velocity[brw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
461 
462  double vx = v_ref_x_;
463  double vy = v_ref_y_;
464  double w = w_ref_;
465  double L = summit_xl_wheelbase_;
466  double W = summit_xl_trackwidth_;
467 
468  double lab = (SUMMIT_XL_WHEELBASE + SUMMIT_XL_TRACKWIDTH) / 2.0;
469  double q1 = (v_ref_x_ + v_ref_y_ + lab * w_ref_) / (summit_xl_wheel_diameter_ / 2.0);
470  double q2 = (v_ref_x_ - v_ref_y_ - lab * w_ref_) / (summit_xl_wheel_diameter_ / 2.0);
471  double q3 = (v_ref_x_ + v_ref_y_ - lab * w_ref_) / (summit_xl_wheel_diameter_ / 2.0);
472  double q4 = (v_ref_x_ - v_ref_y_ + lab * w_ref_) / (summit_xl_wheel_diameter_ / 2.0);
473 
474  //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);
475 
476  // Motor control actions
477  double limit = 40.0;
478 
479  // Axis are not reversed in the omni (swerve) configuration
480  std_msgs::Float64 frw_ref_vel_msg;
481  std_msgs::Float64 flw_ref_vel_msg;
482  std_msgs::Float64 blw_ref_vel_msg;
483  std_msgs::Float64 brw_ref_vel_msg;
484 
485  frw_ref_vel_msg.data = saturation(q1, -limit, limit);
486  flw_ref_vel_msg.data = saturation(q2, -limit, limit);
487  blw_ref_vel_msg.data = saturation(q3, -limit, limit);
488  brw_ref_vel_msg.data = saturation(q4, -limit, limit);
489 
490  ref_vel_frw_.publish( frw_ref_vel_msg );
491  ref_vel_flw_.publish( flw_ref_vel_msg );
492  ref_vel_blw_.publish( blw_ref_vel_msg );
493  ref_vel_brw_.publish( brw_ref_vel_msg );
494  }
495 
496  // Depending on the robot model
497  if (robot_model_ == "x_wam") {
498  // Position reference for the scissor mechanism
499  static double scissor_ref_pos = 0.0;
500  scissor_ref_pos += (v_ref_z_ / desired_freq_);
501  std_msgs::Float64 scissor_ref_pos_msg;
502  // joint_state_.position[scissor_pos_] not used, just setpoint
503  scissor_ref_pos_msg.data = saturation(scissor_ref_pos, 0.0, 0.5);
504  ref_pos_scissor_.publish( scissor_ref_pos_msg );
505  }
506 
507  // PTZ
508  std_msgs::Float64 pan_ref_pos_msg, tilt_ref_pos_msg;
509  pan_ref_pos_msg.data = pos_ref_pan_; //saturation( pos_ref_pan_, 0.0, 0.5);
510  ref_pos_pan_.publish( pan_ref_pos_msg );
511  tilt_ref_pos_msg.data = pos_ref_tilt_; //saturation( pos_ref_tilt_, 0.0, 0.5);
512  ref_pos_tilt_.publish( tilt_ref_pos_msg );
513 }
514 
515 // Update robot odometry depending on kinematic configuration
517 {
518  // Depending on the robot configuration
519 
520  if (active_kinematic_mode_ == SKID_STEERING) {
521 
522  // Compute Velocity (linearSpeedXMps_ computed in control
523  robot_pose_vx_ = linearSpeedXMps_ * cos(robot_pose_pa_);
524  robot_pose_vy_ = linearSpeedXMps_ * sin(robot_pose_pa_);
525  }
526 
527  // Depending on the robot configuration
528  if (active_kinematic_mode_ == MECANUM_STEERING) {
529 
530  // Linear speed of each wheel
531  double v1, v2, v3, v4;
532  v1 = joint_state_.velocity[frw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
533  v2 = joint_state_.velocity[flw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
534  v3 = joint_state_.velocity[blw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
535  v4 = joint_state_.velocity[brw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
536 
537  double lab = (SUMMIT_XL_WHEELBASE + SUMMIT_XL_TRACKWIDTH) / 2.0;
538 
539  double vx = (1 / 4.0) * (v1 + v2 + v3 + v4);
540  double vy = (1 / 4.0) * (v1 - v2 + v3 - v4);
541  double wr = (1 / (4.0 * lab)) * (v1 - v2 - v3 + v4);
542 
543  robot_pose_vx_ = vx;
544  robot_pose_vy_ = vy;
545  }
546 
547  // Compute Position
548  double fSamplePeriod = 1.0 / desired_freq_;
549  // robot_pose_pa_ += ang_vel_z_ * fSamplePeriod; // this velocity comes from IMU callback
550 
551  // read the orientation directly from the IMU
552  double roll, pitch, yaw;
553  tf::Matrix3x3(tf::Quaternion(orientation_x_, orientation_y_, orientation_z_, orientation_w_)).getRPY(roll, pitch, yaw);
554  robot_pose_pa_ = yaw;
555  robot_pose_px_ += robot_pose_vx_ * fSamplePeriod;
556  robot_pose_py_ += robot_pose_vy_ * fSamplePeriod;
557  // ROS_INFO("Odom estimated x=%5.2f y=%5.2f a=%5.2f", robot_pose_px_, robot_pose_py_, robot_pose_pa_);
558 }
559 
560 // Publish robot odometry tf and topic depending
562 {
563  ros::Time current_time = ros::Time::now();
564 
565  //first, we'll publish the transform over tf
566  geometry_msgs::TransformStamped odom_trans;
567  odom_trans.header.stamp = current_time;
568  odom_trans.header.frame_id = "odom";
569  odom_trans.child_frame_id = "base_footprint";
570 
571  odom_trans.transform.translation.x = robot_pose_px_;
572  odom_trans.transform.translation.y = robot_pose_py_;
573  odom_trans.transform.translation.z = 0.0;
574  odom_trans.transform.rotation.x = orientation_x_;
575  odom_trans.transform.rotation.y = orientation_y_;
576  odom_trans.transform.rotation.z = orientation_z_;
577  odom_trans.transform.rotation.w = orientation_w_;
578 
579  // send the transform over /tf
580  // activate / deactivate with param
581  // this tf in needed when not using robot_pose_ekf
582  if (publish_odom_tf_) {
583  odom_broadcaster.sendTransform(odom_trans);
584  }
585 
586  //next, we'll publish the odometry message over ROS
587  nav_msgs::Odometry odom;
588  odom.header.stamp = current_time;
589  odom.header.frame_id = "odom";
590 
591  //set the position
592  // Position
593  odom.pose.pose.position.x = robot_pose_px_;
594  odom.pose.pose.position.y = robot_pose_py_;
595  odom.pose.pose.position.z = 0.0;
596  // Orientation
597  odom.pose.pose.orientation.x = orientation_x_;
598  odom.pose.pose.orientation.y = orientation_y_;
599  odom.pose.pose.orientation.z = orientation_z_;
600  odom.pose.pose.orientation.w = orientation_w_;
601  // Pose covariance
602  for(int i = 0; i < 6; i++)
603  odom.pose.covariance[i*6+i] = 0.001; // test 0.001
604  odom.twist.covariance[35] = 0.03;
605 
606  //set the velocity
607  odom.child_frame_id = "base_footprint";
608  // Linear velocities
609 // odom.twist.twist.linear.x = robot_pose_vx_;
610 // odom.twist.twist.linear.y = robot_pose_vy_;
611  if (active_kinematic_mode_ == SKID_STEERING) {
612  odom.twist.twist.linear.x = linearSpeedXMps_;
613  odom.twist.twist.linear.y = 0;
614  }
615  else if (active_kinematic_mode_ == MECANUM_STEERING) {
616  odom.twist.twist.linear.x = robot_pose_vx_;
617  odom.twist.twist.linear.y = robot_pose_vy_;
618  }
619 
620  odom.twist.twist.linear.z = 0.0;
621  // Angular velocities
622  odom.twist.twist.angular.x = ang_vel_x_;
623  odom.twist.twist.angular.y = ang_vel_y_;
624  odom.twist.twist.angular.z = ang_vel_z_;
625  // Twist covariance
626  for(int i = 0; i < 6; i++)
627  odom.twist.covariance[6*i+i] = 0.001; // test 0.001
628  odom.twist.covariance[35] = 0.03;
629 
630  //publish the message
631  if (publish_odom_msg_)
632  odom_pub_.publish(odom);
633 
634 // gazebo_msgs::ModelState model_state;
635 // model_state.model_name = "summit_xl"; //TODO read from params
636 // model_state.pose = odom.pose.pose;
637 // model_state.twist = odom.twist.twist;
638 // gazebo_set_model_.publish(model_state);
639 }
640 
642 void stopping()
643 {}
644 
645 
646 /*
647  * \brief Checks that the robot is receiving at a correct frequency the command messages. Diagnostics
648  *
649  */
651 {
652  ros::Time current_time = ros::Time::now();
653 
654  double diff = (current_time - last_command_time_).toSec();
655 
656  if(diff > 1.0){
657  stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Topic is not receiving commands");
658  //ROS_INFO("check_command_subscriber: %lf seconds without commands", diff);
659  // TODO: Set Speed References to 0
660  }else{
661  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Topic receiving commands");
662  }
663 }
664 
665 
666 // Set the base velocity command
667 void setCommand(const geometry_msgs::Twist &cmd_vel)
668 {
669  v_ref_x_ = saturation(cmd_vel.linear.x, -10.0, 10.0);
670  v_ref_y_ = saturation(cmd_vel.linear.y, -10.0, 10.0);
671  w_ref_ = saturation(cmd_vel.angular.z, -10.0, 10.0); // -10.0 10.0
672  v_ref_z_ = saturation(cmd_vel.linear.z, -10.0, 10.0);
673 }
674 
675 // CALLBACKS
676 // Service SetMode
677 bool srvCallback_SetMode(robotnik_msgs::set_mode::Request& request, robotnik_msgs::set_mode::Response& response)
678 {
679  // Check if the selected mode is available or not
680  // 1 - SKID STEERING
681  // 2 - OMNIDRIVE
682  // (3 - SWERVE)
683 
684  ROS_INFO("SummitXLControllerClass::srvCallback_SetMode request.mode= %d", request.mode);
685  if (request.mode == 1) {
686  active_kinematic_mode_ = request.mode;
687  return true;
688  }
689  if (request.mode == 2) {
690  if (kinematic_modes_ == 2) {
691  active_kinematic_mode_ = request.mode;
692  return true;
693  }
694  else return false;
695  }
696  return false;
697 }
698 
699 // Service GetMode
700 bool srvCallback_GetMode(robotnik_msgs::get_mode::Request& request, robotnik_msgs::get_mode::Response& response)
701 {
702  response.mode = active_kinematic_mode_;
703  return true;
704 }
705 
706 
707 // Service SetOdometry
708 bool srvCallback_SetOdometry(robotnik_msgs::set_odometry::Request &request, robotnik_msgs::set_odometry::Response &response )
709 {
710  ROS_INFO("summit_xl_odometry::set_odometry: request -> x = %f, y = %f, a = %f", request.x, request.y, request.orientation);
711  robot_pose_px_ = request.x;
712  robot_pose_py_ = request.y;
713  robot_pose_pa_ = request.orientation;
714 
715  response.ret = true;
716  return true;
717 }
718 
719 
720 // Topic command
721 void jointStateCallback(const sensor_msgs::JointStateConstPtr& msg)
722 {
723  joint_state_ = *msg;
724  read_state_ = true;
725 }
726 
727 // Topic command
728 void commandCallback(const geometry_msgs::TwistConstPtr& msg)
729 {
730  // Safety check
731  last_command_time_ = ros::Time::now();
732  subs_command_freq->tick(); // For diagnostics
733 
734  base_vel_msg_ = *msg;
735  this->setCommand(base_vel_msg_);
736 }
737 
738 // Topic ptz command
739 void command_ptzCallback(const robotnik_msgs::ptzConstPtr& msg)
740 {
741  pos_ref_pan_ += msg->pan / 180.0 * PI;
742  pos_ref_tilt_ += msg->tilt / 180.0 * PI;
743 }
744 
745 // Imu callback
746 void imuCallback( const sensor_msgs::Imu& imu_msg){
747 
748  orientation_x_ = imu_msg.orientation.x;
749  orientation_y_ = imu_msg.orientation.y;
750  orientation_z_ = imu_msg.orientation.z;
751  orientation_w_ = imu_msg.orientation.w;
752 
753  ang_vel_x_ = imu_msg.angular_velocity.x;
754  ang_vel_y_ = imu_msg.angular_velocity.y;
755  ang_vel_z_ = imu_msg.angular_velocity.z;
756 
757  lin_acc_x_ = imu_msg.linear_acceleration.x;
758  lin_acc_y_ = imu_msg.linear_acceleration.y;
759  lin_acc_z_ = imu_msg.linear_acceleration.z;
760 }
761 
762 double saturation(double u, double min, double max)
763 {
764  if (u>max) u=max;
765  if (u<min) u=min;
766  return u;
767 }
768 
769 double radnorm( double value )
770 {
771  while (value > PI) value -= PI;
772  while (value < -PI) value += PI;
773  return value;
774 }
775 
776 double radnorm2( double value )
777 {
778  while (value > 2.0*PI) value -= 2.0*PI;
779  while (value < -2.0*PI) value += 2.0*PI;
780  return value;
781 }
782 
783 bool spin()
784 {
785  ROS_INFO("summit_xl_robot_control::spin()");
786  ros::Rate r(desired_freq_); // 50.0
787 
788  while (!ros::isShuttingDown()) // Using ros::isShuttingDown to avoid restarting the node during a shutdown.
789  {
790  if (starting() == 0)
791  {
792  while(ros::ok() && node_handle_.ok()) {
793  UpdateControl();
794  UpdateOdometry();
795  PublishOdometry();
796  diagnostic_.update();
797  ros::spinOnce();
798  r.sleep();
799  }
800  ROS_INFO("END OF ros::ok() !!!");
801  } else {
802  // No need for diagnostic here since a broadcast occurs in start
803  // when there is an error.
804  usleep(1000000);
805  ros::spinOnce();
806  }
807  }
808 
809  ROS_INFO("summit_xl_robot_control::spin() - end");
810  return true;
811 }
812 
813 }; // Class SummitXLControllerClass
814 
815 int main(int argc, char** argv)
816 {
817  ros::init(argc, argv, "summit_xl_robot_control");
818 
819  ros::NodeHandle n;
820  SummitXLControllerClass sxlrc(n);
821 
822 
823  // ros::ServiceServer service = n.advertiseService("set_odometry", &summit_xl_node::set_odometry, &sxlc);
824  sxlrc.spin();
825 
826  return (0);
827 
828 
829 }
830 
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
void getRPY(tfScalar &roll, tfScalar &pitch, tfScalar &yaw, unsigned int solution_number=1) const
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
#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_xl_robot_control
Author(s): Roberto Guzmán , Román Navarro , Jorge Ariño
autogenerated on Sun Jul 9 2017 03:05:39