summit_xl_robot_control.cpp
Go to the documentation of this file.
00001 /*
00002  * summit_xl_robot_control
00003  * Copyright (c) 2013, Robotnik Automation, SLL
00004  * All rights reserved.
00005  *
00006  * Redistribution and use in source and binary forms, with or without
00007  * modification, are permitted provided that the following conditions are met:
00008  *
00009  *     * Redistributions of source code must retain the above copyright
00010  *       notice, this list of conditions and the following disclaimer.
00011  *     * Redistributions in binary form must reproduce the above copyright
00012  *       notice, this list of conditions and the following disclaimer in the
00013  *       documentation and/or other materials provided with the distribution.
00014  *     * Neither the name of the Robotnik Automation, SLL. nor the names of its
00015  *       contributors may be used to endorse or promote products derived from
00016  *       this software without specific prior written permission.
00017  *
00018  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00019  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00020  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00021  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
00022  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00023  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00024  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00025  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00026  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00027  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00028  * POSSIBILITY OF SUCH DAMAGE.
00029  *
00030  * \author Robotnik
00031  * \brief Controller for the Summit XL robot in skid-steering / mecanum omni-drive modes.
00032  * \brief simulation of 4DOF Mecanum kinematics by equivalent 8DOF Swerve drive
00033  */
00034 
00035 #include <ros/ros.h>
00036 #include <sensor_msgs/JointState.h>
00037 #include <sensor_msgs/Imu.h>
00038 #include <geometry_msgs/Twist.h>
00039 #include <std_msgs/Float64.h>
00040 #include <tf/transform_broadcaster.h>
00041 #include <nav_msgs/Odometry.h>
00042 #include <robotnik_msgs/set_mode.h>
00043 #include <robotnik_msgs/get_mode.h>
00044 #include <robotnik_msgs/set_odometry.h>
00045 #include <robotnik_msgs/ptz.h>
00046 #include <gazebo_msgs/ModelState.h>
00047 
00048 //#include "self_test/self_test.h"
00049 #include "diagnostic_msgs/DiagnosticStatus.h"
00050 #include "diagnostic_updater/diagnostic_updater.h"
00051 #include "diagnostic_updater/update_functions.h"
00052 #include "diagnostic_updater/DiagnosticStatusWrapper.h"
00053 #include "diagnostic_updater/publisher.h"
00054 
00055 
00056 #define PI 3.1415926535
00057 #define SUMMIT_XL_MIN_COMMAND_REC_FREQ   5.0
00058 #define SUMMIT_XL_MAX_COMMAND_REC_FREQ   150.0
00059 
00060 #define SKID_STEERING                1
00061 #define MECANUM_STEERING             2
00062 
00063 #define SUMMIT_XL_WHEEL_DIAMETER        0.25      // Default wheel diameter
00064 #define SUMMIT_XL_D_TRACKS_M            1.0       // default equivalent W distance (difference is due to slippage of skid steering)
00065 #define SUMMIT_XL_WHEELBASE         0.446     // default real L distance forward to rear axis
00066 #define SUMMIT_XL_TRACKWIDTH        0.408     // default real W distance from left wheels to right wheels
00067     
00068 using namespace std;
00069 
00070 class SummitXLControllerClass {
00071 
00072 public:
00073 
00074   ros::NodeHandle node_handle_;
00075   ros::NodeHandle private_node_handle_;
00076   double desired_freq_;
00077 
00078   // Diagnostics
00079   diagnostic_updater::Updater diagnostic_;                      // General status diagnostic updater
00080   diagnostic_updater::FrequencyStatus freq_diag_;                        // Component frequency diagnostics
00081   diagnostic_updater::HeaderlessTopicDiagnostic *subs_command_freq; // Topic reception frequency diagnostics
00082   ros::Time last_command_time_;                                 // Last moment when the component received a command
00083   diagnostic_updater::FunctionDiagnosticTask command_freq_;
00084 
00085   // Robot model 
00086   std::string robot_model_;
00087   
00088   // Velocity and position references to low level controllers
00089   ros::Publisher ref_vel_flw_;
00090   ros::Publisher ref_vel_frw_;
00091   ros::Publisher ref_vel_blw_;
00092   ros::Publisher ref_vel_brw_;
00093   ros::Publisher ref_pos_flw_;
00094   ros::Publisher ref_pos_frw_;
00095   ros::Publisher ref_pos_blw_;
00096   ros::Publisher ref_pos_brw_; 
00097   ros::Publisher ref_pos_scissor_;
00098   ros::Publisher ref_pos_pan_;
00099   ros::Publisher ref_pos_tilt_;
00100 
00101   ros::Publisher gazebo_set_model_;
00102 
00103   // Joint states published by the joint_state_controller of the Controller Manager
00104   ros::Subscriber joint_state_sub_;
00105 
00106   // High level robot command
00107   ros::Subscriber cmd_sub_;
00108         
00109   // High level robot command
00110   ros::Subscriber ptz_sub_;
00111 
00112   //ros::Subscriber gyro_sub_;
00113 
00114   // Services
00115   ros::ServiceServer srv_SetOdometry_;
00116   ros::ServiceServer srv_SetMode_;
00117   ros::ServiceServer srv_GetMode_;
00118   
00119   // Topics - skid - velocity
00120   std::string frw_vel_topic_;
00121   std::string flw_vel_topic_;
00122   std::string brw_vel_topic_;
00123   std::string blw_vel_topic_;
00124   
00125   // Joint names - skid - velocity 
00126   std::string joint_front_right_wheel;
00127   std::string joint_front_left_wheel;
00128   std::string joint_back_left_wheel;
00129   std::string joint_back_right_wheel;
00130 
00131   // Topics - swerve - position
00132   std::string frw_pos_topic_;
00133   std::string flw_pos_topic_;
00134   std::string brw_pos_topic_;
00135   std::string blw_pos_topic_;
00136     
00137   // Joint names - swerve - position
00138   std::string joint_front_right_steer;
00139   std::string joint_front_left_steer;
00140   std::string joint_back_left_steer;
00141   std::string joint_back_right_steer;
00142 
00143   // Topic - scissor - position
00144   std::string scissor_pos_topic_;
00145   
00146   // Topic - odom
00147   std::string odom_topic_;
00148 
00149   // Joint names - ptz - position
00150   std::string joint_camera_pan;
00151   std::string joint_camera_tilt;
00152 
00153   // Topics - ptz
00154   std::string pan_pos_topic_;
00155   std::string tilt_pos_topic_;
00156     
00157   // Joint name - scissor mechanism
00158   std::string scissor_prismatic_joint;
00159 
00160   // Selected operation mode
00161   int kinematic_modes_;   
00162   int active_kinematic_mode_;
00163 
00164   // Indexes to joint_states
00165   int frw_vel_, flw_vel_, blw_vel_, brw_vel_;
00166   int frw_pos_, flw_pos_, blw_pos_, brw_pos_;
00167   int scissor_pos_;
00168   int pan_pos_, tilt_pos_;
00169 
00170 
00171   // Robot Speeds
00172   double linearSpeedXMps_;
00173   double linearSpeedYMps_;
00174   double angularSpeedRads_;
00175 
00176   // Robot Positions
00177   double robot_pose_px_;
00178   double robot_pose_py_;
00179   double robot_pose_pa_;
00180   double robot_pose_vx_;
00181   double robot_pose_vy_;
00182   
00183   // Robot Joint States
00184   sensor_msgs::JointState joint_state_;
00185   
00186   // Command reference
00187   geometry_msgs::Twist base_vel_msg_;
00188 
00189   // External speed references
00190   double v_ref_x_;
00191   double v_ref_y_;
00192   double w_ref_;
00193   double v_ref_z_;
00194   double pos_ref_pan_;
00195   double pos_ref_tilt_;
00196   
00197   // Flag to indicate if joint_state has been read
00198   bool read_state_; 
00199   
00200   // Robot configuration parameters 
00201   double summit_xl_wheel_diameter_; 
00202   double summit_xl_d_tracks_m_;
00203   double summit_xl_wheelbase_;
00204   double summit_xl_trackwidth_;
00205 
00206   // IMU values
00207   double ang_vel_x_;
00208   double ang_vel_y_;
00209   double ang_vel_z_;
00210 
00211   double lin_acc_x_;
00212   double lin_acc_y_;
00213   double lin_acc_z_;
00214 
00215   double orientation_x_;
00216   double orientation_y_;
00217   double orientation_z_;
00218   double orientation_w_;
00219 
00220   // Parameter that defines if odom tf is published or not
00221   bool publish_odom_tf_;
00222   bool publish_odom_msg_;
00223 
00224   ros::Subscriber imu_sub_; 
00225   
00226   // Publisher for odom topic
00227   ros::Publisher odom_pub_; 
00228 
00229   // Broadcaster for odom tf  
00230   tf::TransformBroadcaster odom_broadcaster;
00231 
00232 
00236 SummitXLControllerClass(ros::NodeHandle h) : diagnostic_(),
00237   node_handle_(h), private_node_handle_("~"), 
00238   desired_freq_(100),
00239   freq_diag_(diagnostic_updater::FrequencyStatusParam(&desired_freq_, &desired_freq_, 0.05)   ),
00240   command_freq_("Command frequency check", boost::bind(&SummitXLControllerClass::check_command_subscriber, this, _1))
00241   {
00242 
00243   // /summit_xl/joint_blw_velocity_controller/joint
00244   ROS_INFO("summit_xl_robot_control_node - Init ");
00245 
00246   // 4-Axis Skid Steer Rover
00247   // 8-Axis Omni-drive as 4-Axis Mecanum drive
00248   kinematic_modes_ = 1;  
00249   
00250   // Get robot model from the parameters
00251   if (!private_node_handle_.getParam("model", robot_model_)) {
00252           ROS_ERROR("Robot model not defined.");
00253           exit(-1);
00254   }
00255   else ROS_INFO("Robot Model : %s", robot_model_.c_str());
00256 
00257   // Skid configuration - topics
00258   private_node_handle_.param<std::string>("frw_vel_topic", frw_vel_topic_, "joint_frw_velocity_controller/command");
00259   private_node_handle_.param<std::string>("flw_vel_topic", flw_vel_topic_, "joint_flw_velocity_controller/command");
00260   private_node_handle_.param<std::string>("blw_vel_topic", blw_vel_topic_, "joint_blw_velocity_controller/command");
00261   private_node_handle_.param<std::string>("brw_vel_topic", brw_vel_topic_, "joint_brw_velocity_controller/command");
00262 
00263   // Skid configuration - Joint names 
00264   private_node_handle_.param<std::string>("joint_front_right_wheel", joint_front_right_wheel, "joint_front_right_wheel");
00265   private_node_handle_.param<std::string>("joint_front_left_wheel", joint_front_left_wheel, "joint_front_left_wheel");
00266   private_node_handle_.param<std::string>("joint_back_left_wheel", joint_back_left_wheel, "joint_back_left_wheel");
00267   private_node_handle_.param<std::string>("joint_back_right_wheel", joint_back_right_wheel, "joint_back_right_wheel");
00268 
00269   if (!private_node_handle_.getParam("summit_xl_wheelbase", summit_xl_wheelbase_))
00270       summit_xl_wheelbase_ = SUMMIT_XL_WHEELBASE;
00271   if (!private_node_handle_.getParam("summit_xl_trackwidth", summit_xl_trackwidth_))
00272       summit_xl_trackwidth_ = SUMMIT_XL_TRACKWIDTH;
00273 
00274   // Omni configuration - topics
00275   if ((robot_model_=="summit_xl_omni") || (robot_model_=="x_wam")) {
00276         kinematic_modes_ = 2;
00277     
00278     // x-wam only configuration
00279     if (robot_model_=="x_wam") {
00280       private_node_handle_.param<std::string>("scissor_pos_topic", scissor_pos_topic_, "joint_scissor_position_controller/command");            
00281           private_node_handle_.param<std::string>("scissor_prismatic_joint", scissor_prismatic_joint, "scissor_prismatic_joint");
00282       } 
00283     }
00284 
00285   // PTZ topics
00286   private_node_handle_.param<std::string>("pan_pos_topic", pan_pos_topic_, "joint_pan_position_controller/command");
00287   private_node_handle_.param<std::string>("tilt_pos_topic", tilt_pos_topic_, "joint_tilt_position_controller/command");
00288   private_node_handle_.param<std::string>("joint_camera_pan", joint_camera_pan, "joint_camera_pan");
00289   private_node_handle_.param<std::string>("joint_camera_tilt", joint_camera_tilt, "joint_camera_tilt");
00290 
00291   // Odom topic
00292   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)
00293   
00294   // Robot parameters
00295   if (!private_node_handle_.getParam("summit_xl_wheel_diameter", summit_xl_wheel_diameter_))
00296     summit_xl_wheel_diameter_ = SUMMIT_XL_WHEEL_DIAMETER;
00297   if (!private_node_handle_.getParam("summit_xl_d_tracks_m", summit_xl_d_tracks_m_))
00298     summit_xl_d_tracks_m_ = SUMMIT_XL_D_TRACKS_M;
00299 
00300   ROS_INFO("summit_xl_wheel_diameter_ = %5.2f", summit_xl_wheel_diameter_);
00301   ROS_INFO("summit_xl_d_tracks_m_ = %5.2f", summit_xl_d_tracks_m_);
00302 
00303   private_node_handle_.param("publish_odom_tf", publish_odom_tf_, true);
00304   private_node_handle_.param("publish_odom_msg", publish_odom_msg_, true);
00305 
00306   if (publish_odom_tf_) ROS_INFO("PUBLISHING odom->base_footprint tf");
00307   else ROS_INFO("NOT PUBLISHING odom->base_footprint tf");
00308   
00309   if (publish_odom_msg_) ROS_INFO("PUBLISHING odom->base_footprint msg");
00310   else ROS_INFO("NOT PUBLISHING odom->base_footprint msg");
00311   
00312   // Robot Speeds
00313   linearSpeedXMps_   = 0.0;
00314   linearSpeedYMps_   = 0.0;
00315   angularSpeedRads_  = 0.0;
00316 
00317   // Robot Positions
00318   robot_pose_px_ = 0.0;
00319   robot_pose_py_ = 0.0;
00320   robot_pose_pa_ = 0.0;
00321   robot_pose_vx_ = 0.0;
00322   robot_pose_vy_ = 0.0;
00323 
00324   // External speed references
00325   v_ref_x_ = 0.0;
00326   v_ref_y_ = 0.0;
00327   w_ref_ = 0.0;
00328   v_ref_z_ = 0.0;
00329   pos_ref_pan_ = 0.0;
00330   pos_ref_tilt_= 0.0;
00331 
00332   // Imu variables
00333   ang_vel_x_ = 0.0; ang_vel_y_ = 0.0; ang_vel_z_ = 0.0;
00334   lin_acc_x_ = 0.0; lin_acc_y_ = 0.0; lin_acc_z_ = 0.0;
00335   orientation_x_ = 0.0; orientation_y_ = 0.0; orientation_z_ = 0.0; orientation_w_ = 1.0;
00336 
00337   // Active kinematic mode
00338   active_kinematic_mode_ = SKID_STEERING;
00339 
00340   // Advertise services
00341   srv_SetMode_ = node_handle_.advertiseService("/summit_xl_controller/set_mode", &SummitXLControllerClass::srvCallback_SetMode, this);
00342   srv_GetMode_ = node_handle_.advertiseService("get_mode", &SummitXLControllerClass::srvCallback_GetMode, this);
00343   srv_SetOdometry_ = node_handle_.advertiseService("set_odometry",  &SummitXLControllerClass::srvCallback_SetOdometry, this);
00344 
00345   // Subscribe to joint states topic
00346   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)
00347 
00348   // Subscribe to imu data
00349   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)
00350 
00351 
00352   // Adevertise reference topics for the controllers 
00353   ref_vel_frw_ = node_handle_.advertise<std_msgs::Float64>( frw_vel_topic_, 50);
00354   ref_vel_flw_ = node_handle_.advertise<std_msgs::Float64>( flw_vel_topic_, 50);
00355   ref_vel_blw_ = node_handle_.advertise<std_msgs::Float64>( blw_vel_topic_, 50);
00356   ref_vel_brw_ = node_handle_.advertise<std_msgs::Float64>( brw_vel_topic_, 50);
00357   
00358   
00359   if (robot_model_=="x_wam") {
00360       ref_pos_scissor_ = node_handle_.advertise<std_msgs::Float64>( scissor_pos_topic_, 50);         
00361   }
00362           
00363   ref_pos_pan_ = node_handle_.advertise<std_msgs::Float64>( pan_pos_topic_, 50);
00364   ref_pos_tilt_ = node_handle_.advertise<std_msgs::Float64>( tilt_pos_topic_, 50);
00365 
00366   // Subscribe to command topic
00367   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
00368 
00369   // Subscribe to ptz command topic
00370   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)
00371   
00372   // Publish odometry 
00373   odom_pub_ = node_handle_.advertise<nav_msgs::Odometry>(odom_topic_, 1000);
00374 
00375   // Component frequency diagnostics
00376   diagnostic_.setHardwareID("summit_xl_robot_control - simulation");
00377   diagnostic_.add( freq_diag_ );
00378   diagnostic_.add( command_freq_ );
00379     
00380   gazebo_set_model_ = node_handle_.advertise<gazebo_msgs::ModelState>("/gazebo/set_model_state", 1);
00381 
00382   // Topics freq control 
00383   // For /summit_xl_robot_control/command
00384   double min_freq = SUMMIT_XL_MIN_COMMAND_REC_FREQ; // If you update these values, the
00385   double max_freq = SUMMIT_XL_MAX_COMMAND_REC_FREQ; // HeaderlessTopicDiagnostic will use the new values.
00386   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
00387                             diagnostic_updater::FrequencyStatusParam(&min_freq, &max_freq, 0.1, 10));
00388   subs_command_freq->addTask(&command_freq_); // Adding an additional task to the control
00389   
00390   // Flag to indicate joint_state has been read
00391   read_state_ = false;
00392 }
00393 
00395 int starting()
00396 {
00397 
00398   ROS_INFO("SummitXLControllerClass::starting");
00399 
00400   // Initialize joint indexes according to joint names 
00401   if (read_state_) {
00402     vector<string> joint_names = joint_state_.name;
00403     frw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_right_wheel)) - joint_names.begin();
00404     flw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_left_wheel)) - joint_names.begin();
00405     blw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_left_wheel)) - joint_names.begin();
00406     brw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_right_wheel)) - joint_names.begin();
00407         if (robot_model_=="x_wam") {
00408           scissor_pos_ = find (joint_names.begin(),joint_names.end(), string(scissor_prismatic_joint)) - joint_names.begin();
00409           }
00410         // For publishing the ptz joint state   
00411         //pan_pos_ = find(joint_names.begin(), joint_names.end(), string(joint_camera_pan)) - joint_names.begin();
00412         //tilt_pos_ = find(joint_names.begin(), joint_names.end(), string(joint_camera_tilt)) - joint_names.begin();
00413     return 0;
00414     }
00415   else return -1;
00416 }
00417 
00418 
00420 void UpdateControl()
00421 {
00422   // Depending on the robot configuration 
00423   if (active_kinematic_mode_ == SKID_STEERING) {
00424           double v_left_mps, v_right_mps;
00425 
00426           // Calculate its own velocities for realize the motor control 
00427           v_left_mps = ((joint_state_.velocity[blw_vel_] + joint_state_.velocity[flw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0);
00428           v_right_mps = ((joint_state_.velocity[brw_vel_] + joint_state_.velocity[frw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0); 
00429           // sign according to urdf (if wheel model is not symetric, should be inverted)
00430 
00431           linearSpeedXMps_ = (v_right_mps + v_left_mps) / 2.0;                       // m/s
00432           angularSpeedRads_ = (v_right_mps - v_left_mps) / summit_xl_d_tracks_m_;    // rad/s
00433 
00434       std_msgs::Float64 frw_ref_msg; 
00435       std_msgs::Float64 flw_ref_msg;
00436       std_msgs::Float64 blw_ref_msg;
00437       std_msgs::Float64 brw_ref_msg;
00438 
00439           frw_ref_msg.data = (v_ref_x_ + w_ref_* summit_xl_d_tracks_m_/2.0) / (summit_xl_wheel_diameter_ / 2.0);
00440       brw_ref_msg.data = (v_ref_x_ + w_ref_* summit_xl_d_tracks_m_/2.0) / (summit_xl_wheel_diameter_ / 2.0);
00441       flw_ref_msg.data = (v_ref_x_ - w_ref_* summit_xl_d_tracks_m_/2.0) / (summit_xl_wheel_diameter_ / 2.0);
00442       blw_ref_msg.data = (v_ref_x_ - w_ref_* summit_xl_d_tracks_m_/2.0) / (summit_xl_wheel_diameter_ / 2.0);
00443 
00444           ref_vel_frw_.publish( frw_ref_msg );
00445           ref_vel_flw_.publish( flw_ref_msg );
00446           ref_vel_blw_.publish( blw_ref_msg );
00447           ref_vel_brw_.publish( brw_ref_msg );
00448   }
00449 
00450 
00451   // Depending on the robot configuration 
00452   if (active_kinematic_mode_ == MECANUM_STEERING) {
00453 
00454           // Speed references for motor control
00455           // double v_left_mps, v_right_mps;
00456           double v_frw_mps, v_flw_mps, v_blw_mps, v_brw_mps; 
00457           v_frw_mps = joint_state_.velocity[frw_vel_]  * (summit_xl_wheel_diameter_ / 2.0);
00458           v_flw_mps = joint_state_.velocity[flw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00459           v_blw_mps = joint_state_.velocity[blw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00460           v_brw_mps = joint_state_.velocity[brw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00461 
00462           double vx = v_ref_x_;
00463           double vy = v_ref_y_;
00464           double w = w_ref_;
00465           double L = summit_xl_wheelbase_;   
00466           double W = summit_xl_trackwidth_;
00467           
00468       double lab = (SUMMIT_XL_WHEELBASE + SUMMIT_XL_TRACKWIDTH) / 2.0;
00469       double q1 = (v_ref_x_ + v_ref_y_ + lab * w_ref_) / (summit_xl_wheel_diameter_ / 2.0);
00470       double q2 = (v_ref_x_ - v_ref_y_ - lab * w_ref_) / (summit_xl_wheel_diameter_ / 2.0);
00471       double q3 = (v_ref_x_ + v_ref_y_ - lab * w_ref_) / (summit_xl_wheel_diameter_ / 2.0);
00472       double q4 = (v_ref_x_ - v_ref_y_ + lab * w_ref_) / (summit_xl_wheel_diameter_ / 2.0);
00473 
00474       //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);
00475         
00476           // Motor control actions
00477           double limit = 40.0;
00478           
00479           // Axis are not reversed in the omni (swerve) configuration
00480       std_msgs::Float64 frw_ref_vel_msg; 
00481       std_msgs::Float64 flw_ref_vel_msg;
00482       std_msgs::Float64 blw_ref_vel_msg;
00483       std_msgs::Float64 brw_ref_vel_msg;
00484           
00485           frw_ref_vel_msg.data = saturation(q1, -limit, limit);  
00486           flw_ref_vel_msg.data = saturation(q2, -limit, limit);
00487       blw_ref_vel_msg.data = saturation(q3, -limit, limit);
00488           brw_ref_vel_msg.data = saturation(q4, -limit, limit);
00489           
00490           ref_vel_frw_.publish( frw_ref_vel_msg );
00491           ref_vel_flw_.publish( flw_ref_vel_msg );
00492           ref_vel_blw_.publish( blw_ref_vel_msg );
00493           ref_vel_brw_.publish( brw_ref_vel_msg );
00494         }
00495           
00496         // Depending on the robot model 
00497         if (robot_model_ == "x_wam") {          
00498                 // Position reference for the scissor mechanism
00499                 static double scissor_ref_pos = 0.0;
00500                 scissor_ref_pos  += (v_ref_z_ / desired_freq_);         
00501         std_msgs::Float64 scissor_ref_pos_msg;
00502         // joint_state_.position[scissor_pos_] not used, just setpoint 
00503         scissor_ref_pos_msg.data = saturation(scissor_ref_pos, 0.0, 0.5); 
00504         ref_pos_scissor_.publish( scissor_ref_pos_msg ); 
00505                 }
00506 
00507      // PTZ 
00508          std_msgs::Float64 pan_ref_pos_msg, tilt_ref_pos_msg;
00509      pan_ref_pos_msg.data = pos_ref_pan_;            //saturation( pos_ref_pan_, 0.0, 0.5); 
00510      ref_pos_pan_.publish( pan_ref_pos_msg );
00511      tilt_ref_pos_msg.data = pos_ref_tilt_;          //saturation( pos_ref_tilt_, 0.0, 0.5); 
00512      ref_pos_tilt_.publish( tilt_ref_pos_msg );
00513 }
00514 
00515 // Update robot odometry depending on kinematic configuration
00516 void UpdateOdometry()
00517 {
00518   // Depending on the robot configuration 
00519 
00520   if (active_kinematic_mode_ == SKID_STEERING) {
00521           
00522       // Compute Velocity (linearSpeedXMps_ computed in control
00523           robot_pose_vx_ = linearSpeedXMps_ *  cos(robot_pose_pa_);
00524       robot_pose_vy_ = linearSpeedXMps_ *  sin(robot_pose_pa_);
00525   }
00526                 
00527   // Depending on the robot configuration 
00528   if (active_kinematic_mode_ == MECANUM_STEERING) {
00529 
00530       // Linear speed of each wheel
00531           double v1, v2, v3, v4; 
00532           v1 = joint_state_.velocity[frw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00533           v2 = joint_state_.velocity[flw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00534           v3 = joint_state_.velocity[blw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00535           v4 = joint_state_.velocity[brw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00536 
00537       double lab = (SUMMIT_XL_WHEELBASE + SUMMIT_XL_TRACKWIDTH) / 2.0;
00538       
00539       double vx = (1 / 4.0) * (v1 + v2 + v3 + v4);
00540       double vy = (1 / 4.0) * (v1 - v2 + v3 - v4);
00541       double wr = (1 / (4.0 * lab)) * (v1 - v2 - v3 + v4);
00542 
00543       robot_pose_vx_ = vx;
00544       robot_pose_vy_ = vy;                
00545     }
00546       
00547   // Compute Position
00548   double fSamplePeriod = 1.0 / desired_freq_;
00549   //  robot_pose_pa_ += ang_vel_z_ * fSamplePeriod;  // this velocity comes from IMU callback
00550   
00551   // read the orientation directly from the IMU
00552   double roll, pitch, yaw;
00553   tf::Matrix3x3(tf::Quaternion(orientation_x_, orientation_y_, orientation_z_, orientation_w_)).getRPY(roll, pitch, yaw);
00554   robot_pose_pa_ = yaw;
00555   robot_pose_px_ += robot_pose_vx_ * fSamplePeriod;
00556   robot_pose_py_ += robot_pose_vy_ * fSamplePeriod;
00557   // ROS_INFO("Odom estimated x=%5.2f  y=%5.2f a=%5.2f", robot_pose_px_, robot_pose_py_, robot_pose_pa_);
00558 }
00559 
00560 // Publish robot odometry tf and topic depending 
00561 void PublishOdometry()
00562 {
00563         ros::Time current_time = ros::Time::now();
00564         
00565     //first, we'll publish the transform over tf
00566     geometry_msgs::TransformStamped odom_trans;
00567     odom_trans.header.stamp = current_time;
00568     odom_trans.header.frame_id = "odom";
00569     odom_trans.child_frame_id = "base_footprint";
00570 
00571     odom_trans.transform.translation.x = robot_pose_px_;
00572     odom_trans.transform.translation.y = robot_pose_py_;
00573     odom_trans.transform.translation.z = 0.0;
00574     odom_trans.transform.rotation.x = orientation_x_;
00575         odom_trans.transform.rotation.y = orientation_y_;
00576         odom_trans.transform.rotation.z = orientation_z_;
00577         odom_trans.transform.rotation.w = orientation_w_;
00578         
00579     // send the transform over /tf
00580         // activate / deactivate with param
00581         // this tf in needed when not using robot_pose_ekf
00582     if (publish_odom_tf_) {
00583         odom_broadcaster.sendTransform(odom_trans);
00584     }
00585         
00586     //next, we'll publish the odometry message over ROS
00587     nav_msgs::Odometry odom;
00588     odom.header.stamp = current_time;
00589     odom.header.frame_id = "odom";
00590 
00591     //set the position
00592         // Position
00593     odom.pose.pose.position.x = robot_pose_px_;
00594     odom.pose.pose.position.y = robot_pose_py_;
00595     odom.pose.pose.position.z = 0.0;
00596         // Orientation
00597     odom.pose.pose.orientation.x = orientation_x_;
00598         odom.pose.pose.orientation.y = orientation_y_;
00599         odom.pose.pose.orientation.z = orientation_z_;
00600         odom.pose.pose.orientation.w = orientation_w_;
00601         // Pose covariance
00602     for(int i = 0; i < 6; i++)
00603                 odom.pose.covariance[i*6+i] = 0.001;  // test 0.001
00604     odom.twist.covariance[35] = 0.03;
00605 
00606     //set the velocity
00607     odom.child_frame_id = "base_footprint";
00608         // Linear velocities
00609 //    odom.twist.twist.linear.x = robot_pose_vx_;
00610 //    odom.twist.twist.linear.y = robot_pose_vy_;
00611     if (active_kinematic_mode_ == SKID_STEERING) {
00612         odom.twist.twist.linear.x = linearSpeedXMps_; 
00613         odom.twist.twist.linear.y = 0;
00614     }
00615     else if (active_kinematic_mode_ == MECANUM_STEERING) {
00616         odom.twist.twist.linear.x = robot_pose_vx_;
00617         odom.twist.twist.linear.y = robot_pose_vy_;
00618     }
00619 
00620         odom.twist.twist.linear.z = 0.0;
00621         // Angular velocities
00622         odom.twist.twist.angular.x = ang_vel_x_;
00623         odom.twist.twist.angular.y = ang_vel_y_;
00624     odom.twist.twist.angular.z = ang_vel_z_;
00625         // Twist covariance
00626         for(int i = 0; i < 6; i++)
00627                 odom.twist.covariance[6*i+i] = 0.001; // test 0.001
00628     odom.twist.covariance[35] = 0.03;
00629 
00630     //publish the message
00631     if (publish_odom_msg_)
00632         odom_pub_.publish(odom);
00633 
00634 //    gazebo_msgs::ModelState model_state;
00635 //    model_state.model_name = "summit_xl"; //TODO read from params
00636 //    model_state.pose = odom.pose.pose;
00637 //    model_state.twist = odom.twist.twist;
00638 //    gazebo_set_model_.publish(model_state);
00639 }
00640 
00642 void stopping()
00643 {}
00644 
00645 
00646 /*
00647  *      \brief Checks that the robot is receiving at a correct frequency the command messages. Diagnostics
00648  *
00649  */
00650 void check_command_subscriber(diagnostic_updater::DiagnosticStatusWrapper &stat)
00651 {
00652         ros::Time current_time = ros::Time::now();
00653 
00654         double diff = (current_time - last_command_time_).toSec();
00655 
00656         if(diff > 1.0){
00657                 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Topic is not receiving commands");
00658                 //ROS_INFO("check_command_subscriber: %lf seconds without commands", diff);
00659                 // TODO: Set Speed References to 0
00660         }else{
00661                 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Topic receiving commands");
00662         }
00663 }
00664 
00665 
00666 // Set the base velocity command
00667 void setCommand(const geometry_msgs::Twist &cmd_vel)
00668 {   
00669    v_ref_x_ = saturation(cmd_vel.linear.x, -10.0, 10.0);
00670    v_ref_y_ = saturation(cmd_vel.linear.y, -10.0, 10.0);        
00671    w_ref_ = saturation(cmd_vel.angular.z, -10.0, 10.0); // -10.0 10.0
00672    v_ref_z_ = saturation(cmd_vel.linear.z, -10.0, 10.0);
00673 }
00674 
00675 // CALLBACKS
00676 // Service SetMode
00677 bool srvCallback_SetMode(robotnik_msgs::set_mode::Request& request, robotnik_msgs::set_mode::Response& response)
00678 {
00679   // Check if the selected mode is available or not
00680   // 1 - SKID STEERING
00681   // 2 - OMNIDRIVE 
00682   // (3 - SWERVE)
00683 
00684   ROS_INFO("SummitXLControllerClass::srvCallback_SetMode request.mode= %d", request.mode);
00685   if (request.mode == 1) {
00686         active_kinematic_mode_ = request.mode;
00687         return true;
00688         }
00689   if (request.mode == 2) {
00690         if (kinematic_modes_ == 2) {
00691                 active_kinematic_mode_ = request.mode;
00692                 return true;    
00693                 }
00694         else return false;
00695         }
00696   return false;
00697 }
00698 
00699 // Service GetMode
00700 bool srvCallback_GetMode(robotnik_msgs::get_mode::Request& request, robotnik_msgs::get_mode::Response& response)
00701 {
00702   response.mode = active_kinematic_mode_;
00703   return true;  
00704 }
00705 
00706 
00707 // Service SetOdometry 
00708 bool srvCallback_SetOdometry(robotnik_msgs::set_odometry::Request &request, robotnik_msgs::set_odometry::Response &response )
00709 {
00710         ROS_INFO("summit_xl_odometry::set_odometry: request -> x = %f, y = %f, a = %f", request.x, request.y, request.orientation);
00711         robot_pose_px_ = request.x;
00712         robot_pose_py_ = request.y;
00713         robot_pose_pa_ = request.orientation;
00714 
00715         response.ret = true;
00716         return true;
00717 }
00718 
00719 
00720 // Topic command
00721 void jointStateCallback(const sensor_msgs::JointStateConstPtr& msg)
00722 {       
00723   joint_state_ = *msg;
00724   read_state_ = true;
00725 }
00726 
00727 // Topic command
00728 void commandCallback(const geometry_msgs::TwistConstPtr& msg)
00729 {
00730   // Safety check
00731   last_command_time_ = ros::Time::now();
00732   subs_command_freq->tick();                    // For diagnostics
00733 
00734   base_vel_msg_ = *msg;
00735   this->setCommand(base_vel_msg_);
00736 }
00737 
00738 // Topic ptz command
00739 void command_ptzCallback(const robotnik_msgs::ptzConstPtr& msg)
00740 {
00741   pos_ref_pan_ += msg->pan / 180.0 * PI;
00742   pos_ref_tilt_ += msg->tilt / 180.0 * PI;
00743 }
00744 
00745 // Imu callback
00746 void imuCallback( const sensor_msgs::Imu& imu_msg){
00747 
00748         orientation_x_ = imu_msg.orientation.x;
00749         orientation_y_ = imu_msg.orientation.y;
00750         orientation_z_ = imu_msg.orientation.z;
00751         orientation_w_ = imu_msg.orientation.w;
00752 
00753         ang_vel_x_ = imu_msg.angular_velocity.x;
00754         ang_vel_y_ = imu_msg.angular_velocity.y;
00755         ang_vel_z_ = imu_msg.angular_velocity.z;
00756 
00757         lin_acc_x_ = imu_msg.linear_acceleration.x;
00758         lin_acc_y_ = imu_msg.linear_acceleration.y;
00759         lin_acc_z_ = imu_msg.linear_acceleration.z;
00760 }
00761 
00762 double saturation(double u, double min, double max)
00763 {
00764  if (u>max) u=max;
00765  if (u<min) u=min;
00766  return u; 
00767 }
00768 
00769 double radnorm( double value ) 
00770 {
00771   while (value > PI) value -= PI;
00772   while (value < -PI) value += PI;
00773   return value;
00774 }
00775 
00776 double radnorm2( double value ) 
00777 {
00778   while (value > 2.0*PI) value -= 2.0*PI;
00779   while (value < -2.0*PI) value += 2.0*PI;
00780   return value;
00781 }
00782 
00783 bool spin()
00784 {
00785     ROS_INFO("summit_xl_robot_control::spin()");
00786     ros::Rate r(desired_freq_);  // 50.0 
00787 
00788     while (!ros::isShuttingDown()) // Using ros::isShuttingDown to avoid restarting the node during a shutdown.
00789     {
00790       if (starting() == 0)
00791       {
00792             while(ros::ok() && node_handle_.ok()) {
00793           UpdateControl();
00794           UpdateOdometry();
00795           PublishOdometry();
00796           diagnostic_.update();
00797           ros::spinOnce();
00798               r.sleep();
00799           }
00800               ROS_INFO("END OF ros::ok() !!!");
00801       } else {
00802        // No need for diagnostic here since a broadcast occurs in start
00803        // when there is an error.
00804        usleep(1000000);
00805        ros::spinOnce();
00806       }
00807    }
00808 
00809    ROS_INFO("summit_xl_robot_control::spin() - end");
00810    return true;
00811 }
00812 
00813 }; // Class SummitXLControllerClass
00814 
00815 int main(int argc, char** argv)
00816 {
00817         ros::init(argc, argv, "summit_xl_robot_control");
00818 
00819         ros::NodeHandle n;              
00820         SummitXLControllerClass sxlrc(n);
00821 
00822         
00823         // ros::ServiceServer service = n.advertiseService("set_odometry", &summit_xl_node::set_odometry, &sxlc);
00824     sxlrc.spin();
00825 
00826         return (0);
00827 
00828         
00829 }
00830 


summit_xl_robot_control
Author(s): Roberto Guzmán , Román Navarro , Jorge Ariño
autogenerated on Sat Jun 8 2019 20:28:59