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
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
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
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
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
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
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
00224
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
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]);
00243 rear_wheel_joints_[i] = hw_vel->getHandle(rear_wheel_names[i]);
00244 }
00245
00246
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]);
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
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
00310 odometry_.update(front_pos, front_vel, rear_pos, rear_vel, front_steering_pos, time);
00311 }
00312
00313
00314 if (last_state_publish_time_ + publish_period_ < time)
00315 {
00316 last_state_publish_time_ += publish_period_;
00317
00318 const geometry_msgs::Quaternion orientation(
00319 tf::createQuaternionMsgFromYaw(odometry_.getHeading()));
00320
00321
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
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
00346
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
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
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
00377
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
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
00430 last_state_publish_time_ = time;
00431
00432 odometry_.init(time);
00433 }
00434
00435 void AckermannController::stopping(const ros::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
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
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 }