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 #include "ackermann_msgs/AckermannDriveStamped.h"
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 #include <std_srvs/Empty.h>
00055 
00056 
00057 #define PI 3.1415926535
00058 #define AGVS_MIN_COMMAND_REC_FREQ     5.0
00059 #define AGVS_MAX_COMMAND_REC_FREQ     150.0
00060 
00061 #define AGVS_WHEEL_DIAMETER               0.2195      // Default wheel diameter
00062 #define DEFAULT_DIST_CENTER_TO_WHEEL  0.479       // Default distance center to motorwheel
00063     
00064 #define MAX_ELEVATOR_POSITION   0.05            // meters
00065 
00066 using namespace std;
00067 
00068 class AGVSControllerClass {
00069 
00070 public:
00071 
00072   ros::NodeHandle node_handle_;
00073   ros::NodeHandle private_node_handle_;
00074   double desired_freq_;
00075 
00076   
00077   diagnostic_updater::Updater diagnostic_;                      
00078   diagnostic_updater::FrequencyStatus freq_diag_;                        
00079   diagnostic_updater::HeaderlessTopicDiagnostic *subs_command_freq; 
00080   ros::Time last_command_time_;                                 
00081   diagnostic_updater::FunctionDiagnosticTask command_freq_;
00082 
00083   
00084   std::string robot_model_;
00085   
00086   
00087   ros::Publisher ref_vel_fwd_;
00088   ros::Publisher ref_vel_bwd_;
00089   ros::Publisher ref_pos_fwd_;
00090   ros::Publisher ref_pos_bwd_;
00091   ros::Publisher ref_pos_elevator_;
00092 
00093   
00094   ros::Subscriber joint_state_sub_;
00095 
00096   
00097   ros::Subscriber cmd_sub_;
00098         
00099   
00100   ros::ServiceServer srv_SetOdometry_;
00101   ros::ServiceServer srv_SetMode_;
00102   ros::ServiceServer srv_GetMode_;
00103   ros::ServiceServer srv_RaiseElevator_;
00104   ros::ServiceServer srv_LowerElevator_;
00105   
00106   
00107   std::string fwd_vel_topic_;
00108   std::string bwd_vel_topic_;
00109   
00110   
00111   std::string joint_front_wheel;
00112   std::string joint_back_wheel;
00113 
00114   
00115   std::string fwd_pos_topic_;
00116   std::string bwd_pos_topic_;
00117   std::string elevator_pos_topic_;
00118   
00119   std::string imu_topic_;
00120     
00121   
00122   std::string joint_front_motor_wheel;
00123   std::string joint_back_motor_wheel;
00124     
00125   
00126   int fwd_vel_, bwd_vel_;
00127   int fwd_pos_, bwd_pos_;
00128 
00129   
00130   double linearSpeedXMps_;
00131   double linearSpeedYMps_;
00132   double angularSpeedRads_;
00133 
00134   
00135   double robot_pose_px_;
00136   double robot_pose_py_;
00137   double robot_pose_pa_;
00138   double robot_pose_vx_;
00139   double robot_pose_vy_;
00140   
00141   
00142   sensor_msgs::JointState joint_state_;
00143   
00144   
00145   
00146   ackermann_msgs::AckermannDriveStamped base_vel_msg_;
00147 
00148   
00149   double v_ref_;
00150   double a_ref_;
00151 
00152   double v_mps_;  
00153   
00154   
00155   bool read_state_; 
00156   
00157   
00158   double agvs_wheel_diameter_; 
00159   double agvs_dist_to_center_;
00160 
00161   
00162   double ang_vel_x_;
00163   double ang_vel_y_;
00164   double ang_vel_z_;
00165 
00166   double lin_acc_x_;
00167   double lin_acc_y_;
00168   double lin_acc_z_;
00169 
00170   double orientation_diff_x_;
00171   double orientation_diff_y_;
00172   double orientation_diff_z_;
00173   double orientation_diff_w_;
00174 
00175   
00176   bool publish_odom_tf_;
00177 
00178   ros::Subscriber imu_sub_; 
00179   
00180   
00181   ros::Publisher odom_pub_; 
00182 
00183   
00184   tf::TransformBroadcaster odom_broadcaster;
00185 
00186 
00190 AGVSControllerClass(ros::NodeHandle h) : diagnostic_(),
00191   node_handle_(h), private_node_handle_("~"), 
00192   desired_freq_(100.0),
00193   freq_diag_(diagnostic_updater::FrequencyStatusParam(&desired_freq_, &desired_freq_, 0.05)   ),
00194   command_freq_("Command frequency check", boost::bind(&AGVSControllerClass::check_command_subscriber, this, _1))
00195   {
00196 
00197   ROS_INFO("agvs_robot_control_node - Init ");
00198   
00199   ros::NodeHandle agvs_robot_control_node_handle(node_handle_, "agvs_robot_control");
00200 
00201   
00202   if (!private_node_handle_.getParam("model", robot_model_)) {
00203           ROS_ERROR("Robot model not defined.");
00204           exit(-1);
00205           }
00206   else ROS_INFO("Robot Model : %s", robot_model_.c_str());
00207 
00208   
00209   private_node_handle_.param<std::string>("fwd_vel_topic", fwd_vel_topic_, "/agvs/joint_front_wheel_controller/command");
00210   private_node_handle_.param<std::string>("bwd_vel_topic", bwd_vel_topic_, "/agvs/joint_back_wheel_controller/command");
00211   private_node_handle_.param<std::string>("fwd_pos_topic", fwd_pos_topic_, "/agvs/joint_front_motor_wheel_controller/command");
00212   private_node_handle_.param<std::string>("bwd_pos_topic", bwd_pos_topic_, "/agvs/joint_back_motor_wheel_controller/command");
00213   private_node_handle_.param<std::string>("elevator_pos_topic", elevator_pos_topic_, "/agvs/joint_elevator_controller/command");
00214   private_node_handle_.param<std::string>("imu_topic", imu_topic_, "/agvs/imu_data");
00215 
00216   
00217   private_node_handle_.param<std::string>("joint_front_wheel", joint_front_wheel, "joint_front_wheel");
00218   private_node_handle_.param<std::string>("joint_back_wheel", joint_back_wheel, "joint_back_wheel");
00219   private_node_handle_.param<std::string>("joint_front_motor_wheel", joint_front_motor_wheel, "joint_front_motor_wheel");
00220   private_node_handle_.param<std::string>("joint_back_motor_wheel", joint_back_motor_wheel, "joint_back_motor_wheel");
00221 
00222   
00223   if (!private_node_handle_.getParam("agvs_wheel_diameter", agvs_wheel_diameter_))
00224                 agvs_wheel_diameter_ = AGVS_WHEEL_DIAMETER; 
00225   if (!private_node_handle_.getParam("agvs_dist_to_center", agvs_dist_to_center_))
00226                 agvs_dist_to_center_ = DEFAULT_DIST_CENTER_TO_WHEEL;
00227   
00228   
00229 
00230   private_node_handle_.param("publish_odom_tf", publish_odom_tf_, true);
00231   if (publish_odom_tf_) ROS_INFO("PUBLISHING odom->base_footprint tf");
00232   else ROS_INFO("NOT PUBLISHING odom->base_footprint tf");
00233   
00234   
00235   linearSpeedXMps_   = 0.0;
00236   linearSpeedYMps_   = 0.0;
00237   angularSpeedRads_  = 0.0;
00238 
00239   
00240   robot_pose_px_ = 0.0;
00241   robot_pose_py_ = 0.0;
00242   robot_pose_pa_ = 0.0;
00243   robot_pose_vx_ = 0.0;
00244   robot_pose_vy_ = 0.0;
00245 
00246   
00247   v_ref_ = 0.0;
00248   a_ref_ = 0.0;
00249 
00250   
00251   ang_vel_x_ = 0.0; ang_vel_y_ = 0.0; ang_vel_z_ = 0.0;
00252   lin_acc_x_ = 0.0; lin_acc_y_ = 0.0; lin_acc_z_ = 0.0;
00253   orientation_diff_x_ = 0.0; orientation_diff_y_ = 0.0; orientation_diff_z_ = 0.0; orientation_diff_w_ = 1.0;
00254 
00255   
00256   srv_SetOdometry_ = private_node_handle_.advertiseService("set_odometry",  &AGVSControllerClass::srvCallback_SetOdometry, this);
00257   srv_RaiseElevator_ = private_node_handle_.advertiseService("raise_elevator",  &AGVSControllerClass::srvCallback_RaiseElevator, this);
00258   srv_LowerElevator_ = private_node_handle_.advertiseService("lower_elevator",  &AGVSControllerClass::srvCallback_LowerElevator, this);
00259 
00260   
00261   joint_state_sub_ = agvs_robot_control_node_handle.subscribe<sensor_msgs::JointState>("/agvs/joint_states", 1, &AGVSControllerClass::jointStateCallback, this);
00262   
00263   
00264 
00265 
00266   
00267   
00268   imu_sub_ = private_node_handle_.subscribe(imu_topic_, 1, &AGVSControllerClass::imuCallback, this);
00269 
00270   
00271   ref_vel_fwd_ = private_node_handle_.advertise<std_msgs::Float64>( fwd_vel_topic_, 50);
00272   ref_vel_bwd_ = private_node_handle_.advertise<std_msgs::Float64>( bwd_vel_topic_, 50);
00273   ref_pos_fwd_ = private_node_handle_.advertise<std_msgs::Float64>( fwd_pos_topic_, 50);
00274   ref_pos_bwd_ = private_node_handle_.advertise<std_msgs::Float64>( bwd_pos_topic_, 50);          
00275   ref_pos_elevator_ = private_node_handle_.advertise<std_msgs::Float64>( elevator_pos_topic_, 50);        
00276           
00277   
00278   cmd_sub_ = private_node_handle_.subscribe<ackermann_msgs::AckermannDriveStamped>("command", 1, &AGVSControllerClass::commandCallback, this ); 
00279     
00280   
00281   
00282   odom_pub_ = private_node_handle_.advertise<nav_msgs::Odometry>("odom", 1000);
00283 
00284   
00285   diagnostic_.setHardwareID("agvs_robot_control - simulation");
00286   diagnostic_.add( freq_diag_ );
00287   diagnostic_.add( command_freq_ );
00288     
00289   
00290   
00291   double min_freq = AGVS_MIN_COMMAND_REC_FREQ; 
00292   double max_freq = AGVS_MAX_COMMAND_REC_FREQ; 
00293   subs_command_freq = new diagnostic_updater::HeaderlessTopicDiagnostic("/agvs_robot_control/command", diagnostic_,
00294                             diagnostic_updater::FrequencyStatusParam(&min_freq, &max_freq, 0.1, 10));
00295   subs_command_freq->addTask(&command_freq_); 
00296   
00297   
00298   read_state_ = false;
00299   
00300   
00301   v_mps_ = 0;
00302 }
00303 
00305 int starting()
00306 {
00307 
00308   ROS_INFO("AGVSControllerClass::starting");
00309 
00310 
00311 
00312 
00313 
00314   
00315   if (read_state_) {
00316     vector<string> joint_names = joint_state_.name;
00317     fwd_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_wheel)) - joint_names.begin();
00318     bwd_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_wheel)) - joint_names.begin();
00319     fwd_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_front_motor_wheel)) - joint_names.begin();
00320     bwd_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_back_motor_wheel)) - joint_names.begin();
00321     return 0;
00322     }
00323   else return -1;
00324 }
00325 
00330 void UpdateOdometry(){
00331 
00332     
00333         
00334    
00335    
00336    
00337    
00338    
00339    
00340 
00341 
00342         double fBetaRads = 0.0;
00343         double v_mps = 0.0;
00344 
00345         
00346         double fSamplePeriod = 1.0 / desired_freq_;
00347 
00348         
00349         double v_fwd, v_bwd; 
00350         v_fwd = joint_state_.velocity[fwd_vel_] * (agvs_wheel_diameter_ / 2.0);
00351         v_bwd = joint_state_.velocity[bwd_vel_] * (agvs_wheel_diameter_ / 2.0);
00352         
00353         v_mps = -(v_fwd + v_bwd) / 2.0;
00354 
00355         
00356         double a_fwd, a_bwd;
00357         a_fwd = radnorm2( joint_state_.position[fwd_pos_] );
00358         a_bwd = radnorm2( joint_state_.position[bwd_pos_] );
00359         fBetaRads = a_fwd; 
00360         
00361         
00362         if(fabs(v_mps) < 0.00001) v_mps = 0.0;
00363 
00364         
00365         double w = (v_mps / agvs_dist_to_center_) * sin(fBetaRads);
00366         robot_pose_pa_ += w * fSamplePeriod;
00367 
00368         
00369         radnorm(&robot_pose_pa_);
00370         
00371         
00372         robot_pose_vx_ = v_mps * cos(fBetaRads) * cos(robot_pose_pa_);
00373         robot_pose_vy_ = v_mps * cos(fBetaRads) * sin(robot_pose_pa_);
00374         
00375         
00376         robot_pose_px_ += robot_pose_vx_ * fSamplePeriod;
00377         robot_pose_py_ += robot_pose_vy_ * fSamplePeriod;
00378 }
00379 
00380 
00381 void PublishOdometry()
00382 {
00383         ros::Time current_time = ros::Time::now();
00384         
00385     
00386     geometry_msgs::TransformStamped odom_trans;
00387     odom_trans.header.stamp = current_time;
00388     odom_trans.header.frame_id = "odom";
00389     odom_trans.child_frame_id = "base_footprint";
00390 
00391     odom_trans.transform.translation.x = robot_pose_px_;
00392     odom_trans.transform.translation.y = robot_pose_py_;
00393     odom_trans.transform.translation.z = 0.0;
00394 
00395         
00396     double theta = robot_pose_pa_;
00397     geometry_msgs::Quaternion quat = tf::createQuaternionMsgFromYaw( theta );
00398     odom_trans.transform.rotation.x = quat.x;
00399         odom_trans.transform.rotation.y = quat.y;
00400         odom_trans.transform.rotation.z = quat.z;
00401         odom_trans.transform.rotation.w = quat.w;
00402 
00403         
00404     
00405         
00406         
00407     if (publish_odom_tf_) odom_broadcaster.sendTransform(odom_trans);  
00408         
00409     
00410     nav_msgs::Odometry odom;
00411     odom.header.stamp = current_time;
00412     odom.header.frame_id = "odom";
00413 
00414     
00415         
00416     odom.pose.pose.position.x = robot_pose_px_;
00417     odom.pose.pose.position.y = robot_pose_py_;
00418     odom.pose.pose.position.z = 0.0;
00419         
00420     odom.pose.pose.orientation.x = orientation_diff_x_;
00421         odom.pose.pose.orientation.y = orientation_diff_y_;
00422         odom.pose.pose.orientation.z = orientation_diff_z_;
00423         odom.pose.pose.orientation.w = orientation_diff_w_;
00424         
00425     
00426     for(int i = 0; i < 6; i++)
00427                 odom.pose.covariance[i*6+i] = 0.1;  
00428 
00429     
00430     odom.child_frame_id = "base_footprint";
00431         
00432     odom.twist.twist.linear.x = robot_pose_vx_;
00433     odom.twist.twist.linear.y = robot_pose_vy_;
00434         odom.twist.twist.linear.z = 0.0;
00435         
00436         odom.twist.twist.angular.x = ang_vel_x_;
00437         odom.twist.twist.angular.y = ang_vel_y_;
00438     odom.twist.twist.angular.z = ang_vel_z_;
00439         
00440         for(int i = 0; i < 6; i++)
00441                 odom.twist.covariance[6*i+i] = 0.1;  
00442 
00443     
00444     odom_pub_.publish(odom);
00445 }
00446 
00447 void UpdateControl()
00448 {
00449   
00450   std_msgs::Float64 vel_ref_msg; 
00451   std_msgs::Float64 pos_ref_msg;
00452   static double ev_ant = 0.0;
00453 
00454   
00455   
00456   
00457   
00458   
00459   
00460   
00461 
00462 
00463 
00464 
00465 
00466 
00467 
00468   
00469   double Kp = 10.0;  
00470   vel_ref_msg.data = -v_ref_ * Kp;
00471 
00472   pos_ref_msg.data = a_ref_;
00473                   
00474   
00475   ref_vel_fwd_.publish( vel_ref_msg );
00476   ref_vel_bwd_.publish( vel_ref_msg );
00477   
00478   ref_pos_fwd_.publish( pos_ref_msg );
00479   pos_ref_msg.data = -a_ref_; 
00480   ref_pos_bwd_.publish( pos_ref_msg );
00481 }
00482 
00483 
00484 void SetElevatorPosition(double val){
00485         
00486         std_msgs::Float64 ref_msg; 
00487         
00488         ref_msg.data = val;
00489         
00490         ref_pos_elevator_.publish( ref_msg );
00491 }
00492 
00494 void stopping()
00495 {}
00496 
00497 
00498 
00499 
00500 
00501 void check_command_subscriber(diagnostic_updater::DiagnosticStatusWrapper &stat)
00502 {
00503         ros::Time current_time = ros::Time::now();
00504 
00505         double diff = (current_time - last_command_time_).toSec();
00506 
00507         if(diff > 1.0){
00508                 stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Topic is not receiving commands");
00509                 
00510                 
00511         }else{
00512                 stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Topic receiving commands");
00513         }
00514 }
00515 
00516 
00517 bool srvCallback_SetOdometry(robotnik_msgs::set_odometry::Request &request, robotnik_msgs::set_odometry::Response &response )
00518 {
00519         
00520         robot_pose_px_ = request.x;
00521         robot_pose_py_ = request.y;
00522         robot_pose_pa_ = request.orientation;
00523 
00524         response.ret = true;
00525         return true;
00526 }
00527 
00528 
00529 bool srvCallback_RaiseElevator(std_srvs::Empty::Request &request, std_srvs::Empty::Response &response )
00530 {
00531         
00532         SetElevatorPosition(MAX_ELEVATOR_POSITION);
00533         
00534         return true;
00535 }
00536 
00537 
00538 bool srvCallback_LowerElevator(std_srvs::Empty::Request &request, std_srvs::Empty::Response &response )
00539 {
00540         SetElevatorPosition(0.0);
00541         
00542         return true;
00543 }
00544 
00545 
00546 
00547 void jointStateCallback(const sensor_msgs::JointStateConstPtr& msg)
00548 {       
00549   joint_state_ = *msg;
00550   read_state_ = true;
00551 }
00552 
00553 
00554 void commandCallback(const ackermann_msgs::AckermannDriveStamped::ConstPtr& msg)
00555 {
00556   
00557   last_command_time_ = ros::Time::now();
00558   subs_command_freq->tick();                    
00559 
00560   double speed_limit = 2.0;  
00561   double angle_limit = PI;   
00562   v_ref_ = saturation(msg->drive.speed, -speed_limit, speed_limit);  
00563   a_ref_ = saturation(msg->drive.steering_angle, -angle_limit, angle_limit);
00564 }
00565 
00566 
00567 void imuCallback( const sensor_msgs::Imu& imu_msg){
00568 
00569         orientation_diff_x_ = imu_msg.orientation.x;
00570         orientation_diff_y_ = imu_msg.orientation.y;
00571         orientation_diff_z_ = imu_msg.orientation.z;
00572         orientation_diff_w_ = imu_msg.orientation.w;
00573 
00574         ang_vel_x_ = imu_msg.angular_velocity.x;
00575         ang_vel_y_ = imu_msg.angular_velocity.y;
00576         ang_vel_z_ = imu_msg.angular_velocity.z;
00577 
00578         lin_acc_x_ = imu_msg.linear_acceleration.x;
00579         lin_acc_y_ = imu_msg.linear_acceleration.y;
00580     lin_acc_z_ = imu_msg.linear_acceleration.z;
00581 }
00582 
00583 double saturation(double u, double min, double max)
00584 {
00585  if (u>max) u=max;
00586  if (u<min) u=min;
00587  return u; 
00588 }
00589 
00590 
00591 
00593 static inline void radnorm(double* radians)
00594 {
00595         while (*radians >= (PI)) {
00596                 *radians -= 2.0 * PI;
00597                 }
00598         while (*radians <= (-PI)) {
00599                 *radians += 2.0 * PI;
00600                 }
00601 }
00602 
00603 static inline double radnorm2( double value ) 
00604 {
00605   while (value > 2.0*PI) value -= 2.0*PI;
00606   while (value < -2.0*PI) value += 2.0*PI;
00607   return value;
00608 }
00609 
00610 bool spin()
00611 {
00612     ROS_INFO("agvs_robot_control::spin()");
00613     ros::Rate r(desired_freq_);  
00614 
00615     while (!ros::isShuttingDown()) 
00616     {
00617       if (starting() == 0)
00618       {
00619             while(ros::ok() && node_handle_.ok()) {
00620           UpdateControl();
00621           UpdateOdometry();
00622           PublishOdometry();
00623           diagnostic_.update();
00624           ros::spinOnce();
00625               r.sleep();
00626           }
00627               ROS_INFO("END OF ros::ok() !!!");
00628       } else {
00629        
00630        
00631        usleep(1000000);
00632        ros::spinOnce();
00633       }
00634    }
00635 
00636    ROS_INFO("agvs_robot_control::spin() - end");
00637    return true;
00638 }
00639 
00640 }; 
00641 
00642 int main(int argc, char** argv)
00643 {
00644         ros::init(argc, argv, "agvs_robot_control");
00645 
00646         ros::NodeHandle n;              
00647         AGVSControllerClass sxlrc(n);
00648 
00649     sxlrc.spin();
00650 
00651         return (0);
00652 
00653         
00654 }
00655