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


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