00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
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 
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   
00079   diagnostic_updater::Updater diagnostic_;                      
00080   diagnostic_updater::FrequencyStatus freq_diag_;                        
00081   diagnostic_updater::HeaderlessTopicDiagnostic *subs_command_freq; 
00082   ros::Time last_command_time_;                                 
00083   diagnostic_updater::FunctionDiagnosticTask command_freq_;
00084 
00085   
00086   std::string robot_model_;
00087   
00088   
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   
00102   ros::Subscriber joint_state_sub_;
00103 
00104   
00105   ros::Subscriber cmd_sub_;
00106         
00107   
00108   ros::Subscriber ptz_sub_;
00109 
00110   
00111 
00112   
00113   ros::ServiceServer srv_SetOdometry_;
00114   ros::ServiceServer srv_SetMode_;
00115   ros::ServiceServer srv_GetMode_;
00116   
00117   
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   
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   
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   
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   
00142   std::string scissor_pos_topic_;
00143   
00144   
00145   std::string odom_topic_;
00146 
00147   
00148   std::string joint_camera_pan;
00149   std::string joint_camera_tilt;
00150 
00151   
00152   std::string pan_pos_topic_;
00153   std::string tilt_pos_topic_;
00154     
00155   
00156   std::string scissor_prismatic_joint;
00157 
00158   
00159   int kinematic_modes_;   
00160   int active_kinematic_mode_;
00161 
00162   
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   
00170   double linearSpeedXMps_;
00171   double linearSpeedYMps_;
00172   double angularSpeedRads_;
00173 
00174   
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   
00182   sensor_msgs::JointState joint_state_;
00183   
00184   
00185   geometry_msgs::Twist base_vel_msg_;
00186 
00187   
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   
00196   bool read_state_; 
00197   
00198   
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   
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   
00219   bool publish_odom_tf_;
00220 
00221   ros::Subscriber imu_sub_; 
00222   
00223   
00224   ros::Publisher odom_pub_; 
00225 
00226   
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   
00241   ROS_INFO("summit_xl_robot_control_node - Init ");
00242 
00243   
00244   
00245   kinematic_modes_ = 1;  
00246   
00247   ros::NodeHandle summit_xl_robot_control_node_handle(node_handle_, "summit_xl_robot_control");
00248 
00249   
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   
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   
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   
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     
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   
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   
00300   private_node_handle_.param<std::string>("odom_topic", odom_topic_, "/summit_xl/odom_robot_control");
00301   
00302   
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   
00315   linearSpeedXMps_   = 0.0;
00316   linearSpeedYMps_   = 0.0;
00317   angularSpeedRads_  = 0.0;
00318 
00319   
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   
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   
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   
00340   active_kinematic_mode_ = SKID_STEERING;
00341 
00342   
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   
00348   joint_state_sub_ = summit_xl_robot_control_node_handle.subscribe<sensor_msgs::JointState>("/summit_xl/joint_states", 1, &SummitXLControllerClass::jointStateCallback, this);
00349 
00350   
00351   
00352   imu_sub_ = summit_xl_robot_control_node_handle.subscribe("/imu_data", 1, &SummitXLControllerClass::imuCallback, this);
00353 
00354 
00355   
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   
00375   cmd_sub_ = summit_xl_robot_control_node_handle.subscribe<geometry_msgs::Twist>("/summit_xl/robot_control/command", 1, &SummitXLControllerClass::commandCallback, this);
00376 
00377   
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   
00380   
00381   
00382   odom_pub_ = summit_xl_robot_control_node_handle.advertise<nav_msgs::Odometry>(odom_topic_, 1000);
00383 
00384   
00385   diagnostic_.setHardwareID("summit_xl_robot_control - simulation");
00386   diagnostic_.add( freq_diag_ );
00387   diagnostic_.add( command_freq_ );
00388     
00389   
00390   
00391   double min_freq = SUMMIT_XL_MIN_COMMAND_REC_FREQ; 
00392   double max_freq = SUMMIT_XL_MAX_COMMAND_REC_FREQ; 
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_); 
00396   
00397   
00398   read_state_ = false;
00399 }
00400 
00402 int starting()
00403 {
00404 
00405   ROS_INFO("SummitXLControllerClass::starting");
00406 
00407   
00408   
00409   
00410 
00411   
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         
00428         
00429         
00430     return 0;
00431     }
00432   else return -1;
00433 }
00434 
00435 
00437 void UpdateControl()
00438 {
00439   
00440   if (active_kinematic_mode_ == SKID_STEERING) {
00441 
00442           double v_left_mps, v_right_mps;
00443 
00444           
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           
00448 
00449           linearSpeedXMps_ = (v_right_mps + v_left_mps) / 2.0;                       
00450           angularSpeedRads_ = (v_right_mps - v_left_mps) / summit_xl_d_tracks_m_;    
00451 
00452           
00453                 
00454 
00455           
00456           double epv=0.0;
00457           double epw=0.0;
00458           static double epvant =0.0;
00459           static double epwant =0.0;
00460 
00461           
00462           
00463           
00464           
00465           double kpv=2.5; double kdv=0.0;
00466           double kpw=25.0; double kdw=15.0;
00467 
00468           
00469           epv = v_ref_x_ - linearSpeedXMps_;
00470           epw = w_ref_ - angularSpeedRads_;
00471           
00472 
00473           
00474           double uv= kpv * epv + kdv * (epv - epvant);
00475           double uw= kpw * epw + kdw * (epw - epwant);
00476           epvant = epv;
00477           epwant = epw;
00478 
00479           
00480           double dUl = uv - 0.5 * summit_xl_d_tracks_m_ * uw;
00481           
00482           double dUr = -(uv + 0.5 * summit_xl_d_tracks_m_ * uw);  
00483 
00484           
00485           double limit = 40.0;
00486           
00487           
00488 
00489           
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   
00509   if (active_kinematic_mode_ == MECANUM_STEERING) {
00510 
00511           
00512           
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       
00548         
00549           
00550           double limit = 40.0;
00551           
00552           
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         
00582         if (robot_model_ == "x_wam") {          
00583                 
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         
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      
00593          std_msgs::Float64 pan_ref_pos_msg, tilt_ref_pos_msg;
00594      pan_ref_pos_msg.data = pos_ref_pan_;            
00595      ref_pos_pan_.publish( pan_ref_pos_msg );
00596      tilt_ref_pos_msg.data = pos_ref_tilt_;          
00597      ref_pos_tilt_.publish( tilt_ref_pos_msg );
00598 }
00599 
00600 
00601 void UpdateOdometry()
00602 {
00603   
00604   if (active_kinematic_mode_ == SKID_STEERING) {
00605           
00606       
00607           robot_pose_vx_ = linearSpeedXMps_ *  cos(robot_pose_pa_);
00608       robot_pose_vy_ = linearSpeedXMps_ *  sin(robot_pose_pa_);
00609       }
00610                 
00611   
00612   if (active_kinematic_mode_ == MECANUM_STEERING) {
00613 
00614       
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       
00634       robot_pose_vx_ = (A+B) / 2.0;
00635       robot_pose_vy_ = (C+D) / 2.0;               
00636       }
00637       
00638       
00639       double fSamplePeriod = 1.0 / desired_freq_;
00640           robot_pose_pa_ += ang_vel_z_ * fSamplePeriod;  
00641       robot_pose_px_ += robot_pose_vx_ * fSamplePeriod;
00642       robot_pose_py_ += robot_pose_vy_ * fSamplePeriod;
00643       
00644 }
00645 
00646 
00647 void PublishOdometry()
00648 {
00649         ros::Time current_time = ros::Time::now();
00650         
00651     
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     
00666         
00667         
00668     if (publish_odom_tf_) odom_broadcaster.sendTransform(odom_trans);  
00669         
00670     
00671     nav_msgs::Odometry odom;
00672     odom.header.stamp = current_time;
00673     odom.header.frame_id = "odom";
00674 
00675     
00676         
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         
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         
00686     for(int i = 0; i < 6; i++)
00687                 odom.pose.covariance[i*6+i] = 0.1;  
00688 
00689     
00690     odom.child_frame_id = "base_footprint";
00691         
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         
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         
00700         for(int i = 0; i < 6; i++)
00701                 odom.twist.covariance[6*i+i] = 0.1;  
00702 
00703     
00704     odom_pub_.publish(odom);
00705 }
00706 
00708 void stopping()
00709 {}
00710 
00711 
00712 
00713 
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                 
00725                 
00726         }else{
00727                 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Topic receiving commands");
00728         }
00729 }
00730 
00731 
00732 
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); 
00738    v_ref_z_ = saturation(cmd_vel.linear.z, -10.0, 10.0);
00739 }
00740 
00741 
00742 
00743 bool srvCallback_SetMode(robotnik_msgs::set_mode::Request& request, robotnik_msgs::set_mode::Response& response)
00744 {
00745   
00746   
00747   
00748   
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 
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 
00774 bool srvCallback_SetOdometry(robotnik_msgs::set_odometry::Request &request, robotnik_msgs::set_odometry::Response &response )
00775 {
00776         
00777         
00778         
00779         
00780 
00781         response.ret = true;
00782         return true;
00783 }
00784 
00785 
00786 
00787 void jointStateCallback(const sensor_msgs::JointStateConstPtr& msg)
00788 {       
00789   joint_state_ = *msg;
00790   read_state_ = true;
00791 }
00792 
00793 
00794 void commandCallback(const geometry_msgs::TwistConstPtr& msg)
00795 {
00796   
00797   last_command_time_ = ros::Time::now();
00798   subs_command_freq->tick();                    
00799 
00800   base_vel_msg_ = *msg;
00801   this->setCommand(base_vel_msg_);
00802 }
00803 
00804 
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 
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_);  
00853 
00854     while (!ros::isShuttingDown()) 
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        
00869        
00870        usleep(1000000);
00871        ros::spinOnce();
00872       }
00873    }
00874 
00875    ROS_INFO("summit_xl_robot_control::spin() - end");
00876    return true;
00877 }
00878 
00879 }; 
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         
00890     sxlrc.spin();
00891 
00892         return (0);
00893 
00894         
00895 }
00896