ackermann_controller.cpp
Go to the documentation of this file.
00001 #include <cmath>
00002 
00003 #include <tf/transform_datatypes.h>
00004 
00005 #include <urdf_parser/urdf_parser.h>
00006 
00007 #include <boost/assign.hpp>
00008 
00009 #include <urdf_vehicle_kinematic/urdf_vehicle_kinematic.h>
00010 
00011 #include <ackermann_controller/ackermann_controller.h>
00012 
00013 namespace ackermann_controller{
00014 
00015   AckermannController::AckermannController()
00016     : open_loop_(false)
00017     , command_struct_()
00018     , command_struct_ackermann_()
00019     , track_(0.0)
00020     , front_wheel_radius_(0.0)
00021     , rear_wheel_radius_(0.0)
00022     , steering_limit_(0.0)
00023     , wheel_base_(0.0)
00024     , cmd_vel_timeout_(0.5)
00025     , base_frame_id_("base_link")
00026     , enable_odom_tf_(true)
00027     , enable_twist_cmd_(false)
00028   {
00029   }
00030 
00031   bool AckermannController::initRequest(hardware_interface::RobotHW *const robot_hw,
00032                          ros::NodeHandle& root_nh,
00033                          ros::NodeHandle& ctrlr_nh,
00034                          std::set<std::string> &claimed_resources)
00035   {
00036     if (state_ != CONSTRUCTED)
00037     {
00038       ROS_ERROR("The ackermann controller could not be created.");
00039       return false;
00040     }
00041 
00042     hardware_interface::PositionJointInterface *const pos_joint_hw = robot_hw->get<hardware_interface::PositionJointInterface>();
00043     hardware_interface::VelocityJointInterface *const vel_joint_hw = robot_hw->get<hardware_interface::VelocityJointInterface>();
00044 
00045     if (pos_joint_hw == NULL)
00046     {
00047       ROS_ERROR("This controller requires a hardware interface of type '%s'."
00048                 " Make sure this is registered in the hardware_interface::RobotHW class.",
00049                 hardware_interface::internal::demangledTypeName<hardware_interface::PositionJointInterface>().c_str());
00050       return false;
00051     }
00052     else if (vel_joint_hw == NULL)
00053     {
00054       ROS_ERROR("This controller requires a hardware interface of type '%s'."
00055                 " Make sure this is registered in the hardware_interface::RobotHW class.",
00056                 hardware_interface::internal::demangledTypeName<hardware_interface::PositionJointInterface>().c_str());
00057       return false;
00058     }
00059 
00060     pos_joint_hw->clearClaims();
00061     vel_joint_hw->clearClaims();
00062     if(init(pos_joint_hw, vel_joint_hw, root_nh, ctrlr_nh) == false)
00063     {
00064       ROS_ERROR("Failed to initialize the controller");
00065       return false;
00066     }
00067 
00068     claimed_resources.clear();
00069     const std::set<std::string> claims_pos = pos_joint_hw->getClaims();
00070     claimed_resources.insert(claims_pos.begin(), claims_pos.end());
00071     pos_joint_hw->clearClaims();
00072 
00073     const std::set<std::string> claims_vel = vel_joint_hw->getClaims();
00074     claimed_resources.insert(claims_vel.begin(), claims_vel.end());
00075     vel_joint_hw->clearClaims();
00076 
00077     state_ = INITIALIZED;
00078     return true;
00079   }
00080 
00081   bool AckermannController::init(hardware_interface::PositionJointInterface* hw_pos,
00082                                  hardware_interface::VelocityJointInterface* hw_vel,
00083                                  ros::NodeHandle& root_nh,
00084                                  ros::NodeHandle &controller_nh)
00085   {
00086     const std::string complete_ns = controller_nh.getNamespace();
00087     std::size_t id = complete_ns.find_last_of("/");
00088     name_ = complete_ns.substr(id + 1);
00089 
00090     // Get joint names from the parameter server
00091     std::vector<std::string> front_wheel_names, rear_wheel_names;
00092     if (!getWheelNames(controller_nh, "front_wheel", front_wheel_names) or
00093         !getWheelNames(controller_nh, "rear_wheel", rear_wheel_names))
00094     {
00095       return false;
00096     }
00097 
00098     if (front_wheel_names.size() != rear_wheel_names.size())
00099     {
00100       ROS_ERROR_STREAM_NAMED(name_,
00101           "#front wheels (" << front_wheel_names.size() << ") != " <<
00102           "#rear wheels (" << rear_wheel_names.size() << ").");
00103       return false;
00104     }
00105     else if (front_wheel_names.size() != 2)
00106     {
00107       ROS_ERROR_STREAM_NAMED(name_,
00108           "#two wheels by axle (left and right) is needed; now : "<<front_wheel_names.size()<<" .");
00109       return false;
00110     }
00111     else
00112     {
00113       front_wheel_joints_.resize(front_wheel_names.size());
00114       rear_wheel_joints_.resize(front_wheel_names.size());
00115     }
00116 
00117     // Get steering joint names from the parameter server
00118     std::vector<std::string> front_steering_names;
00119     if (!getWheelNames(controller_nh, "front_steering", front_steering_names))
00120     {
00121       return false;
00122     }
00123 
00124     if (front_steering_names.size() != 2)
00125     {
00126       ROS_ERROR_STREAM_NAMED(name_,
00127           "#two steering by axle (left and right) is needed; now : "<<front_steering_names.size()<<" .");
00128       return false;
00129     }
00130     else
00131     {
00132       front_steering_joints_.resize(front_steering_names.size());
00133     }
00134 
00135     // Odometry related:
00136     double publish_rate;
00137     controller_nh.param("publish_rate", publish_rate, 50.0);
00138     ROS_INFO_STREAM_NAMED(name_, "Controller state will be published at "
00139                           << publish_rate << "Hz.");
00140     publish_period_ = ros::Duration(1.0 / publish_rate);
00141 
00142     controller_nh.param("open_loop", open_loop_, open_loop_);
00143 
00144     int velocity_rolling_window_size = 10;
00145     controller_nh.param("velocity_rolling_window_size", velocity_rolling_window_size, velocity_rolling_window_size);
00146     ROS_INFO_STREAM_NAMED(name_, "Velocity rolling window size of "
00147                           << velocity_rolling_window_size << ".");
00148 
00149     odometry_.setVelocityRollingWindowSize(velocity_rolling_window_size);
00150 
00151     // Twist command related:
00152     controller_nh.param("cmd_vel_timeout", cmd_vel_timeout_, cmd_vel_timeout_);
00153     ROS_INFO_STREAM_NAMED(name_, "Velocity commands will be considered old if they are older than "
00154                           << cmd_vel_timeout_ << "s.");
00155 
00156     controller_nh.param("base_frame_id", base_frame_id_, base_frame_id_);
00157     ROS_INFO_STREAM_NAMED(name_, "Base frame_id set to " << base_frame_id_);
00158 
00159     controller_nh.param("enable_odom_tf", enable_odom_tf_, enable_odom_tf_);
00160     ROS_INFO_STREAM_NAMED(name_, "Publishing to tf is " << (enable_odom_tf_?"enabled":"disabled"));
00161 
00162     controller_nh.param("enable_twist_cmd", enable_twist_cmd_, enable_twist_cmd_);
00163     ROS_INFO_STREAM_NAMED(name_, "Twist cmd is " << (enable_twist_cmd_?"enabled":"disabled")<<" (default is ackermann)");
00164 
00165     // Velocity and acceleration limits:
00166     controller_nh.param("linear/x/has_velocity_limits"    , limiter_lin_.has_velocity_limits    , limiter_lin_.has_velocity_limits    );
00167     controller_nh.param("linear/x/has_acceleration_limits", limiter_lin_.has_acceleration_limits, limiter_lin_.has_acceleration_limits);
00168     controller_nh.param("linear/x/max_velocity"           , limiter_lin_.max_velocity           ,  limiter_lin_.max_velocity          );
00169     controller_nh.param("linear/x/min_velocity"           , limiter_lin_.min_velocity           , -limiter_lin_.max_velocity          );
00170     controller_nh.param("linear/x/max_acceleration"       , limiter_lin_.max_acceleration       ,  limiter_lin_.max_acceleration      );
00171     controller_nh.param("linear/x/min_acceleration"       , limiter_lin_.min_acceleration       , -limiter_lin_.max_acceleration      );
00172 
00173     controller_nh.param("angular/z/has_velocity_limits"    , limiter_ang_.has_velocity_limits    , limiter_ang_.has_velocity_limits    );
00174     controller_nh.param("angular/z/has_acceleration_limits", limiter_ang_.has_acceleration_limits, limiter_ang_.has_acceleration_limits);
00175     controller_nh.param("angular/z/max_velocity"           , limiter_ang_.max_velocity           ,  limiter_ang_.max_velocity          );
00176     controller_nh.param("angular/z/min_velocity"           , limiter_ang_.min_velocity           , -limiter_ang_.max_velocity          );
00177     controller_nh.param("angular/z/max_acceleration"       , limiter_ang_.max_acceleration       ,  limiter_ang_.max_acceleration      );
00178     controller_nh.param("angular/z/min_acceleration"       , limiter_ang_.min_acceleration       , -limiter_ang_.max_acceleration      );
00179 
00180     // If either parameter is not available, we need to look up the value in the URDF
00181     bool lookup_track = !controller_nh.getParam("track", track_);
00182     bool lookup_front_wheel_radius = !controller_nh.getParam("front_wheel_radius", front_wheel_radius_);
00183     bool lookup_rear_wheel_radius = !controller_nh.getParam("rear_wheel_radius", rear_wheel_radius_);
00184     bool lookup_wheel_base = !controller_nh.getParam("wheel_base", wheel_base_);
00185 
00186     urdf_vehicle_kinematic::UrdfVehicleKinematic uvk(root_nh, base_frame_id_);
00187     if(lookup_track)
00188     {
00189       if(!uvk.getDistanceBetweenJoints(front_steering_names[0], front_steering_names[1], track_))
00190         return false;
00191       else
00192         controller_nh.setParam("track",track_);
00193     }
00194     if(lookup_front_wheel_radius)
00195     {
00196       if(!uvk.getJointRadius(front_wheel_names[0], front_wheel_radius_))
00197         return false;
00198       else
00199         controller_nh.setParam("front_wheel_radius",front_wheel_radius_);
00200     }
00201     if(lookup_rear_wheel_radius)
00202     {
00203       if(!uvk.getJointRadius(rear_wheel_names[0], rear_wheel_radius_))
00204         return false;
00205       else
00206         controller_nh.setParam("rear_wheel_radius",rear_wheel_radius_);
00207     }
00208     if(lookup_wheel_base)
00209     {
00210       if(!uvk.getDistanceBetweenJoints(front_wheel_names[0], rear_wheel_names[0], wheel_base_))
00211         return false;
00212       else
00213         controller_nh.setParam("wheel_base",wheel_base_);
00214     }
00215 
00216     if(!uvk.getJointSteeringLimits(front_steering_names[0], steering_limit_))
00217       return false;
00218     else
00219     {
00220       controller_nh.setParam("steering_limit",steering_limit_);
00221     }
00222 
00223     // Regardless of how we got the separation and radius, use them
00224     // to set the odometry parameters
00225     const double ws = track_;
00226     const double wb = wheel_base_;
00227     odometry_.setWheelParams(ws, front_wheel_radius_, rear_wheel_radius_, wb);
00228     ROS_INFO_STREAM_NAMED(name_,
00229                           "Odometry params : wheel separation " << ws
00230                           << ", front wheel radius " << front_wheel_radius_
00231                           << ", rear wheel radius " << rear_wheel_radius_
00232                           << ", wheel base " << wb);
00233 
00234     setOdomPubFields(root_nh, controller_nh);
00235 
00236     // Get the joint object to use in the realtime loop
00237     for (int i = 0; i < front_wheel_joints_.size(); ++i)
00238     {
00239       ROS_INFO_STREAM_NAMED(name_,
00240                             "Adding front wheel with joint name: " << front_wheel_names[i]
00241                             << " and rear wheel with joint name: " << rear_wheel_names[i]);
00242       front_wheel_joints_[i] = hw_vel->getHandle(front_wheel_names[i]);  // throws on failure
00243       rear_wheel_joints_[i] = hw_vel->getHandle(rear_wheel_names[i]);  // throws on failure
00244     }
00245 
00246     // Get the steering joint object to use in the realtime loop
00247     for (int i = 0; i < front_steering_joints_.size(); ++i)
00248     {
00249       ROS_INFO_STREAM_NAMED(name_,
00250                             "Adding front steering with joint name: " << front_steering_names[i]);
00251       front_steering_joints_[i] = hw_pos->getHandle(front_steering_names[i]);  // throws on failure
00252     }
00253 
00254     if(enable_twist_cmd_ == true)
00255       sub_command_ = controller_nh.subscribe("cmd_vel", 1, &AckermannController::cmdVelCallback, this);
00256     else
00257       sub_command_ackermann_ = controller_nh.subscribe("cmd_ackermann", 1, &AckermannController::cmdAckermannCallback, this);
00258 
00259     return true;
00260   }
00261 
00262   void AckermannController::update(const ros::Time& time, const ros::Duration& period)
00263   {
00264     // COMPUTE AND PUBLISH ODOMETRY
00265     if (open_loop_)
00266     {
00267       odometry_.updateOpenLoop(last0_cmd_.lin, last0_cmd_.ang, time);
00268     }
00269     else
00270     {
00271       double front_pos  = 0.0;
00272       double rear_pos = 0.0;
00273       double front_vel  = 0.0;
00274       double rear_vel = 0.0;
00275       for (size_t i = 0; i < front_wheel_joints_.size(); ++i)
00276       {
00277         const double fp = front_wheel_joints_[i].getPosition();
00278         const double rp = rear_wheel_joints_[i].getPosition();
00279         if (std::isnan(fp) || std::isnan(rp))
00280           return;
00281         front_pos  += fp;
00282         rear_pos += rp;
00283 
00284         const double ls = front_wheel_joints_[i].getVelocity();
00285         const double rs = rear_wheel_joints_[i].getVelocity();
00286         if (std::isnan(ls) || std::isnan(rs))
00287           return;
00288         front_vel  += ls;
00289         rear_vel += rs;
00290       }
00291       front_pos  /= front_wheel_joints_.size();
00292       rear_pos /= front_wheel_joints_.size();
00293       front_vel  /= front_wheel_joints_.size();
00294       rear_vel /= front_wheel_joints_.size();
00295 
00296       double front_left_steering_pos = 0.0, front_right_steering_pos = 0.0;
00297       if (front_steering_joints_.size() == 2)
00298       {
00299         front_left_steering_pos = front_steering_joints_[0].getPosition();
00300         front_right_steering_pos = front_steering_joints_[1].getPosition();
00301       }
00302       double front_steering_pos = 0.0;
00303       if(fabs(front_left_steering_pos) > 0.001 || fabs(front_right_steering_pos) > 0.001)
00304       {
00305         front_steering_pos = atan(2*tan(front_left_steering_pos)*tan(front_right_steering_pos)/
00306                                         (tan(front_left_steering_pos) + tan(front_right_steering_pos)));
00307       }
00308       ROS_DEBUG_STREAM_THROTTLE(1, "front_left_steering_pos "<<front_left_steering_pos<<" front_right_steering_pos "<<front_right_steering_pos<<" front_steering_pos "<<front_steering_pos);
00309       // Estimate linear and angular velocity using joint information
00310       odometry_.update(front_pos, front_vel, rear_pos, rear_vel, front_steering_pos, time);
00311     }
00312 
00313     // Publish odometry message
00314     if (last_state_publish_time_ + publish_period_ < time)
00315     {
00316       last_state_publish_time_ += publish_period_;
00317       // Compute and store orientation info
00318       const geometry_msgs::Quaternion orientation(
00319             tf::createQuaternionMsgFromYaw(odometry_.getHeading()));
00320 
00321       // Populate odom message and publish
00322       if (odom_pub_->trylock())
00323       {
00324         odom_pub_->msg_.header.stamp = time;
00325         odom_pub_->msg_.pose.pose.position.x = odometry_.getX();
00326         odom_pub_->msg_.pose.pose.position.y = odometry_.getY();
00327         odom_pub_->msg_.pose.pose.orientation = orientation;
00328         odom_pub_->msg_.twist.twist.linear.x  = odometry_.getLinear();
00329         odom_pub_->msg_.twist.twist.angular.z = odometry_.getAngular();
00330         odom_pub_->unlockAndPublish();
00331       }
00332 
00333       // Publish tf /odom frame
00334       if (enable_odom_tf_ && tf_odom_pub_->trylock())
00335       {
00336         geometry_msgs::TransformStamped& odom_frame = tf_odom_pub_->msg_.transforms[0];
00337         odom_frame.header.stamp = time;
00338         odom_frame.transform.translation.x = odometry_.getX();
00339         odom_frame.transform.translation.y = odometry_.getY();
00340         odom_frame.transform.rotation = orientation;
00341         tf_odom_pub_->unlockAndPublish();
00342       }
00343     }
00344 
00345     // MOVE ROBOT
00346     // Retreive current velocity command and time step:
00347     Commands curr_cmd;
00348     if(enable_twist_cmd_ == false)
00349       curr_cmd = *(command_ackermann_.readFromRT());
00350     else
00351       curr_cmd = *(command_.readFromRT());
00352 
00353     const double dt = (time - curr_cmd.stamp).toSec();
00354 
00355     // Brake if cmd_vel has timeout:
00356     if (dt > cmd_vel_timeout_)
00357     {
00358       curr_cmd.lin = 0.0;
00359       curr_cmd.ang = 0.0;
00360       curr_cmd.steering = 0.0;
00361     }
00362 
00363     // Limit velocities and accelerations:
00364     const double cmd_dt(period.toSec());
00365 
00366     limiter_lin_.limit(curr_cmd.lin, last0_cmd_.lin, last1_cmd_.lin, cmd_dt);
00367     limiter_ang_.limit(curr_cmd.ang, last0_cmd_.ang, last1_cmd_.ang, cmd_dt);
00368 
00369     last1_cmd_ = last0_cmd_;
00370     last0_cmd_ = curr_cmd;
00371 
00372 
00373     const double angular_speed = odometry_.getAngular();
00374 
00375     ROS_DEBUG_STREAM("angular_speed "<<angular_speed<<" curr_cmd.lin "<<curr_cmd.lin);
00376     // Compute wheels velocities:
00377     // TODO should use angular cmd instead of angular odom and differenciate twist and ackermann cmd
00378     const double vel_left_front  = copysign(1.0, curr_cmd.lin) *
00379                                    sqrt((pow((curr_cmd.lin - angular_speed*track_/2),2)
00380                                          +pow(wheel_base_*angular_speed,2)))/front_wheel_radius_;
00381     const double vel_right_front = copysign(1.0, curr_cmd.lin) *
00382                                    sqrt((pow((curr_cmd.lin + angular_speed*track_/2),2)+
00383                                          pow(wheel_base_*angular_speed,2)))/front_wheel_radius_;
00384     const double vel_left_rear = (curr_cmd.lin - angular_speed*track_/2)/rear_wheel_radius_;
00385     const double vel_right_rear = (curr_cmd.lin + angular_speed*track_/2)/rear_wheel_radius_;
00386     // Set wheels velocities:
00387     if(front_wheel_joints_.size() == 2 && rear_wheel_joints_.size() == 2)
00388     {
00389       front_wheel_joints_[0].setCommand(vel_left_front);
00390       rear_wheel_joints_[0].setCommand(vel_left_rear);
00391       front_wheel_joints_[1].setCommand(vel_right_front);
00392       rear_wheel_joints_[1].setCommand(vel_right_rear);
00393     }
00394 
00395     double front_left_steering = 0, front_right_steering = 0;
00396     if(enable_twist_cmd_ == true)
00397     {
00398       if(fabs(odometry_.getLinear()) > fabs(curr_cmd.ang*track_/2.0))
00399       {
00400         front_left_steering = atan(curr_cmd.ang*wheel_base_ /
00401                                     (odometry_.getLinear() - curr_cmd.ang*track_/2.0));
00402         front_right_steering = atan(curr_cmd.ang*wheel_base_ /
00403                                      (odometry_.getLinear() + curr_cmd.ang*track_/2.0));
00404       }
00405     }
00406     else
00407     {
00408       front_left_steering = atan2(tan(curr_cmd.steering),
00409                                   1 - tan(curr_cmd.steering)*track_/(2*wheel_base_));
00410       front_right_steering = atan2(tan(curr_cmd.steering),
00411                                    1 + tan(curr_cmd.steering)*track_/(2*wheel_base_));
00412     }
00413 
00415     handleSteeringSaturation(front_left_steering, front_right_steering);
00416 
00417     if(front_steering_joints_.size() == 2)
00418     {
00419       ROS_DEBUG_STREAM("front_left_steering "<<front_left_steering<<"front_right_steering "<<front_right_steering);
00420       front_steering_joints_[0].setCommand(front_left_steering);
00421       front_steering_joints_[1].setCommand(front_right_steering);
00422     }
00423   }
00424 
00425   void AckermannController::starting(const ros::Time& time)
00426   {
00427     brake();
00428 
00429     // Register starting time used to keep fixed rate
00430     last_state_publish_time_ = time;
00431 
00432     odometry_.init(time);
00433   }
00434 
00435   void AckermannController::stopping(const ros::Time& /*time*/)
00436   {
00437     brake();
00438   }
00439 
00440   void AckermannController::brake()
00441   {
00442     const double vel = 0.0;
00443     for (size_t i = 0; i < front_wheel_joints_.size(); ++i)
00444     {
00445       front_wheel_joints_[i].setCommand(vel);
00446       rear_wheel_joints_[i].setCommand(vel);
00447     }
00448 
00449     const double pos = 0.0;
00450     for (size_t i = 0; i < front_steering_joints_.size(); ++i)
00451     {
00452       front_steering_joints_[i].setCommand(pos);
00453     }
00454   }
00455 
00456   void AckermannController::cmdVelCallback(const geometry_msgs::Twist& command)
00457   {
00458     if (isRunning())
00459     {
00460       command_struct_.ang   = command.angular.z;
00461       command_struct_.lin   = command.linear.x;
00462       command_struct_.stamp = ros::Time::now();
00463       command_.writeFromNonRT (command_struct_);
00464       ROS_DEBUG_STREAM_NAMED(name_,
00465                              "Added values to command. "
00466                              << "Ang: "   << command_struct_.ang << ", "
00467                              << "Lin: "   << command_struct_.lin << ", "
00468                              << "Stamp: " << command_struct_.stamp);
00469     }
00470     else
00471     {
00472       ROS_ERROR_NAMED(name_, "Can't accept new commands. Controller is not running.");
00473     }
00474   }
00475 
00476   void AckermannController::cmdAckermannCallback(const ackermann_msgs::AckermannDrive& command)
00477   {
00478     if (isRunning())
00479     {
00480       command_struct_ackermann_.steering   = command.steering_angle;
00481       command_struct_ackermann_.lin   = command.speed;
00482       command_struct_ackermann_.stamp = ros::Time::now();
00483       command_ackermann_.writeFromNonRT (command_struct_ackermann_);
00484       ROS_DEBUG_STREAM_NAMED(name_,
00485                              "Added values to command. "
00486                              << "Steering: "   << command_struct_ackermann_.steering << ", "
00487                              << "Lin: "   << command_struct_ackermann_.lin << ", "
00488                              << "Stamp: " << command_struct_ackermann_.stamp);
00489     }
00490     else
00491     {
00492       ROS_ERROR_NAMED(name_, "Can't accept new commands. Controller is not running.");
00493     }
00494   }
00495 
00496   bool AckermannController::getWheelNames(ros::NodeHandle& controller_nh,
00497                               const std::string& wheel_param,
00498                               std::vector<std::string>& wheel_names)
00499   {
00500       XmlRpc::XmlRpcValue wheel_list;
00501       if (!controller_nh.getParam(wheel_param, wheel_list))
00502       {
00503         ROS_ERROR_STREAM_NAMED(name_,
00504             "Couldn't retrieve wheel param '" << wheel_param << "'.");
00505         return false;
00506       }
00507 
00508       if (wheel_list.getType() == XmlRpc::XmlRpcValue::TypeArray)
00509       {
00510         if (wheel_list.size() == 0)
00511         {
00512           ROS_ERROR_STREAM_NAMED(name_,
00513               "Wheel param '" << wheel_param << "' is an empty list");
00514           return false;
00515         }
00516 
00517         for (int i = 0; i < wheel_list.size(); ++i)
00518         {
00519           if (wheel_list[i].getType() != XmlRpc::XmlRpcValue::TypeString)
00520           {
00521             ROS_ERROR_STREAM_NAMED(name_,
00522                 "Wheel param '" << wheel_param << "' #" << i <<
00523                 " isn't a string.");
00524             return false;
00525           }
00526         }
00527 
00528         wheel_names.resize(wheel_list.size());
00529         for (int i = 0; i < wheel_list.size(); ++i)
00530         {
00531           wheel_names[i] = static_cast<std::string>(wheel_list[i]);
00532         }
00533       }
00534       else if (wheel_list.getType() == XmlRpc::XmlRpcValue::TypeString)
00535       {
00536         wheel_names.push_back(wheel_list);
00537       }
00538       else
00539       {
00540         ROS_ERROR_STREAM_NAMED(name_,
00541             "Wheel param '" << wheel_param <<
00542             "' is neither a list of strings nor a string.");
00543         return false;
00544       }
00545 
00546       return true;
00547   }
00548 
00549   void AckermannController::setOdomPubFields(ros::NodeHandle& root_nh, ros::NodeHandle& controller_nh)
00550   {
00551     // Get and check params for covariances
00552     XmlRpc::XmlRpcValue pose_cov_list;
00553     controller_nh.getParam("pose_covariance_diagonal", pose_cov_list);
00554     ROS_ASSERT(pose_cov_list.getType() == XmlRpc::XmlRpcValue::TypeArray);
00555     ROS_ASSERT(pose_cov_list.size() == 6);
00556     for (int i = 0; i < pose_cov_list.size(); ++i)
00557       ROS_ASSERT(pose_cov_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
00558 
00559     XmlRpc::XmlRpcValue twist_cov_list;
00560     controller_nh.getParam("twist_covariance_diagonal", twist_cov_list);
00561     ROS_ASSERT(twist_cov_list.getType() == XmlRpc::XmlRpcValue::TypeArray);
00562     ROS_ASSERT(twist_cov_list.size() == 6);
00563     for (int i = 0; i < twist_cov_list.size(); ++i)
00564       ROS_ASSERT(twist_cov_list[i].getType() == XmlRpc::XmlRpcValue::TypeDouble);
00565 
00566     // Setup odometry realtime publisher + odom message constant fields
00567     odom_pub_.reset(new realtime_tools::RealtimePublisher<nav_msgs::Odometry>(controller_nh, "odom", 100));
00568     odom_pub_->msg_.header.frame_id = "odom";
00569     odom_pub_->msg_.child_frame_id = base_frame_id_;
00570     odom_pub_->msg_.pose.pose.position.z = 0;
00571     odom_pub_->msg_.pose.covariance = boost::assign::list_of
00572         (static_cast<double>(pose_cov_list[0])) (0)  (0)  (0)  (0)  (0)
00573         (0)  (static_cast<double>(pose_cov_list[1])) (0)  (0)  (0)  (0)
00574         (0)  (0)  (static_cast<double>(pose_cov_list[2])) (0)  (0)  (0)
00575         (0)  (0)  (0)  (static_cast<double>(pose_cov_list[3])) (0)  (0)
00576         (0)  (0)  (0)  (0)  (static_cast<double>(pose_cov_list[4])) (0)
00577         (0)  (0)  (0)  (0)  (0)  (static_cast<double>(pose_cov_list[5]));
00578     odom_pub_->msg_.twist.twist.linear.y  = 0;
00579     odom_pub_->msg_.twist.twist.linear.z  = 0;
00580     odom_pub_->msg_.twist.twist.angular.x = 0;
00581     odom_pub_->msg_.twist.twist.angular.y = 0;
00582     odom_pub_->msg_.twist.covariance = boost::assign::list_of
00583         (static_cast<double>(twist_cov_list[0])) (0)  (0)  (0)  (0)  (0)
00584         (0)  (static_cast<double>(twist_cov_list[1])) (0)  (0)  (0)  (0)
00585         (0)  (0)  (static_cast<double>(twist_cov_list[2])) (0)  (0)  (0)
00586         (0)  (0)  (0)  (static_cast<double>(twist_cov_list[3])) (0)  (0)
00587         (0)  (0)  (0)  (0)  (static_cast<double>(twist_cov_list[4])) (0)
00588         (0)  (0)  (0)  (0)  (0)  (static_cast<double>(twist_cov_list[5]));
00589     tf_odom_pub_.reset(new realtime_tools::RealtimePublisher<tf::tfMessage>(root_nh, "/tf", 100));
00590     tf_odom_pub_->msg_.transforms.resize(1);
00591     tf_odom_pub_->msg_.transforms[0].transform.translation.z = 0.0;
00592     tf_odom_pub_->msg_.transforms[0].child_frame_id = base_frame_id_;
00593     tf_odom_pub_->msg_.transforms[0].header.frame_id = "odom";
00594   }
00595 
00596   void AckermannController::handleSteeringSaturation(double &front_left_steering, double &front_right_steering)
00597   {
00598     if(front_left_steering > steering_limit_)
00599     {
00600       front_left_steering = copysign(steering_limit_, front_left_steering);
00601       front_right_steering = atan(wheel_base_/(wheel_base_/tan(front_left_steering) + track_));
00602     }
00603     else if(front_right_steering < -steering_limit_)
00604     {
00605       front_right_steering = copysign(steering_limit_, front_right_steering);
00606       front_left_steering = atan(wheel_base_/(wheel_base_/tan(front_right_steering) - track_));
00607     }
00608   }
00609 
00610 } // namespace ackermann_controller


ackermann_controller
Author(s): Vincent Rousseau
autogenerated on Sat Jun 8 2019 20:06:19