41 #include <urdf_parser/urdf_parser.h> 43 #include <boost/assign.hpp> 58 ROS_ERROR_STREAM(
"Link " << link->name <<
" does not have collision description. Add collision description for link to urdf.");
62 if(!link->collision->geometry)
64 ROS_ERROR_STREAM(
"Link " << link->name <<
" does not have collision geometry description. Add collision geometry description for link to urdf.");
68 if(link->collision->geometry->type != urdf::Geometry::CYLINDER && link->collision->geometry->type != urdf::Geometry::SPHERE)
70 ROS_ERROR_STREAM(
"Link " << link->name <<
" does not have cylinder nor sphere geometry");
84 , use_realigned_roller_joints_(false)
87 , cmd_vel_timeout_(0.5)
88 , base_frame_id_(
"base_link")
89 , odom_frame_id_(
"odom")
90 , enable_odom_tf_(true)
91 , wheel_joints_size_(0)
101 const std::string complete_ns = controller_nh.
getNamespace();
102 std::size_t
id = complete_ns.find_last_of(
"/");
103 name_ = complete_ns.substr(
id + 1);
110 std::string wheel0_name;
111 controller_nh.
param(
"front_left_wheel_joint", wheel0_name, wheel0_name);
114 std::string wheel1_name;
115 controller_nh.
param(
"back_left_wheel_joint", wheel1_name, wheel1_name);
118 std::string wheel2_name;
119 controller_nh.
param(
"back_right_wheel_joint", wheel2_name, wheel2_name);
122 std::string wheel3_name;
123 controller_nh.
param(
"front_right_wheel_joint", wheel3_name, wheel3_name);
128 controller_nh.
param(
"publish_rate", publish_rate, 50.0);
130 << publish_rate <<
"Hz.");
204 if (std::isnan(wheel0_vel) || std::isnan(wheel1_vel) || std::isnan(wheel2_vel) || std::isnan(wheel3_vel))
208 odometry_.
update(wheel0_vel, wheel1_vel, wheel2_vel, wheel3_vel, time);
216 const geometry_msgs::Quaternion orientation(
225 odom_pub_->msg_.pose.pose.orientation = orientation;
235 geometry_msgs::TransformStamped& odom_frame =
tf_odom_pub_->msg_.transforms[0];
236 odom_frame.header.stamp = time;
239 odom_frame.transform.rotation = orientation;
247 const double dt = (time - curr_cmd.
stamp).toSec();
258 const double cmd_dt(period.
toSec());
315 "Added values to command. " 330 const std::string& wheel0_name,
331 const std::string& wheel1_name,
332 const std::string& wheel2_name,
333 const std::string& wheel3_name)
339 if (has_wheel_separation_x != has_wheel_separation_y)
345 bool lookup_wheel_separation = !(has_wheel_separation_x && has_wheel_separation_y);
349 if (lookup_wheel_separation || lookup_wheel_radius)
352 const std::string model_param_name =
"robot_description";
353 bool res = root_nh.
hasParam(model_param_name);
354 std::string robot_model_str=
"";
355 if(!res || !root_nh.
getParam(model_param_name,robot_model_str))
361 urdf::ModelInterfaceSharedPtr model(urdf::parseURDF(robot_model_str));
364 urdf::JointConstSharedPtr wheel0_urdfJoint(model->getJoint(wheel0_name));
365 if(!wheel0_urdfJoint)
368 <<
" couldn't be retrieved from model description");
371 urdf::JointConstSharedPtr wheel1_urdfJoint(model->getJoint(wheel1_name));
372 if(!wheel1_urdfJoint)
375 <<
" couldn't be retrieved from model description");
378 urdf::JointConstSharedPtr wheel2_urdfJoint(model->getJoint(wheel2_name));
379 if(!wheel2_urdfJoint)
382 <<
" couldn't be retrieved from model description");
385 urdf::JointConstSharedPtr wheel3_urdfJoint(model->getJoint(wheel3_name));
386 if(!wheel3_urdfJoint)
389 <<
" couldn't be retrieved from model description");
393 if (lookup_wheel_separation)
395 ROS_INFO_STREAM(
"wheel0 to origin: " << wheel0_urdfJoint->parent_to_joint_origin_transform.position.x <<
"," 396 << wheel0_urdfJoint->parent_to_joint_origin_transform.position.y <<
", " 397 << wheel0_urdfJoint->parent_to_joint_origin_transform.position.z);
398 ROS_INFO_STREAM(
"wheel1 to origin: " << wheel1_urdfJoint->parent_to_joint_origin_transform.position.x <<
"," 399 << wheel1_urdfJoint->parent_to_joint_origin_transform.position.y <<
", " 400 << wheel1_urdfJoint->parent_to_joint_origin_transform.position.z);
401 ROS_INFO_STREAM(
"wheel2 to origin: " << wheel2_urdfJoint->parent_to_joint_origin_transform.position.x <<
"," 402 << wheel2_urdfJoint->parent_to_joint_origin_transform.position.y <<
", " 403 << wheel2_urdfJoint->parent_to_joint_origin_transform.position.z);
404 ROS_INFO_STREAM(
"wheel3 to origin: " << wheel3_urdfJoint->parent_to_joint_origin_transform.position.x <<
"," 405 << wheel3_urdfJoint->parent_to_joint_origin_transform.position.y <<
", " 406 << wheel3_urdfJoint->parent_to_joint_origin_transform.position.z);
408 double wheel0_x = wheel0_urdfJoint->parent_to_joint_origin_transform.position.x;
409 double wheel0_y = wheel0_urdfJoint->parent_to_joint_origin_transform.position.y;
410 double wheel1_x = wheel1_urdfJoint->parent_to_joint_origin_transform.position.x;
411 double wheel1_y = wheel1_urdfJoint->parent_to_joint_origin_transform.position.y;
412 double wheel2_x = wheel2_urdfJoint->parent_to_joint_origin_transform.position.x;
413 double wheel2_y = wheel2_urdfJoint->parent_to_joint_origin_transform.position.y;
414 double wheel3_x = wheel3_urdfJoint->parent_to_joint_origin_transform.position.x;
415 double wheel3_y = wheel3_urdfJoint->parent_to_joint_origin_transform.position.y;
417 wheels_k_ = (-(-wheel0_x - wheel0_y) - (wheel1_x - wheel1_y) + (-wheel2_x - wheel2_y) + (wheel3_x - wheel3_y))
430 if (lookup_wheel_radius)
433 double wheel0_radius = 0.0;
434 double wheel1_radius = 0.0;
435 double wheel2_radius = 0.0;
436 double wheel3_radius = 0.0;
438 if (!
getWheelRadius(model, model->getLink(wheel0_urdfJoint->child_link_name), wheel0_radius) ||
439 !
getWheelRadius(model, model->getLink(wheel1_urdfJoint->child_link_name), wheel1_radius) ||
440 !
getWheelRadius(model, model->getLink(wheel2_urdfJoint->child_link_name), wheel2_radius) ||
441 !
getWheelRadius(model, model->getLink(wheel3_urdfJoint->child_link_name), wheel3_radius))
447 if (
abs(wheel0_radius - wheel1_radius) > 1e-3 ||
448 abs(wheel0_radius - wheel2_radius) > 1e-3 ||
449 abs(wheel0_radius - wheel3_radius) > 1e-3)
469 const urdf::LinkConstSharedPtr& wheel_link,
double& wheel_radius)
471 urdf::LinkConstSharedPtr radius_link = wheel_link;
476 const urdf::JointConstSharedPtr& roller_joint = radius_link->child_joints[0];
480 ". Are you sure mecanum wheels are simulated using realigned rollers?");
484 radius_link = model->getLink(roller_joint->child_link_name);
488 ". Are you sure mecanum wheels are simulated using realigned rollers?");
495 ROS_ERROR_STREAM(
"Wheel link " << radius_link->name <<
" is NOT modeled as a cylinder!");
499 if (radius_link->collision->geometry->type == urdf::Geometry::CYLINDER)
500 wheel_radius = (
static_cast<urdf::Cylinder*
>(radius_link->collision->geometry.get()))->radius;
502 wheel_radius = (
static_cast<urdf::Sphere*
>(radius_link->collision->geometry.get()))->radius;
512 controller_nh.
getParam(
"pose_covariance_diagonal", pose_cov_list);
515 for (
int i = 0; i < pose_cov_list.
size(); ++i)
519 controller_nh.
getParam(
"twist_covariance_diagonal", twist_cov_list);
522 for (
int i = 0; i < twist_cov_list.
size(); ++i)
529 odom_pub_->msg_.pose.pose.position.z = 0;
530 odom_pub_->msg_.pose.covariance = boost::assign::list_of
531 (static_cast<double>(pose_cov_list[0])) (0) (0) (0) (0) (0)
532 (0) (
static_cast<double>(pose_cov_list[1])) (0) (0) (0) (0)
533 (0) (0) (
static_cast<double>(pose_cov_list[2])) (0) (0) (0)
534 (0) (0) (0) (
static_cast<double>(pose_cov_list[3])) (0) (0)
535 (0) (0) (0) (0) (
static_cast<double>(pose_cov_list[4])) (0)
536 (0) (0) (0) (0) (0) (
static_cast<double>(pose_cov_list[5]));
537 odom_pub_->msg_.twist.twist.linear.y = 0;
538 odom_pub_->msg_.twist.twist.linear.z = 0;
539 odom_pub_->msg_.twist.twist.angular.x = 0;
540 odom_pub_->msg_.twist.twist.angular.y = 0;
541 odom_pub_->msg_.twist.covariance = boost::assign::list_of
542 (static_cast<double>(twist_cov_list[0])) (0) (0) (0) (0) (0)
543 (0) (
static_cast<double>(twist_cov_list[1])) (0) (0) (0) (0)
544 (0) (0) (
static_cast<double>(twist_cov_list[2])) (0) (0) (0)
545 (0) (0) (0) (
static_cast<double>(twist_cov_list[3])) (0) (0)
546 (0) (0) (0) (0) (
static_cast<double>(twist_cov_list[4])) (0)
547 (0) (0) (0) (0) (0) (
static_cast<double>(twist_cov_list[5]));
552 tf_odom_pub_->msg_.transforms[0].transform.translation.z = 0.0;
ros::Duration publish_period_
Odometry related:
void setWheelsParams(double wheels_k, double wheels_radius)
Sets the wheels parameters: mecanum geometric param and radius.
void limit(double &v, double v0, double dt)
Limit the velocity and acceleration.
double getLinearX() const
linearX velocity getter
double cmd_vel_timeout_
Timeout to consider cmd_vel commands old:
ros::Subscriber sub_command_
hardware_interface::JointHandle wheel1_jointHandle_
#define ROS_DEBUG_STREAM_NAMED(name, args)
void update(const ros::Time &time, const ros::Duration &period)
Updates controller, i.e. computes the odometry and sets the new velocity commands.
#define ROS_ERROR_STREAM_NAMED(name, args)
realtime_tools::RealtimeBuffer< Commands > command_
bool getWheelRadius(const urdf::ModelInterfaceSharedPtr model, const urdf::LinkConstSharedPtr &wheel_link, double &wheel_radius)
Get the radius of a given wheel.
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
void brake()
Brakes the wheels, i.e. sets the velocity to 0.
ros::Time last_state_publish_time_
boost::shared_ptr< realtime_tools::RealtimePublisher< tf::tfMessage > > tf_odom_pub_
std::string odom_frame_id_
#define ROS_INFO_STREAM_NAMED(name, args)
void starting(const ros::Time &time)
Starts controller.
Type const & getType() const
double getY() const
y position getter
hardware_interface::JointHandle wheel3_jointHandle_
double getLinearY() const
linearY velocity getter
void setupRtPublishersMsg(ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh)
Sets the odometry publishing fields.
hardware_interface::JointHandle wheel2_jointHandle_
bool setWheelParamsFromUrdf(ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh, const std::string &wheel0_name, const std::string &wheel1_name, const std::string &wheel2_name, const std::string &wheel3_name)
Sets odometry parameters from the URDF, i.e. the wheel radius and separation.
double wheel_separation_x_
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
static bool isCylinderOrSphere(const urdf::LinkConstSharedPtr &link)
void updateOpenLoop(double linearX, double linearY, double angular, const ros::Time &time)
Updates the odometry class with latest velocity command.
const std::string & getNamespace() const
boost::shared_ptr< realtime_tools::RealtimePublisher< nav_msgs::Odometry > > odom_pub_
Odometry related:
double getAngular() const
angular velocity getter
double getHeading() const
heading getter
void stopping(const ros::Time &time)
Stops controller.
bool has_acceleration_limits
void init(const ros::Time &time)
Initialize the odometry.
double getVelocity() const
bool use_realigned_roller_joints_
Wheel radius (assuming it's the same for the left and right wheels):
void cmdVelCallback(const geometry_msgs::Twist &command)
Velocity command callback.
bool init(hardware_interface::VelocityJointInterface *hw, ros::NodeHandle &root_nh, ros::NodeHandle &controller_nh)
Initialize controller.
JointHandle getHandle(const std::string &name)
hardware_interface::JointHandle wheel0_jointHandle_
Hardware handles:
SpeedLimiter limiter_ang_
void setCommand(double command)
static geometry_msgs::Quaternion createQuaternionMsgFromYaw(double yaw)
#define ROS_INFO_STREAM(args)
Velocity command related:
INLINE Rall1d< T, V, S > abs(const Rall1d< T, V, S > &x)
SpeedLimiter limiter_linY_
std::string base_frame_id_
Frame to use for the robot base:
bool getParam(const std::string &key, std::string &s) const
#define ROS_ERROR_NAMED(name,...)
double getX() const
x position getter
double wheel_separation_y_
bool hasParam(const std::string &key) const
bool update(double wheel0_vel, double wheel1_vel, double wheel2_vel, double wheel3_vel, const ros::Time &time)
Updates the odometry class with latest wheels position.
#define ROS_ERROR_STREAM(args)
bool enable_odom_tf_
Whether to publish odometry to tf or not:
SpeedLimiter limiter_linX_