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 
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   // Joint states published by the joint_state_controller of the Controller Manager
00102   ros::Subscriber joint_state_sub_;
00103 
00104   // High level robot command
00105   ros::Subscriber cmd_sub_;
00106         
00107   // High level robot command
00108   ros::Subscriber ptz_sub_;
00109 
00110   //ros::Subscriber gyro_sub_;
00111 
00112   // Services
00113   ros::ServiceServer srv_SetOdometry_;
00114   ros::ServiceServer srv_SetMode_;
00115   ros::ServiceServer srv_GetMode_;
00116   
00117   // Topics - skid - velocity
00118   std::string frw_vel_topic_;
00119   std::string flw_vel_topic_;
00120   std::string brw_vel_topic_;
00121   std::string blw_vel_topic_;
00122   
00123   // Joint names - skid - velocity 
00124   std::string joint_front_right_wheel;
00125   std::string joint_front_left_wheel;
00126   std::string joint_back_left_wheel;
00127   std::string joint_back_right_wheel;
00128 
00129   // Topics - swerve - position
00130   std::string frw_pos_topic_;
00131   std::string flw_pos_topic_;
00132   std::string brw_pos_topic_;
00133   std::string blw_pos_topic_;
00134     
00135   // Joint names - swerve - position
00136   std::string joint_front_right_steer;
00137   std::string joint_front_left_steer;
00138   std::string joint_back_left_steer;
00139   std::string joint_back_right_steer;
00140 
00141   // Topic - scissor - position
00142   std::string scissor_pos_topic_;
00143   
00144   // Topic - odom
00145   std::string odom_topic_;
00146 
00147   // Joint names - ptz - position
00148   std::string joint_camera_pan;
00149   std::string joint_camera_tilt;
00150 
00151   // Topics - ptz
00152   std::string pan_pos_topic_;
00153   std::string tilt_pos_topic_;
00154     
00155   // Joint name - scissor mechanism
00156   std::string scissor_prismatic_joint;
00157 
00158   // Selected operation mode
00159   int kinematic_modes_;   
00160   int active_kinematic_mode_;
00161 
00162   // Indexes to joint_states
00163   int frw_vel_, flw_vel_, blw_vel_, brw_vel_;
00164   int frw_pos_, flw_pos_, blw_pos_, brw_pos_;
00165   int scissor_pos_;
00166   int pan_pos_, tilt_pos_;
00167 
00168 
00169   // Robot Speeds
00170   double linearSpeedXMps_;
00171   double linearSpeedYMps_;
00172   double angularSpeedRads_;
00173 
00174   // Robot Positions
00175   double robot_pose_px_;
00176   double robot_pose_py_;
00177   double robot_pose_pa_;
00178   double robot_pose_vx_;
00179   double robot_pose_vy_;
00180   
00181   // Robot Joint States
00182   sensor_msgs::JointState joint_state_;
00183   
00184   // Command reference
00185   geometry_msgs::Twist base_vel_msg_;
00186 
00187   // External speed references
00188   double v_ref_x_;
00189   double v_ref_y_;
00190   double w_ref_;
00191   double v_ref_z_;
00192   double pos_ref_pan_;
00193   double pos_ref_tilt_;
00194   
00195   // Flag to indicate if joint_state has been read
00196   bool read_state_; 
00197   
00198   // Robot configuration parameters 
00199   double summit_xl_wheel_diameter_; 
00200   double summit_xl_d_tracks_m_;
00201   double summit_xl_wheelbase_;
00202   double summit_xl_trackwidth_;
00203 
00204   // IMU values
00205   double ang_vel_x_;
00206   double ang_vel_y_;
00207   double ang_vel_z_;
00208 
00209   double lin_acc_x_;
00210   double lin_acc_y_;
00211   double lin_acc_z_;
00212 
00213   double orientation_x_;
00214   double orientation_y_;
00215   double orientation_z_;
00216   double orientation_w_;
00217 
00218   // Parameter that defines if odom tf is published or not
00219   bool publish_odom_tf_;
00220 
00221   ros::Subscriber imu_sub_; 
00222   
00223   // Publisher for odom topic
00224   ros::Publisher odom_pub_; 
00225 
00226   // Broadcaster for odom tf  
00227   tf::TransformBroadcaster odom_broadcaster;
00228 
00229 
00233 SummitXLControllerClass(ros::NodeHandle h) : diagnostic_(),
00234   node_handle_(h), private_node_handle_("~"), 
00235   desired_freq_(100),
00236   freq_diag_(diagnostic_updater::FrequencyStatusParam(&desired_freq_, &desired_freq_, 0.05)   ),
00237   command_freq_("Command frequency check", boost::bind(&SummitXLControllerClass::check_command_subscriber, this, _1))
00238   {
00239 
00240   // /summit_xl/joint_blw_velocity_controller/joint
00241   ROS_INFO("summit_xl_robot_control_node - Init ");
00242 
00243   // 4-Axis Skid Steer Rover
00244   // 8-Axis Omni-drive as 4-Axis Mecanum drive
00245   kinematic_modes_ = 1;  
00246   
00247   ros::NodeHandle summit_xl_robot_control_node_handle(node_handle_, "summit_xl_robot_control");
00248 
00249   // Get robot model from the parameters
00250   if (!private_node_handle_.getParam("model", robot_model_)) {
00251           ROS_ERROR("Robot model not defined.");
00252           exit(-1);
00253           }
00254   else ROS_INFO("Robot Model : %s", robot_model_.c_str());
00255 
00256   // Skid configuration - topics
00257   private_node_handle_.param<std::string>("frw_vel_topic", frw_vel_topic_, "/summit_xl/joint_frw_velocity_controller/command");
00258   private_node_handle_.param<std::string>("flw_vel_topic", flw_vel_topic_, "/summit_xl/joint_flw_velocity_controller/command");
00259   private_node_handle_.param<std::string>("blw_vel_topic", blw_vel_topic_, "/summit_xl/joint_blw_velocity_controller/command");
00260   private_node_handle_.param<std::string>("brw_vel_topic", brw_vel_topic_, "/summit_xl/joint_brw_velocity_controller/command");
00261 
00262   // Skid configuration - Joint names 
00263   private_node_handle_.param<std::string>("joint_front_right_wheel", joint_front_right_wheel, "joint_front_right_wheel");
00264   private_node_handle_.param<std::string>("joint_front_left_wheel", joint_front_left_wheel, "joint_front_left_wheel");
00265   private_node_handle_.param<std::string>("joint_back_left_wheel", joint_back_left_wheel, "joint_back_left_wheel");
00266   private_node_handle_.param<std::string>("joint_back_right_wheel", joint_back_right_wheel, "joint_back_right_wheel");
00267 
00268   // Omni configuration - topics
00269   if ((robot_model_=="summit_xl_omni") || (robot_model_=="x_wam")) {
00270         kinematic_modes_ = 2;
00271     private_node_handle_.param<std::string>("frw_pos_topic", frw_pos_topic_, "/summit_xl/joint_frw_velocity_controller/command");
00272     private_node_handle_.param<std::string>("flw_pos_topic", flw_pos_topic_, "/summit_xl/joint_flw_velocity_controller/command");
00273     private_node_handle_.param<std::string>("blw_pos_topic", blw_pos_topic_, "/summit_xl/joint_blw_velocity_controller/command");
00274     private_node_handle_.param<std::string>("brw_pos_topic", brw_pos_topic_, "/summit_xl/joint_brw_velocity_controller/command");
00275 
00276     private_node_handle_.param<std::string>("joint_front_right_steer", joint_front_right_steer, "joint_front_right_steer");
00277     private_node_handle_.param<std::string>("joint_front_left_steer", joint_front_left_steer, "joint_front_left_steer");
00278     private_node_handle_.param<std::string>("joint_back_left_steer", joint_back_left_steer, "joint_back_left_steer");
00279     private_node_handle_.param<std::string>("joint_back_right_steer", joint_back_right_steer, "joint_back_right_steer");
00280 
00281     if (!private_node_handle_.getParam("summit_xl_wheelbase", summit_xl_wheelbase_))
00282         summit_xl_wheelbase_ = SUMMIT_XL_WHEELBASE;
00283     if (!private_node_handle_.getParam("summit_xl_trackwidth", summit_xl_trackwidth_))
00284         summit_xl_trackwidth_ = SUMMIT_XL_TRACKWIDTH;
00285 
00286     // x-wam only configuration
00287     if (robot_model_=="x_wam") {
00288       private_node_handle_.param<std::string>("scissor_pos_topic", scissor_pos_topic_, "/summit_xl/joint_scissor_position_controller/command");         
00289           private_node_handle_.param<std::string>("scissor_prismatic_joint", scissor_prismatic_joint, "scissor_prismatic_joint");
00290       } 
00291     }
00292 
00293   // PTZ topics
00294   private_node_handle_.param<std::string>("pan_pos_topic", pan_pos_topic_, "/summit_xl/joint_pan_position_controller/command");
00295   private_node_handle_.param<std::string>("tilt_pos_topic", tilt_pos_topic_, "/summit_xl/joint_tilt_position_controller/command");
00296   private_node_handle_.param<std::string>("joint_camera_pan", joint_camera_pan, "joint_camera_pan");
00297   private_node_handle_.param<std::string>("joint_camera_tilt", joint_camera_tilt, "joint_camera_tilt");
00298 
00299   // Odom topic
00300   private_node_handle_.param<std::string>("odom_topic", odom_topic_, "/summit_xl/odom_robot_control");
00301   
00302   // Robot parameters
00303   if (!private_node_handle_.getParam("summit_xl_wheel_diameter", summit_xl_wheel_diameter_))
00304     summit_xl_wheel_diameter_ = SUMMIT_XL_WHEEL_DIAMETER;
00305   if (!private_node_handle_.getParam("summit_xl_d_tracks_m", summit_xl_d_tracks_m_))
00306     summit_xl_d_tracks_m_ = SUMMIT_XL_D_TRACKS_M;
00307   ROS_INFO("summit_xl_wheel_diameter_ = %5.2f", summit_xl_wheel_diameter_);
00308   ROS_INFO("summit_xl_d_tracks_m_ = %5.2f", summit_xl_d_tracks_m_);
00309 
00310   private_node_handle_.param("publish_odom_tf", publish_odom_tf_, true);
00311   if (publish_odom_tf_) ROS_INFO("PUBLISHING odom->base_footprin tf");
00312   else ROS_INFO("NOT PUBLISHING odom->base_footprint tf");
00313   
00314   // Robot Speeds
00315   linearSpeedXMps_   = 0.0;
00316   linearSpeedYMps_   = 0.0;
00317   angularSpeedRads_  = 0.0;
00318 
00319   // Robot Positions
00320   robot_pose_px_ = 0.0;
00321   robot_pose_py_ = 0.0;
00322   robot_pose_pa_ = 0.0;
00323   robot_pose_vx_ = 0.0;
00324   robot_pose_vy_ = 0.0;
00325 
00326   // External speed references
00327   v_ref_x_ = 0.0;
00328   v_ref_y_ = 0.0;
00329   w_ref_ = 0.0;
00330   v_ref_z_ = 0.0;
00331   pos_ref_pan_ = 0.0;
00332   pos_ref_tilt_= 0.0;
00333 
00334   // Imu variables
00335   ang_vel_x_ = 0.0; ang_vel_y_ = 0.0; ang_vel_z_ = 0.0;
00336   lin_acc_x_ = 0.0; lin_acc_y_ = 0.0; lin_acc_z_ = 0.0;
00337   orientation_x_ = 0.0; orientation_y_ = 0.0; orientation_z_ = 0.0; orientation_w_ = 0.0;
00338 
00339   // Active kinematic mode
00340   active_kinematic_mode_ = SKID_STEERING;
00341 
00342   // Advertise services
00343   srv_SetMode_ = summit_xl_robot_control_node_handle.advertiseService("set_mode", &SummitXLControllerClass::srvCallback_SetMode, this);
00344   srv_GetMode_ = summit_xl_robot_control_node_handle.advertiseService("get_mode", &SummitXLControllerClass::srvCallback_GetMode, this);
00345   srv_SetOdometry_ = summit_xl_robot_control_node_handle.advertiseService("set_odometry",  &SummitXLControllerClass::srvCallback_SetOdometry, this);
00346 
00347   // Subscribe to joint states topic
00348   joint_state_sub_ = summit_xl_robot_control_node_handle.subscribe<sensor_msgs::JointState>("/summit_xl/joint_states", 1, &SummitXLControllerClass::jointStateCallback, this);
00349 
00350   // Subscribe to imu data
00351   // imu_sub_ = summit_xl_robot_control_node_handle.subscribe("/summit_xl/imu_data", 1, &SummitXLControllerClass::imuCallback, this);
00352   imu_sub_ = summit_xl_robot_control_node_handle.subscribe("/imu_data", 1, &SummitXLControllerClass::imuCallback, this);
00353 
00354 
00355   // Adevertise reference topics for the controllers 
00356   ref_vel_frw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( frw_vel_topic_, 50);
00357   ref_vel_flw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( flw_vel_topic_, 50);
00358   ref_vel_blw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( blw_vel_topic_, 50);
00359   ref_vel_brw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( brw_vel_topic_, 50);
00360   
00361   if ((robot_model_=="summit_xl_omni")||(robot_model_=="x_wam")) {
00362           ref_pos_frw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( frw_pos_topic_, 50);
00363           ref_pos_flw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( flw_pos_topic_, 50);
00364           ref_pos_blw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( blw_pos_topic_, 50);   
00365           ref_pos_brw_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( brw_pos_topic_, 50);
00366   
00367           if (robot_model_=="x_wam")
00368              ref_pos_scissor_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( scissor_pos_topic_, 50);           
00369           }
00370           
00371   ref_pos_pan_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( pan_pos_topic_, 50);
00372   ref_pos_tilt_ = summit_xl_robot_control_node_handle.advertise<std_msgs::Float64>( tilt_pos_topic_, 50);
00373 
00374   // Subscribe to command topic
00375   cmd_sub_ = summit_xl_robot_control_node_handle.subscribe<geometry_msgs::Twist>("/summit_xl/robot_control/command", 1, &SummitXLControllerClass::commandCallback, this);
00376 
00377   // Subscribe to ptz command topic
00378   ptz_sub_ = summit_xl_robot_control_node_handle.subscribe<robotnik_msgs::ptz>("/summit_xl/robot_control/command_ptz", 1, &SummitXLControllerClass::command_ptzCallback, this);
00379   // /summit_xl_robot_control/command_ptz
00380   
00381   // Publish odometry 
00382   odom_pub_ = summit_xl_robot_control_node_handle.advertise<nav_msgs::Odometry>(odom_topic_, 1000);
00383 
00384   // Component frequency diagnostics
00385   diagnostic_.setHardwareID("summit_xl_robot_control - simulation");
00386   diagnostic_.add( freq_diag_ );
00387   diagnostic_.add( command_freq_ );
00388     
00389   // Topics freq control 
00390   // For /summit_xl_robot_control/command
00391   double min_freq = SUMMIT_XL_MIN_COMMAND_REC_FREQ; // If you update these values, the
00392   double max_freq = SUMMIT_XL_MAX_COMMAND_REC_FREQ; // HeaderlessTopicDiagnostic will use the new values.
00393   subs_command_freq = new diagnostic_updater::HeaderlessTopicDiagnostic("/summit_xl_robot_control/command", diagnostic_,
00394                             diagnostic_updater::FrequencyStatusParam(&min_freq, &max_freq, 0.1, 10));
00395   subs_command_freq->addTask(&command_freq_); // Adding an additional task to the control
00396   
00397   // Flag to indicate joint_state has been read
00398   read_state_ = false;
00399 }
00400 
00402 int starting()
00403 {
00404 
00405   ROS_INFO("SummitXLControllerClass::starting");
00406 
00407   //name: ['joint_back_left_wheel', 'joint_back_right_wheel', 'joint_front_left_wheel', 'joint_front_right_wheel']
00408   //position: [-0.04246698357387224, 0.053199274627900195, -0.04246671523622059, 0.03126368464965523]
00409   //velocity: [-0.0006956167983269147, 0.0004581098383479411, -0.0013794952191663358, 0.00045523862784977847]
00410 
00411   // Initialize joint indexes according to joint names 
00412   if (read_state_) {
00413     vector<string> joint_names = joint_state_.name;
00414     frw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_right_wheel)) - joint_names.begin();
00415     flw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_left_wheel)) - joint_names.begin();
00416     blw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_left_wheel)) - joint_names.begin();
00417     brw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_right_wheel)) - joint_names.begin();
00418     if ((robot_model_=="summit_xl_omni")||(robot_model_=="x_wam")) {
00419       frw_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_front_right_steer)) - joint_names.begin();
00420       flw_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_front_left_steer)) - joint_names.begin();
00421       blw_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_back_left_steer)) - joint_names.begin();
00422       brw_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_back_right_steer)) - joint_names.begin();
00423           }
00424         if (robot_model_=="x_wam") {
00425           scissor_pos_ = find (joint_names.begin(),joint_names.end(), string(scissor_prismatic_joint)) - joint_names.begin();
00426           }
00427         // For publishing the ptz joint state   
00428         //pan_pos_ = find(joint_names.begin(), joint_names.end(), string(joint_camera_pan)) - joint_names.begin();
00429         //tilt_pos_ = find(joint_names.begin(), joint_names.end(), string(joint_camera_tilt)) - joint_names.begin();
00430     return 0;
00431     }
00432   else return -1;
00433 }
00434 
00435 
00437 void UpdateControl()
00438 {
00439   // Depending on the robot configuration 
00440   if (active_kinematic_mode_ == SKID_STEERING) {
00441 
00442           double v_left_mps, v_right_mps;
00443 
00444           // Calculate its own velocities for realize the motor control 
00445           v_left_mps = ((joint_state_.velocity[blw_vel_] + joint_state_.velocity[flw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0);
00446           v_right_mps = -((joint_state_.velocity[brw_vel_] + joint_state_.velocity[frw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0); 
00447           // sign according to urdf (if wheel model is not symetric, should be inverted)
00448 
00449           linearSpeedXMps_ = (v_right_mps + v_left_mps) / 2.0;                       // m/s
00450           angularSpeedRads_ = (v_right_mps - v_left_mps) / summit_xl_d_tracks_m_;    // rad/s
00451 
00452           //ROS_INFO("vleft=%5.2f   vright=%5.2f    linearSpeedXMps=%5.2f, linearSpeedYMps=%5.2f, angularSpeedRads=%5.4f", v_left_mps, v_right_mps,
00453                 //      linearSpeedXMps_, linearSpeedYMps_, angularSpeedRads_); 
00454 
00455           // Current controllers close this loop allowing (v,w) references.
00456           double epv=0.0;
00457           double epw=0.0;
00458           static double epvant =0.0;
00459           static double epwant =0.0;
00460 
00461           // Adjusted for soft indoor office soil
00462           //double kpv=2.5; double kdv=0.0;
00463           //double kpw=2.5;  double kdw=0.0;
00464           // 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!!!
00465           double kpv=2.5; double kdv=0.0;
00466           double kpw=25.0; double kdw=15.0;
00467 
00468           // State feedback error
00469           epv = v_ref_x_ - linearSpeedXMps_;
00470           epw = w_ref_ - angularSpeedRads_;
00471           // ROS_INFO("v_ref_x_=%5.2f, linearSpeedXMps_=%5.2f w_ref_=%5.2f angularSpeedRads_=%5.2f", v_ref_x_, linearSpeedXMps_, w_ref_, angularSpeedRads_);
00472 
00473           // Compute state control actions
00474           double uv= kpv * epv + kdv * (epv - epvant);
00475           double uw= kpw * epw + kdw * (epw - epwant);
00476           epvant = epv;
00477           epwant = epw;
00478 
00479           // Inverse kinematics
00480           double dUl = uv - 0.5 * summit_xl_d_tracks_m_ * uw;
00481           // sign according to urdf (if wheel model is not symetric, should be inverted)
00482           double dUr = -(uv + 0.5 * summit_xl_d_tracks_m_ * uw);  
00483 
00484           // Motor control actions
00485           double limit = 40.0;
00486           
00487           //ROS_INFO("epv=%5.2f, epw=%5.2f ***  dUl=%5.2f  dUr=%5.2f", epv, epw, dUl, dUr);
00488 
00489           // Axis are not reversed in the omni (swerve) configuration
00490       std_msgs::Float64 frw_ref_msg; 
00491       std_msgs::Float64 flw_ref_msg;
00492       std_msgs::Float64 blw_ref_msg;
00493       std_msgs::Float64 brw_ref_msg;
00494           
00495       double k1 = 0.5; 
00496           frw_ref_msg.data = saturation( k1 * dUr, -limit, limit);  
00497           flw_ref_msg.data = saturation( k1 * dUl, -limit, limit);
00498       blw_ref_msg.data = saturation( k1 * dUl, -limit, limit);
00499           brw_ref_msg.data = saturation( k1 * dUr, -limit, limit);
00500           
00501           ref_vel_frw_.publish( frw_ref_msg );
00502           ref_vel_flw_.publish( flw_ref_msg );
00503           ref_vel_blw_.publish( blw_ref_msg );
00504           ref_vel_brw_.publish( brw_ref_msg );
00505           }
00506 
00507 
00508   // Depending on the robot configuration 
00509   if (active_kinematic_mode_ == MECANUM_STEERING) {
00510 
00511           // Speed references for motor control
00512           // double v_left_mps, v_right_mps;
00513           double v_frw_mps, v_flw_mps, v_blw_mps, v_brw_mps; 
00514           v_frw_mps = joint_state_.velocity[frw_vel_]  * (summit_xl_wheel_diameter_ / 2.0);
00515           v_flw_mps = joint_state_.velocity[flw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00516           v_blw_mps = joint_state_.velocity[blw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00517           v_brw_mps = joint_state_.velocity[brw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00518 
00519           double vx = v_ref_x_;
00520           double vy = v_ref_y_;
00521           double w = w_ref_;
00522           double L = summit_xl_wheelbase_;   
00523           double W = summit_xl_trackwidth_;
00524           
00525 
00526           double x1 = L/2.0; double y1 = - W/2.0;
00527           double wx1 = v_ref_x_ - w_ref_ * y1;
00528           double wy1 = v_ref_y_ + w_ref_ * x1;
00529           double q1 = -sqrt( wx1*wx1 + wy1*wy1 );
00530           double a1 = radnorm( atan2( wy1, wx1 ) );
00531           double x2 = L/2.0; double y2 = W/2.0;
00532           double wx2 = v_ref_x_ - w_ref_ * y2;
00533           double wy2 = v_ref_y_ + w_ref_ * x2;
00534           double q2 = sqrt( wx2*wx2 + wy2*wy2 );
00535           double a2 = radnorm( atan2( wy2, wx2 ) );
00536           double x3 = -L/2.0; double y3 = W/2.0;
00537           double wx3 = v_ref_x_ - w_ref_ * y3;
00538           double wy3 = v_ref_y_ + w_ref_ * x3;
00539           double q3 = sqrt( wx3*wx3 + wy3*wy3 );
00540           double a3 = radnorm( atan2( wy3, wx3 ) );
00541           double x4 = -L/2.0; double y4 = -W/2.0;
00542           double wx4 = v_ref_x_ - w_ref_ * y4;
00543           double wy4 = v_ref_y_ + w_ref_ * x4;
00544           double q4 = -sqrt( wx4*wx4 + wy4*wy4 );
00545           double a4 = radnorm( atan2( wy4, wx4 ) );
00546           
00547       //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);
00548         
00549           // Motor control actions
00550           double limit = 40.0;
00551           
00552           // Axis are not reversed in the omni (swerve) configuration
00553       std_msgs::Float64 frw_ref_vel_msg; 
00554       std_msgs::Float64 flw_ref_vel_msg;
00555       std_msgs::Float64 blw_ref_vel_msg;
00556       std_msgs::Float64 brw_ref_vel_msg;
00557           frw_ref_vel_msg.data = saturation(-1.0 * (joint_state_.velocity[frw_vel_] - q1), -limit, limit);  
00558           flw_ref_vel_msg.data = saturation(-1.0 * (joint_state_.velocity[flw_vel_] - q2), -limit, limit);
00559       blw_ref_vel_msg.data = saturation(-1.0 * (joint_state_.velocity[blw_vel_] - q3), -limit, limit);
00560           brw_ref_vel_msg.data = saturation(-1.0 * (joint_state_.velocity[brw_vel_] - q4), -limit, limit);
00561           ref_vel_frw_.publish( frw_ref_vel_msg );
00562           ref_vel_flw_.publish( flw_ref_vel_msg );
00563           ref_vel_blw_.publish( blw_ref_vel_msg );
00564           ref_vel_brw_.publish( brw_ref_vel_msg );
00565           std_msgs::Float64 frw_ref_pos_msg; 
00566       std_msgs::Float64 flw_ref_pos_msg;
00567       std_msgs::Float64 blw_ref_pos_msg;
00568       std_msgs::Float64 brw_ref_pos_msg;
00569           frw_ref_pos_msg.data = a1; 
00570           flw_ref_pos_msg.data = a2; 
00571           blw_ref_pos_msg.data = a3; 
00572           brw_ref_pos_msg.data = a4;
00573           
00574           ref_pos_frw_.publish( frw_ref_pos_msg);
00575           ref_pos_flw_.publish( flw_ref_pos_msg);
00576           ref_pos_blw_.publish( blw_ref_pos_msg);
00577           ref_pos_brw_.publish( brw_ref_pos_msg);
00578           
00579           }
00580           
00581         // Depending on the robot model 
00582         if (robot_model_ == "x_wam") {          
00583                 // Position reference for the scissor mechanism
00584                 static double scissor_ref_pos = 0.0;
00585                 scissor_ref_pos  += (v_ref_z_ / desired_freq_);         
00586         std_msgs::Float64 scissor_ref_pos_msg;
00587         // joint_state_.position[scissor_pos_] not used, just setpoint 
00588         scissor_ref_pos_msg.data = saturation(scissor_ref_pos, 0.0, 0.5); 
00589         ref_pos_scissor_.publish( scissor_ref_pos_msg ); 
00590                 }
00591 
00592      // PTZ 
00593          std_msgs::Float64 pan_ref_pos_msg, tilt_ref_pos_msg;
00594      pan_ref_pos_msg.data = pos_ref_pan_;            //saturation( pos_ref_pan_, 0.0, 0.5); 
00595      ref_pos_pan_.publish( pan_ref_pos_msg );
00596      tilt_ref_pos_msg.data = pos_ref_tilt_;          //saturation( pos_ref_tilt_, 0.0, 0.5); 
00597      ref_pos_tilt_.publish( tilt_ref_pos_msg );
00598 }
00599 
00600 // Update robot odometry depending on kinematic configuration
00601 void UpdateOdometry()
00602 {
00603   // Depending on the robot configuration 
00604   if (active_kinematic_mode_ == SKID_STEERING) {
00605           
00606       // Compute Velocity (linearSpeedXMps_ computed in control
00607           robot_pose_vx_ = linearSpeedXMps_ *  cos(robot_pose_pa_);
00608       robot_pose_vy_ = linearSpeedXMps_ *  sin(robot_pose_pa_);
00609       }
00610                 
00611   // Depending on the robot configuration 
00612   if (active_kinematic_mode_ == MECANUM_STEERING) {
00613 
00614       // Linear speed of each wheel
00615           double v1, v2, v3, v4; 
00616           v1 = joint_state_.velocity[frw_vel_]  * (summit_xl_wheel_diameter_ / 2.0);
00617           v2 = joint_state_.velocity[flw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00618           v3 = joint_state_.velocity[blw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00619           v4 = joint_state_.velocity[brw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
00620       double a1, a2, a3, a4;
00621       a1 = radnorm2( joint_state_.position[frw_pos_] );
00622       a2 = radnorm2( joint_state_.position[flw_pos_] );
00623       a3 = radnorm2( joint_state_.position[blw_pos_] );
00624       a4 = radnorm2( joint_state_.position[brw_pos_] );
00625       double v1x = -v1 * cos( a1 ); double v1y = -v1 * sin( a1 );
00626       double v2x = v2 * cos( a2 ); double v2y = v2 * sin( a2 );
00627       double v3x = v3 * cos( a3 ); double v3y = v3 * sin( a3 );
00628       double v4x = -v4 * cos( a4 ); double v4y = -v4 * sin( a4 );
00629       double C = (v4y + v1y) / 2.0;
00630       double B = (v2x + v1x) / 2.0;
00631       double D = (v2y + v3y) / 2.0;
00632       double A = (v3x + v4x) / 2.0;
00633       // double W = ( (B-A)/summit_xl_wheelbase_ ); // + (D-C)/summit_xl_trackwidth_ ) / 2.0;
00634       robot_pose_vx_ = (A+B) / 2.0;
00635       robot_pose_vy_ = (C+D) / 2.0;               
00636       }
00637       
00638       // Compute Position
00639       double fSamplePeriod = 1.0 / desired_freq_;
00640           robot_pose_pa_ += ang_vel_z_ * fSamplePeriod;  // this velocity comes from IMU callback
00641       robot_pose_px_ += robot_pose_vx_ * fSamplePeriod;
00642       robot_pose_py_ += robot_pose_vy_ * fSamplePeriod;
00643       // ROS_INFO("Odom estimated x=%5.2f  y=%5.2f a=%5.2f", robot_pose_px_, robot_pose_py_, robot_pose_pa_);
00644 }
00645 
00646 // Publish robot odometry tf and topic depending 
00647 void PublishOdometry()
00648 {
00649         ros::Time current_time = ros::Time::now();
00650         
00651     //first, we'll publish the transform over tf
00652     geometry_msgs::TransformStamped odom_trans;
00653     odom_trans.header.stamp = current_time;
00654     odom_trans.header.frame_id = "odom";
00655     odom_trans.child_frame_id = "base_footprint";
00656 
00657     odom_trans.transform.translation.x = robot_pose_px_;
00658     odom_trans.transform.translation.y = robot_pose_py_;
00659     odom_trans.transform.translation.z = 0.0;
00660     odom_trans.transform.rotation.x = orientation_x_;
00661         odom_trans.transform.rotation.y = orientation_y_;
00662         odom_trans.transform.rotation.z = orientation_z_;
00663         odom_trans.transform.rotation.w = orientation_w_;
00664         
00665     // send the transform over /tf
00666         // activate / deactivate with param
00667         // this tf in needed when not using robot_pose_ekf
00668     if (publish_odom_tf_) odom_broadcaster.sendTransform(odom_trans);  
00669         
00670     //next, we'll publish the odometry message over ROS
00671     nav_msgs::Odometry odom;
00672     odom.header.stamp = current_time;
00673     odom.header.frame_id = "odom";
00674 
00675     //set the position
00676         // Position
00677     odom.pose.pose.position.x = robot_pose_px_;
00678     odom.pose.pose.position.y = robot_pose_py_;
00679     odom.pose.pose.position.z = 0.0;
00680         // Orientation
00681     odom.pose.pose.orientation.x = orientation_x_;
00682         odom.pose.pose.orientation.y = orientation_y_;
00683         odom.pose.pose.orientation.z = orientation_z_;
00684         odom.pose.pose.orientation.w = orientation_w_;
00685         // Pose covariance
00686     for(int i = 0; i < 6; i++)
00687                 odom.pose.covariance[i*6+i] = 0.1;  // test 0.001
00688 
00689     //set the velocity
00690     odom.child_frame_id = "base_footprint";
00691         // Linear velocities
00692     odom.twist.twist.linear.x = robot_pose_vx_;
00693     odom.twist.twist.linear.y = robot_pose_vy_;
00694         odom.twist.twist.linear.z = 0.0;
00695         // Angular velocities
00696         odom.twist.twist.angular.x = ang_vel_x_;
00697         odom.twist.twist.angular.y = ang_vel_y_;
00698     odom.twist.twist.angular.z = ang_vel_z_;
00699         // Twist covariance
00700         for(int i = 0; i < 6; i++)
00701                 odom.twist.covariance[6*i+i] = 0.1;  // test 0.001
00702 
00703     //publish the message
00704     odom_pub_.publish(odom);
00705 }
00706 
00708 void stopping()
00709 {}
00710 
00711 
00712 /*
00713  *      \brief Checks that the robot is receiving at a correct frequency the command messages. Diagnostics
00714  *
00715  */
00716 void check_command_subscriber(diagnostic_updater::DiagnosticStatusWrapper &stat)
00717 {
00718         ros::Time current_time = ros::Time::now();
00719 
00720         double diff = (current_time - last_command_time_).toSec();
00721 
00722         if(diff > 1.0){
00723                 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Topic is not receiving commands");
00724                 //ROS_INFO("check_command_subscriber: %lf seconds without commands", diff);
00725                 // TODO: Set Speed References to 0
00726         }else{
00727                 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Topic receiving commands");
00728         }
00729 }
00730 
00731 
00732 // Set the base velocity command
00733 void setCommand(const geometry_msgs::Twist &cmd_vel)
00734 {   
00735    v_ref_x_ = saturation(cmd_vel.linear.x, -10.0, 10.0);
00736    v_ref_y_ = saturation(cmd_vel.linear.y, -10.0, 10.0);        
00737    w_ref_ = saturation(cmd_vel.angular.z, -10.0, 10.0); // -10.0 10.0
00738    v_ref_z_ = saturation(cmd_vel.linear.z, -10.0, 10.0);
00739 }
00740 
00741 // CALLBACKS
00742 // Service SetMode
00743 bool srvCallback_SetMode(robotnik_msgs::set_mode::Request& request, robotnik_msgs::set_mode::Response& response)
00744 {
00745   // Check if the selected mode is available or not
00746   // 1 - SKID STEERING
00747   // 2 - OMNIDRIVE 
00748   // (3 - SWERVE)
00749 
00750   ROS_INFO("SummitXLControllerClass::srvCallback_SetMode request.mode= %d", request.mode);
00751   if (request.mode == 1) {
00752         active_kinematic_mode_ = request.mode;
00753         return true;
00754         }
00755   if (request.mode == 2) {
00756         if (kinematic_modes_ == 2) {
00757                 active_kinematic_mode_ = request.mode;
00758                 return true;    
00759                 }
00760         else return false;
00761         }
00762   return false;
00763 }
00764 
00765 // Service GetMode
00766 bool srvCallback_GetMode(robotnik_msgs::get_mode::Request& request, robotnik_msgs::get_mode::Response& response)
00767 {
00768   response.mode = active_kinematic_mode_;
00769   return true;  
00770 }
00771 
00772 
00773 // Service SetOdometry 
00774 bool srvCallback_SetOdometry(robotnik_msgs::set_odometry::Request &request, robotnik_msgs::set_odometry::Response &response )
00775 {
00776         // ROS_INFO("summit_xl_odometry::set_odometry: request -> x = %f, y = %f, a = %f", req.x, req.y, req.orientation);
00777         //robot_pose_px_ = req.x;
00778         //robot_pose_py_ = req.y;
00779         //robot_pose_pa_ = req.orientation;
00780 
00781         response.ret = true;
00782         return true;
00783 }
00784 
00785 
00786 // Topic command
00787 void jointStateCallback(const sensor_msgs::JointStateConstPtr& msg)
00788 {       
00789   joint_state_ = *msg;
00790   read_state_ = true;
00791 }
00792 
00793 // Topic command
00794 void commandCallback(const geometry_msgs::TwistConstPtr& msg)
00795 {
00796   // Safety check
00797   last_command_time_ = ros::Time::now();
00798   subs_command_freq->tick();                    // For diagnostics
00799 
00800   base_vel_msg_ = *msg;
00801   this->setCommand(base_vel_msg_);
00802 }
00803 
00804 // Topic ptz command
00805 void command_ptzCallback(const robotnik_msgs::ptzConstPtr& msg)
00806 {
00807   pos_ref_pan_ += msg->pan / 180.0 * PI;
00808   pos_ref_tilt_ += msg->tilt / 180.0 * PI;
00809 }
00810 
00811 // Imu callback
00812 void imuCallback( const sensor_msgs::Imu& imu_msg){
00813 
00814         orientation_x_ = imu_msg.orientation.x;
00815         orientation_y_ = imu_msg.orientation.y;
00816         orientation_z_ = imu_msg.orientation.z;
00817         orientation_w_ = imu_msg.orientation.w;
00818 
00819         ang_vel_x_ = imu_msg.angular_velocity.x;
00820         ang_vel_y_ = imu_msg.angular_velocity.y;
00821         ang_vel_z_ = imu_msg.angular_velocity.z;
00822 
00823         lin_acc_x_ = imu_msg.linear_acceleration.x;
00824         lin_acc_y_ = imu_msg.linear_acceleration.y;
00825         lin_acc_z_ = imu_msg.linear_acceleration.z;
00826 }
00827 
00828 double saturation(double u, double min, double max)
00829 {
00830  if (u>max) u=max;
00831  if (u<min) u=min;
00832  return u; 
00833 }
00834 
00835 double radnorm( double value ) 
00836 {
00837   while (value > PI) value -= PI;
00838   while (value < -PI) value += PI;
00839   return value;
00840 }
00841 
00842 double radnorm2( double value ) 
00843 {
00844   while (value > 2.0*PI) value -= 2.0*PI;
00845   while (value < -2.0*PI) value += 2.0*PI;
00846   return value;
00847 }
00848 
00849 bool spin()
00850 {
00851     ROS_INFO("summit_xl_robot_control::spin()");
00852     ros::Rate r(desired_freq_);  // 50.0 
00853 
00854     while (!ros::isShuttingDown()) // Using ros::isShuttingDown to avoid restarting the node during a shutdown.
00855     {
00856       if (starting() == 0)
00857       {
00858             while(ros::ok() && node_handle_.ok()) {
00859           UpdateControl();
00860           UpdateOdometry();
00861           PublishOdometry();
00862           diagnostic_.update();
00863           ros::spinOnce();
00864               r.sleep();
00865           }
00866               ROS_INFO("END OF ros::ok() !!!");
00867       } else {
00868        // No need for diagnostic here since a broadcast occurs in start
00869        // when there is an error.
00870        usleep(1000000);
00871        ros::spinOnce();
00872       }
00873    }
00874 
00875    ROS_INFO("summit_xl_robot_control::spin() - end");
00876    return true;
00877 }
00878 
00879 }; // Class SummitXLControllerClass
00880 
00881 int main(int argc, char** argv)
00882 {
00883         ros::init(argc, argv, "summit_xl_robot_control");
00884 
00885         ros::NodeHandle n;              
00886         SummitXLControllerClass sxlrc(n);
00887 
00888         
00889         // ros::ServiceServer service = n.advertiseService("set_odometry", &summit_xl_node::set_odometry, &sxlc);
00890     sxlrc.spin();
00891 
00892         return (0);
00893 
00894         
00895 }
00896 


summit_x_robot_control
Author(s): Roberto Guzman
autogenerated on Thu Jun 6 2019 18:38:57