36 #include <sensor_msgs/JointState.h> 37 #include <sensor_msgs/Imu.h> 38 #include <geometry_msgs/Twist.h> 39 #include <std_msgs/Float64.h> 41 #include <nav_msgs/Odometry.h> 42 #include <robotnik_msgs/set_mode.h> 43 #include <robotnik_msgs/get_mode.h> 44 #include <robotnik_msgs/set_odometry.h> 45 #include <robotnik_msgs/ptz.h> 46 #include <gazebo_msgs/ModelState.h> 49 #include "diagnostic_msgs/DiagnosticStatus.h" 56 #define PI 3.1415926535 57 #define SUMMIT_XL_MIN_COMMAND_REC_FREQ 5.0 58 #define SUMMIT_XL_MAX_COMMAND_REC_FREQ 150.0 60 #define SKID_STEERING 1 61 #define MECANUM_STEERING 2 63 #define SUMMIT_XL_WHEEL_DIAMETER 0.25 // Default wheel diameter 64 #define SUMMIT_XL_D_TRACKS_M 1.0 // default equivalent W distance (difference is due to slippage of skid steering) 65 #define SUMMIT_XL_WHEELBASE 0.446 // default real L distance forward to rear axis 66 #define SUMMIT_XL_TRACKWIDTH 0.408 // default real W distance from left wheels to right wheels 237 node_handle_(h), private_node_handle_(
"~"),
239 freq_diag_(
diagnostic_updater::FrequencyStatusParam(&desired_freq_, &desired_freq_, 0.05) ),
244 ROS_INFO(
"summit_xl_robot_control_node - Init ");
248 kinematic_modes_ = 1;
251 if (!private_node_handle_.
getParam(
"model", robot_model_)) {
255 else ROS_INFO(
"Robot Model : %s", robot_model_.c_str());
258 private_node_handle_.
param<std::string>(
"frw_vel_topic", frw_vel_topic_,
"joint_frw_velocity_controller/command");
259 private_node_handle_.
param<std::string>(
"flw_vel_topic", flw_vel_topic_,
"joint_flw_velocity_controller/command");
260 private_node_handle_.
param<std::string>(
"blw_vel_topic", blw_vel_topic_,
"joint_blw_velocity_controller/command");
261 private_node_handle_.
param<std::string>(
"brw_vel_topic", brw_vel_topic_,
"joint_brw_velocity_controller/command");
264 private_node_handle_.
param<std::string>(
"joint_front_right_wheel", joint_front_right_wheel,
"joint_front_right_wheel");
265 private_node_handle_.
param<std::string>(
"joint_front_left_wheel", joint_front_left_wheel,
"joint_front_left_wheel");
266 private_node_handle_.
param<std::string>(
"joint_back_left_wheel", joint_back_left_wheel,
"joint_back_left_wheel");
267 private_node_handle_.
param<std::string>(
"joint_back_right_wheel", joint_back_right_wheel,
"joint_back_right_wheel");
269 if (!private_node_handle_.
getParam(
"summit_xl_wheelbase", summit_xl_wheelbase_))
271 if (!private_node_handle_.
getParam(
"summit_xl_trackwidth", summit_xl_trackwidth_))
275 if ((robot_model_==
"summit_xl_omni") || (robot_model_==
"x_wam")) {
276 kinematic_modes_ = 2;
279 if (robot_model_==
"x_wam") {
280 private_node_handle_.
param<std::string>(
"scissor_pos_topic", scissor_pos_topic_,
"joint_scissor_position_controller/command");
281 private_node_handle_.
param<std::string>(
"scissor_prismatic_joint", scissor_prismatic_joint,
"scissor_prismatic_joint");
286 private_node_handle_.
param<std::string>(
"pan_pos_topic", pan_pos_topic_,
"joint_pan_position_controller/command");
287 private_node_handle_.
param<std::string>(
"tilt_pos_topic", tilt_pos_topic_,
"joint_tilt_position_controller/command");
288 private_node_handle_.
param<std::string>(
"joint_camera_pan", joint_camera_pan,
"joint_camera_pan");
289 private_node_handle_.
param<std::string>(
"joint_camera_tilt", joint_camera_tilt,
"joint_camera_tilt");
292 node_handle_.
param<std::string>(
"odom_topic", odom_topic_,
"/odom");
295 if (!private_node_handle_.
getParam(
"summit_xl_wheel_diameter", summit_xl_wheel_diameter_))
297 if (!private_node_handle_.
getParam(
"summit_xl_d_tracks_m", summit_xl_d_tracks_m_))
300 ROS_INFO(
"summit_xl_wheel_diameter_ = %5.2f", summit_xl_wheel_diameter_);
301 ROS_INFO(
"summit_xl_d_tracks_m_ = %5.2f", summit_xl_d_tracks_m_);
303 private_node_handle_.
param(
"publish_odom_tf", publish_odom_tf_,
true);
304 private_node_handle_.
param(
"publish_odom_msg", publish_odom_msg_,
true);
306 if (publish_odom_tf_)
ROS_INFO(
"PUBLISHING odom->base_footprint tf");
307 else ROS_INFO(
"NOT PUBLISHING odom->base_footprint tf");
309 if (publish_odom_msg_)
ROS_INFO(
"PUBLISHING odom->base_footprint msg");
310 else ROS_INFO(
"NOT PUBLISHING odom->base_footprint msg");
313 linearSpeedXMps_ = 0.0;
314 linearSpeedYMps_ = 0.0;
315 angularSpeedRads_ = 0.0;
318 robot_pose_px_ = 0.0;
319 robot_pose_py_ = 0.0;
320 robot_pose_pa_ = 0.0;
321 robot_pose_vx_ = 0.0;
322 robot_pose_vy_ = 0.0;
333 ang_vel_x_ = 0.0; ang_vel_y_ = 0.0; ang_vel_z_ = 0.0;
334 lin_acc_x_ = 0.0; lin_acc_y_ = 0.0; lin_acc_z_ = 0.0;
335 orientation_x_ = 0.0; orientation_y_ = 0.0; orientation_z_ = 0.0; orientation_w_ = 1.0;
353 ref_vel_frw_ = node_handle_.
advertise<std_msgs::Float64>( frw_vel_topic_, 50);
354 ref_vel_flw_ = node_handle_.
advertise<std_msgs::Float64>( flw_vel_topic_, 50);
355 ref_vel_blw_ = node_handle_.
advertise<std_msgs::Float64>( blw_vel_topic_, 50);
356 ref_vel_brw_ = node_handle_.
advertise<std_msgs::Float64>( brw_vel_topic_, 50);
359 if (robot_model_==
"x_wam") {
360 ref_pos_scissor_ = node_handle_.
advertise<std_msgs::Float64>( scissor_pos_topic_, 50);
363 ref_pos_pan_ = node_handle_.
advertise<std_msgs::Float64>( pan_pos_topic_, 50);
364 ref_pos_tilt_ = node_handle_.
advertise<std_msgs::Float64>( tilt_pos_topic_, 50);
373 odom_pub_ = node_handle_.
advertise<nav_msgs::Odometry>(odom_topic_, 1000);
376 diagnostic_.
setHardwareID(
"summit_xl_robot_control - simulation");
377 diagnostic_.
add( freq_diag_ );
378 diagnostic_.
add( command_freq_ );
380 gazebo_set_model_ = node_handle_.
advertise<gazebo_msgs::ModelState>(
"/gazebo/set_model_state", 1);
388 subs_command_freq->
addTask(&command_freq_);
398 ROS_INFO(
"SummitXLControllerClass::starting");
402 vector<string> joint_names = joint_state_.name;
403 frw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_right_wheel)) - joint_names.begin();
404 flw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_left_wheel)) - joint_names.begin();
405 blw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_left_wheel)) - joint_names.begin();
406 brw_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_right_wheel)) - joint_names.begin();
407 if (robot_model_==
"x_wam") {
408 scissor_pos_ = find (joint_names.begin(),joint_names.end(), string(scissor_prismatic_joint)) - joint_names.begin();
424 double v_left_mps, v_right_mps;
427 v_left_mps = ((joint_state_.velocity[blw_vel_] + joint_state_.velocity[flw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0);
428 v_right_mps = ((joint_state_.velocity[brw_vel_] + joint_state_.velocity[frw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0);
431 linearSpeedXMps_ = (v_right_mps + v_left_mps) / 2.0;
432 angularSpeedRads_ = (v_right_mps - v_left_mps) / summit_xl_d_tracks_m_;
434 std_msgs::Float64 frw_ref_msg;
435 std_msgs::Float64 flw_ref_msg;
436 std_msgs::Float64 blw_ref_msg;
437 std_msgs::Float64 brw_ref_msg;
439 frw_ref_msg.data = (v_ref_x_ + w_ref_* summit_xl_d_tracks_m_/2.0) / (summit_xl_wheel_diameter_ / 2.0);
440 brw_ref_msg.data = (v_ref_x_ + w_ref_* summit_xl_d_tracks_m_/2.0) / (summit_xl_wheel_diameter_ / 2.0);
441 flw_ref_msg.data = (v_ref_x_ - w_ref_* summit_xl_d_tracks_m_/2.0) / (summit_xl_wheel_diameter_ / 2.0);
442 blw_ref_msg.data = (v_ref_x_ - w_ref_* summit_xl_d_tracks_m_/2.0) / (summit_xl_wheel_diameter_ / 2.0);
444 ref_vel_frw_.
publish( frw_ref_msg );
445 ref_vel_flw_.
publish( flw_ref_msg );
446 ref_vel_blw_.
publish( blw_ref_msg );
447 ref_vel_brw_.
publish( brw_ref_msg );
456 double v_frw_mps, v_flw_mps, v_blw_mps, v_brw_mps;
457 v_frw_mps = joint_state_.velocity[frw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
458 v_flw_mps = joint_state_.velocity[flw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
459 v_blw_mps = joint_state_.velocity[blw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
460 v_brw_mps = joint_state_.velocity[brw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
462 double vx = v_ref_x_;
463 double vy = v_ref_y_;
465 double L = summit_xl_wheelbase_;
466 double W = summit_xl_trackwidth_;
469 double q1 = (v_ref_x_ + v_ref_y_ + lab * w_ref_) / (summit_xl_wheel_diameter_ / 2.0);
470 double q2 = (v_ref_x_ - v_ref_y_ - lab * w_ref_) / (summit_xl_wheel_diameter_ / 2.0);
471 double q3 = (v_ref_x_ + v_ref_y_ - lab * w_ref_) / (summit_xl_wheel_diameter_ / 2.0);
472 double q4 = (v_ref_x_ - v_ref_y_ + lab * w_ref_) / (summit_xl_wheel_diameter_ / 2.0);
480 std_msgs::Float64 frw_ref_vel_msg;
481 std_msgs::Float64 flw_ref_vel_msg;
482 std_msgs::Float64 blw_ref_vel_msg;
483 std_msgs::Float64 brw_ref_vel_msg;
485 frw_ref_vel_msg.data = saturation(q1, -limit, limit);
486 flw_ref_vel_msg.data = saturation(q2, -limit, limit);
487 blw_ref_vel_msg.data = saturation(q3, -limit, limit);
488 brw_ref_vel_msg.data = saturation(q4, -limit, limit);
490 ref_vel_frw_.
publish( frw_ref_vel_msg );
491 ref_vel_flw_.
publish( flw_ref_vel_msg );
492 ref_vel_blw_.
publish( blw_ref_vel_msg );
493 ref_vel_brw_.
publish( brw_ref_vel_msg );
497 if (robot_model_ ==
"x_wam") {
499 static double scissor_ref_pos = 0.0;
500 scissor_ref_pos += (v_ref_z_ / desired_freq_);
501 std_msgs::Float64 scissor_ref_pos_msg;
503 scissor_ref_pos_msg.data = saturation(scissor_ref_pos, 0.0, 0.5);
504 ref_pos_scissor_.
publish( scissor_ref_pos_msg );
508 std_msgs::Float64 pan_ref_pos_msg, tilt_ref_pos_msg;
509 pan_ref_pos_msg.data = pos_ref_pan_;
510 ref_pos_pan_.
publish( pan_ref_pos_msg );
511 tilt_ref_pos_msg.data = pos_ref_tilt_;
512 ref_pos_tilt_.
publish( tilt_ref_pos_msg );
523 robot_pose_vx_ = linearSpeedXMps_ * cos(robot_pose_pa_);
524 robot_pose_vy_ = linearSpeedXMps_ * sin(robot_pose_pa_);
531 double v1, v2, v3, v4;
532 v1 = joint_state_.velocity[frw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
533 v2 = joint_state_.velocity[flw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
534 v3 = joint_state_.velocity[blw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
535 v4 = joint_state_.velocity[brw_vel_] * (summit_xl_wheel_diameter_ / 2.0);
539 double vx = (1 / 4.0) * (v1 + v2 + v3 + v4);
540 double vy = (1 / 4.0) * (v1 - v2 + v3 - v4);
541 double wr = (1 / (4.0 * lab)) * (v1 - v2 - v3 + v4);
548 double fSamplePeriod = 1.0 / desired_freq_;
552 double roll, pitch, yaw;
554 robot_pose_pa_ = yaw;
555 robot_pose_px_ += robot_pose_vx_ * fSamplePeriod;
556 robot_pose_py_ += robot_pose_vy_ * fSamplePeriod;
566 geometry_msgs::TransformStamped odom_trans;
567 odom_trans.header.stamp = current_time;
568 odom_trans.header.frame_id =
"odom";
569 odom_trans.child_frame_id =
"base_footprint";
571 odom_trans.transform.translation.x = robot_pose_px_;
572 odom_trans.transform.translation.y = robot_pose_py_;
573 odom_trans.transform.translation.z = 0.0;
574 odom_trans.transform.rotation.x = orientation_x_;
575 odom_trans.transform.rotation.y = orientation_y_;
576 odom_trans.transform.rotation.z = orientation_z_;
577 odom_trans.transform.rotation.w = orientation_w_;
582 if (publish_odom_tf_) {
587 nav_msgs::Odometry odom;
588 odom.header.stamp = current_time;
589 odom.header.frame_id =
"odom";
593 odom.pose.pose.position.x = robot_pose_px_;
594 odom.pose.pose.position.y = robot_pose_py_;
595 odom.pose.pose.position.z = 0.0;
597 odom.pose.pose.orientation.x = orientation_x_;
598 odom.pose.pose.orientation.y = orientation_y_;
599 odom.pose.pose.orientation.z = orientation_z_;
600 odom.pose.pose.orientation.w = orientation_w_;
602 for(
int i = 0; i < 6; i++)
603 odom.pose.covariance[i*6+i] = 0.001;
604 odom.twist.covariance[35] = 0.03;
607 odom.child_frame_id =
"base_footprint";
612 odom.twist.twist.linear.x = linearSpeedXMps_;
613 odom.twist.twist.linear.y = 0;
616 odom.twist.twist.linear.x = robot_pose_vx_;
617 odom.twist.twist.linear.y = robot_pose_vy_;
620 odom.twist.twist.linear.z = 0.0;
622 odom.twist.twist.angular.x = ang_vel_x_;
623 odom.twist.twist.angular.y = ang_vel_y_;
624 odom.twist.twist.angular.z = ang_vel_z_;
626 for(
int i = 0; i < 6; i++)
627 odom.twist.covariance[6*i+i] = 0.001;
628 odom.twist.covariance[35] = 0.03;
631 if (publish_odom_msg_)
654 double diff = (current_time - last_command_time_).toSec();
657 stat.
summary(diagnostic_msgs::DiagnosticStatus::WARN,
"Topic is not receiving commands");
661 stat.
summary(diagnostic_msgs::DiagnosticStatus::OK,
"Topic receiving commands");
669 v_ref_x_ = saturation(cmd_vel.linear.x, -10.0, 10.0);
670 v_ref_y_ = saturation(cmd_vel.linear.y, -10.0, 10.0);
671 w_ref_ = saturation(cmd_vel.angular.z, -10.0, 10.0);
672 v_ref_z_ = saturation(cmd_vel.linear.z, -10.0, 10.0);
677 bool srvCallback_SetMode(robotnik_msgs::set_mode::Request& request, robotnik_msgs::set_mode::Response& response)
684 ROS_INFO(
"SummitXLControllerClass::srvCallback_SetMode request.mode= %d", request.mode);
685 if (request.mode == 1) {
686 active_kinematic_mode_ = request.mode;
689 if (request.mode == 2) {
690 if (kinematic_modes_ == 2) {
691 active_kinematic_mode_ = request.mode;
700 bool srvCallback_GetMode(robotnik_msgs::get_mode::Request& request, robotnik_msgs::get_mode::Response& response)
702 response.mode = active_kinematic_mode_;
710 ROS_INFO(
"summit_xl_odometry::set_odometry: request -> x = %f, y = %f, a = %f", request.x, request.y, request.orientation);
711 robot_pose_px_ = request.x;
712 robot_pose_py_ = request.y;
713 robot_pose_pa_ = request.orientation;
732 subs_command_freq->
tick();
734 base_vel_msg_ = *msg;
735 this->setCommand(base_vel_msg_);
741 pos_ref_pan_ += msg->pan / 180.0 *
PI;
742 pos_ref_tilt_ += msg->tilt / 180.0 *
PI;
748 orientation_x_ = imu_msg.orientation.x;
749 orientation_y_ = imu_msg.orientation.y;
750 orientation_z_ = imu_msg.orientation.z;
751 orientation_w_ = imu_msg.orientation.w;
753 ang_vel_x_ = imu_msg.angular_velocity.x;
754 ang_vel_y_ = imu_msg.angular_velocity.y;
755 ang_vel_z_ = imu_msg.angular_velocity.z;
757 lin_acc_x_ = imu_msg.linear_acceleration.x;
758 lin_acc_y_ = imu_msg.linear_acceleration.y;
759 lin_acc_z_ = imu_msg.linear_acceleration.z;
771 while (value >
PI) value -=
PI;
772 while (value < -
PI) value +=
PI;
778 while (value > 2.0*
PI) value -= 2.0*
PI;
779 while (value < -2.0*
PI) value += 2.0*
PI;
785 ROS_INFO(
"summit_xl_robot_control::spin()");
809 ROS_INFO(
"summit_xl_robot_control::spin() - end");
815 int main(
int argc,
char** argv)
817 ros::init(argc, argv,
"summit_xl_robot_control");
int main(int argc, char **argv)
SummitXLControllerClass(ros::NodeHandle h)
double summit_xl_d_tracks_m_
std::string scissor_prismatic_joint
double radnorm(double value)
#define SUMMIT_XL_MAX_COMMAND_REC_FREQ
ros::Publisher ref_pos_tilt_
ros::NodeHandle node_handle_
std::string blw_pos_topic_
void publish(const boost::shared_ptr< M > &message) const
std::string joint_front_left_wheel
void check_command_subscriber(diagnostic_updater::DiagnosticStatusWrapper &stat)
double summit_xl_wheelbase_
#define SUMMIT_XL_WHEELBASE
void summary(unsigned char lvl, const std::string s)
std::string joint_back_left_wheel
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
tf::TransformBroadcaster odom_broadcaster
std::string scissor_pos_topic_
void setHardwareID(const std::string &hwid)
ros::Time last_command_time_
void jointStateCallback(const sensor_msgs::JointStateConstPtr &msg)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void imuCallback(const sensor_msgs::Imu &imu_msg)
void commandCallback(const geometry_msgs::TwistConstPtr &msg)
void add(const std::string &name, TaskFunction f)
int starting()
Controller startup in realtime.
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
ros::Publisher ref_vel_brw_
ros::Publisher ref_pos_blw_
double saturation(double u, double min, double max)
bool srvCallback_SetOdometry(robotnik_msgs::set_odometry::Request &request, robotnik_msgs::set_odometry::Response &response)
#define SUMMIT_XL_MIN_COMMAND_REC_FREQ
bool srvCallback_SetMode(robotnik_msgs::set_mode::Request &request, robotnik_msgs::set_mode::Response &response)
std::string joint_front_left_steer
double radnorm2(double value)
void command_ptzCallback(const robotnik_msgs::ptzConstPtr &msg)
diagnostic_updater::FunctionDiagnosticTask command_freq_
ros::Subscriber joint_state_sub_
void getRPY(tfScalar &roll, tfScalar &pitch, tfScalar &yaw, unsigned int solution_number=1) const
ros::Publisher ref_vel_blw_
double summit_xl_trackwidth_
bool param(const std::string ¶m_name, T ¶m_val, const T &default_val) const
void UpdateControl()
Controller update loop.
geometry_msgs::Twist base_vel_msg_
bool srvCallback_GetMode(robotnik_msgs::get_mode::Request &request, robotnik_msgs::get_mode::Response &response)
std::string brw_vel_topic_
ros::NodeHandle private_node_handle_
ROSCPP_DECL bool isShuttingDown()
ros::ServiceServer srv_SetMode_
double summit_xl_wheel_diameter_
#define SUMMIT_XL_TRACKWIDTH
std::string frw_pos_topic_
void setCommand(const geometry_msgs::Twist &cmd_vel)
std::string blw_vel_topic_
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
void stopping()
Controller stopping.
std::string joint_back_right_wheel
std::string joint_camera_tilt
ros::Publisher ref_pos_flw_
diagnostic_updater::HeaderlessTopicDiagnostic * subs_command_freq
std::string joint_camera_pan
ros::Publisher ref_pos_scissor_
ros::Publisher ref_vel_frw_
TFSIMD_FORCE_INLINE const tfScalar & w() const
ros::ServiceServer srv_SetOdometry_
std::string frw_vel_topic_
std::string brw_pos_topic_
std::string pan_pos_topic_
sensor_msgs::JointState joint_state_
bool getParam(const std::string &key, std::string &s) const
std::string joint_back_left_steer
ros::ServiceServer srv_GetMode_
int active_kinematic_mode_
diagnostic_updater::FrequencyStatus freq_diag_
ros::Publisher gazebo_set_model_
std::string joint_front_right_steer
std::string flw_pos_topic_
#define SUMMIT_XL_WHEEL_DIAMETER
ros::Publisher ref_pos_pan_
ROSCPP_DECL void spinOnce()
std::string tilt_pos_topic_
ros::Publisher ref_vel_flw_
diagnostic_updater::Updater diagnostic_
std::string joint_back_right_steer
ros::Publisher ref_pos_frw_
#define SUMMIT_XL_D_TRACKS_M
ros::Publisher ref_pos_brw_
std::string joint_front_right_wheel
std::string flw_vel_topic_
void addTask(DiagnosticTask *t)