agvs_robot_control.cpp
Go to the documentation of this file.
1 /*
2  * agvs_robot_control
3  * Copyright (c) 2014, Robotnik Automation, SLL
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are met:
8  *
9  * * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * * Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  * * Neither the name of the Robotnik Automation, SLL. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *
30  * \author Robotnik
31  * \brief Controller for the AGVS robot Ackerman Drive
32  * \brief (will include dual odometry measurement)
33  */
34 
35 #include <ros/ros.h>
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 
47 #include "ackermann_msgs/AckermannDriveStamped.h"
48 
49 #include "diagnostic_msgs/DiagnosticStatus.h"
54 #include <std_srvs/Empty.h>
55 
56 
57 #define PI 3.1415926535
58 #define AGVS_MIN_COMMAND_REC_FREQ 5.0
59 #define AGVS_MAX_COMMAND_REC_FREQ 150.0
60 
61 #define AGVS_WHEEL_DIAMETER 0.2195 // Default wheel diameter
62 #define DEFAULT_DIST_CENTER_TO_WHEEL 0.479 // Default distance center to motorwheel
63 
64 #define MAX_ELEVATOR_POSITION 0.05 // meters
65 
66 using namespace std;
67 
69 
70 public:
71 
74  double desired_freq_;
75 
76  // Diagnostics
77  diagnostic_updater::Updater diagnostic_; // General status diagnostic updater
78  diagnostic_updater::FrequencyStatus freq_diag_; // Component frequency diagnostics
79  diagnostic_updater::HeaderlessTopicDiagnostic *subs_command_freq; // Topic reception frequency diagnostics
80  ros::Time last_command_time_; // Last moment when the component received a command
82 
83  // Robot model
84  std::string robot_model_;
85 
86  // Velocity and position references to low level controllers
92 
93  // Joint states published by the joint_state_controller of the Controller Manager
95 
96  // High level robot command
98 
99  // Services
105 
106  // Topics - Ackerman - velocity
107  std::string fwd_vel_topic_;
108  std::string bwd_vel_topic_;
109 
110  // Joint names - Ackerman - velocity
111  std::string joint_front_wheel;
112  std::string joint_back_wheel;
113 
114  // Topics - Ackerman - position
115  std::string fwd_pos_topic_;
116  std::string bwd_pos_topic_;
117  std::string elevator_pos_topic_;
118 
119  std::string imu_topic_;
120 
121  // Joint names - Ackerman - position
124 
125  // Indexes to joint_states
126  int fwd_vel_, bwd_vel_;
127  int fwd_pos_, bwd_pos_;
128 
129  // Robot Speeds
133 
134  // Robot Positions
140 
141  // Robot Joint States
142  sensor_msgs::JointState joint_state_;
143 
144  // Command reference
145  // geometry_msgs::Twist base_vel_msg_;
146  ackermann_msgs::AckermannDriveStamped base_vel_msg_;
147 
148  // External references
149  double v_ref_;
150  double a_ref_;
151 
152  double v_mps_; // Measured real robot speed traction wheel speed
153 
154  // Flag to indicate if joint_state has been read
155  bool read_state_;
156 
157  // Robot configuration parameters
160 
161  // IMU values
162  double ang_vel_x_;
163  double ang_vel_y_;
164  double ang_vel_z_;
165 
166  double lin_acc_x_;
167  double lin_acc_y_;
168  double lin_acc_z_;
169 
174 
175  // Parameter that defines if odom tf is published or not
177 
179 
180  // Publisher for odom topic
182 
183  // Broadcaster for odom tf
185 
186 
191  node_handle_(h), private_node_handle_("~"),
192  desired_freq_(100.0),
193  freq_diag_(diagnostic_updater::FrequencyStatusParam(&desired_freq_, &desired_freq_, 0.05) ),
194  command_freq_("Command frequency check", boost::bind(&AGVSControllerClass::check_command_subscriber, this, _1))
195  {
196 
197  ROS_INFO("agvs_robot_control_node - Init ");
198 
199  ros::NodeHandle agvs_robot_control_node_handle(node_handle_, "agvs_robot_control");
200 
201  // Get robot model from the parameters
202  if (!private_node_handle_.getParam("model", robot_model_)) {
203  ROS_ERROR("Robot model not defined.");
204  exit(-1);
205  }
206  else ROS_INFO("Robot Model : %s", robot_model_.c_str());
207 
208  // Ackerman configuration - topics (control actions)
209  private_node_handle_.param<std::string>("fwd_vel_topic", fwd_vel_topic_, "/agvs/joint_front_wheel_controller/command");
210  private_node_handle_.param<std::string>("bwd_vel_topic", bwd_vel_topic_, "/agvs/joint_back_wheel_controller/command");
211  private_node_handle_.param<std::string>("fwd_pos_topic", fwd_pos_topic_, "/agvs/joint_front_motor_wheel_controller/command");
212  private_node_handle_.param<std::string>("bwd_pos_topic", bwd_pos_topic_, "/agvs/joint_back_motor_wheel_controller/command");
213  private_node_handle_.param<std::string>("elevator_pos_topic", elevator_pos_topic_, "/agvs/joint_elevator_controller/command");
214  private_node_handle_.param<std::string>("imu_topic", imu_topic_, "/agvs/imu_data");
215 
216  // Ackerman configuration - joint names
217  private_node_handle_.param<std::string>("joint_front_wheel", joint_front_wheel, "joint_front_wheel");
218  private_node_handle_.param<std::string>("joint_back_wheel", joint_back_wheel, "joint_back_wheel");
219  private_node_handle_.param<std::string>("joint_front_motor_wheel", joint_front_motor_wheel, "joint_front_motor_wheel");
220  private_node_handle_.param<std::string>("joint_back_motor_wheel", joint_back_motor_wheel, "joint_back_motor_wheel");
221 
222  // Robot kinematic parameters
223  if (!private_node_handle_.getParam("agvs_wheel_diameter", agvs_wheel_diameter_))
224  agvs_wheel_diameter_ = AGVS_WHEEL_DIAMETER;
225  if (!private_node_handle_.getParam("agvs_dist_to_center", agvs_dist_to_center_))
226  agvs_dist_to_center_ = DEFAULT_DIST_CENTER_TO_WHEEL;
227  //ROS_INFO("agvs_wheel_diameter_ = %5.2f", agvs_wheel_diameter_);
228  //ROS_INFO("agvs_dist_to_center_ = %5.2f", agvs_dist_to_center_);
229 
230  private_node_handle_.param("publish_odom_tf", publish_odom_tf_, true);
231  if (publish_odom_tf_) ROS_INFO("PUBLISHING odom->base_footprint tf");
232  else ROS_INFO("NOT PUBLISHING odom->base_footprint tf");
233 
234  // Robot Speeds
235  linearSpeedXMps_ = 0.0;
236  linearSpeedYMps_ = 0.0;
237  angularSpeedRads_ = 0.0;
238 
239  // Robot Positions
240  robot_pose_px_ = 0.0;
241  robot_pose_py_ = 0.0;
242  robot_pose_pa_ = 0.0;
243  robot_pose_vx_ = 0.0;
244  robot_pose_vy_ = 0.0;
245 
246  // External speed references
247  v_ref_ = 0.0;
248  a_ref_ = 0.0;
249 
250  // Imu variables
251  ang_vel_x_ = 0.0; ang_vel_y_ = 0.0; ang_vel_z_ = 0.0;
252  lin_acc_x_ = 0.0; lin_acc_y_ = 0.0; lin_acc_z_ = 0.0;
253  orientation_diff_x_ = 0.0; orientation_diff_y_ = 0.0; orientation_diff_z_ = 0.0; orientation_diff_w_ = 1.0;
254 
255  // Advertise services
256  srv_SetOdometry_ = private_node_handle_.advertiseService("set_odometry", &AGVSControllerClass::srvCallback_SetOdometry, this);
257  srv_RaiseElevator_ = private_node_handle_.advertiseService("raise_elevator", &AGVSControllerClass::srvCallback_RaiseElevator, this);
258  srv_LowerElevator_ = private_node_handle_.advertiseService("lower_elevator", &AGVSControllerClass::srvCallback_LowerElevator, this);
259 
260  // Subscribe to joint states topic
261  joint_state_sub_ = agvs_robot_control_node_handle.subscribe<sensor_msgs::JointState>("/agvs/joint_states", 1, &AGVSControllerClass::jointStateCallback, this);
262  //joint_state_sub_ = private_node_handle_.subscribe<sensor_msgs::JointState>("joint_states", 1, &AGVSControllerClass::jointStateCallback, this);
263  //joint_state_sub_ = summit_xl_robot_control_node_handle.subscribe<sensor_msgs::JointState>("/summit_xl/joint_states", 1, &SummitXLControllerClass::jointStateCallback, this);
264 
265 
266  // Subscribe to imu data
267  // imu_sub_ = agvs_robot_control_node_handle.subscribe("/agvs/imu_data", 1, &AGVSControllerClass::imuCallback, this);
268  imu_sub_ = private_node_handle_.subscribe(imu_topic_, 1, &AGVSControllerClass::imuCallback, this);
269 
270  // Adevertise reference topics for the controllers
271  ref_vel_fwd_ = private_node_handle_.advertise<std_msgs::Float64>( fwd_vel_topic_, 50);
272  ref_vel_bwd_ = private_node_handle_.advertise<std_msgs::Float64>( bwd_vel_topic_, 50);
273  ref_pos_fwd_ = private_node_handle_.advertise<std_msgs::Float64>( fwd_pos_topic_, 50);
274  ref_pos_bwd_ = private_node_handle_.advertise<std_msgs::Float64>( bwd_pos_topic_, 50);
275  ref_pos_elevator_ = private_node_handle_.advertise<std_msgs::Float64>( elevator_pos_topic_, 50);
276 
277  // Subscribe to command topic
278  cmd_sub_ = private_node_handle_.subscribe<ackermann_msgs::AckermannDriveStamped>("command", 1, &AGVSControllerClass::commandCallback, this );
279 
280  // TODO odom topic as parameter
281  // Publish odometry
282  odom_pub_ = private_node_handle_.advertise<nav_msgs::Odometry>("odom", 1000);
283 
284  // Component frequency diagnostics
285  diagnostic_.setHardwareID("agvs_robot_control - simulation");
286  diagnostic_.add( freq_diag_ );
287  diagnostic_.add( command_freq_ );
288 
289  // Topics freq control
290  // For /agvs_robot_control/command
291  double min_freq = AGVS_MIN_COMMAND_REC_FREQ; // If you update these values, the
292  double max_freq = AGVS_MAX_COMMAND_REC_FREQ; // HeaderlessTopicDiagnostic will use the new values.
293  subs_command_freq = new diagnostic_updater::HeaderlessTopicDiagnostic("/agvs_robot_control/command", diagnostic_,
294  diagnostic_updater::FrequencyStatusParam(&min_freq, &max_freq, 0.1, 10));
295  subs_command_freq->addTask(&command_freq_); // Adding an additional task to the control
296 
297  // Flag to indicate joint_state has been read
298  read_state_ = false;
299 
300  // Robot ackermann measured speed.
301  v_mps_ = 0;
302 }
303 
305 int starting()
306 {
307 
308  ROS_INFO("AGVSControllerClass::starting");
309 
310 // name: ['joint_back_motor_wheel', 'joint_back_wheel', 'joint_front_motor_wheel', 'joint_front_wheel']
311 // position: [6.283185307179586, -3.14159, 6.283185307179586, -3.14159]
312 // velocity: [nan, nan, nan, nan]
313 
314  // Initialize joint indexes according to joint names
315  if (read_state_) {
316  vector<string> joint_names = joint_state_.name;
317  fwd_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_front_wheel)) - joint_names.begin();
318  bwd_vel_ = find (joint_names.begin(),joint_names.end(), string(joint_back_wheel)) - joint_names.begin();
319  fwd_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_front_motor_wheel)) - joint_names.begin();
320  bwd_pos_ = find (joint_names.begin(),joint_names.end(), string(joint_back_motor_wheel)) - joint_names.begin();
321  return 0;
322  }
323  else return -1;
324 }
325 
331 
332  // TODO UpdateOdometry differential drive
333 
334  // double v_left_mps, v_right_mps;
335  // Calculate its own velocities for realize the motor control
336  // v_left_mps = ((joint_state_.velocity[blw_vel_] + joint_state_.velocity[flw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0);
337  // v_right_mps = -((joint_state_.velocity[brw_vel_] + joint_state_.velocity[frw_vel_]) / 2.0) * (summit_xl_wheel_diameter_ / 2.0);
338  // sign according to urdf (if wheel model is not symetric, should be inverted)
339  // angularSpeedRads_ = (v_right_mps - v_left_mps) / summit_xl_d_tracks_m_; // rad/s
340 
341 
342  double fBetaRads = 0.0;
343  double v_mps = 0.0;
344 
345  // Compute Position
346  double fSamplePeriod = 1.0 / desired_freq_;
347 
348  // Linear speed of each wheel
349  double v_fwd, v_bwd;
350  v_fwd = joint_state_.velocity[fwd_vel_] * (agvs_wheel_diameter_ / 2.0);
351  v_bwd = joint_state_.velocity[bwd_vel_] * (agvs_wheel_diameter_ / 2.0);
352  //ROS_INFO("v_fwd = %.3lf, v_bwd = %.3lf", v_fwd, v_bwd);
353  v_mps = -(v_fwd + v_bwd) / 2.0;
354 
355  // Angle of fwd and bwd motorwheels
356  double a_fwd, a_bwd;
357  a_fwd = radnorm2( joint_state_.position[fwd_pos_] );
358  a_bwd = radnorm2( joint_state_.position[bwd_pos_] );
359  fBetaRads = a_fwd; // consider to get a mean, but both angles are antisimetric
360 
361  // Filter noise
362  if(fabs(v_mps) < 0.00001) v_mps = 0.0;
363 
364  // Compute Odometry
365  double w = (v_mps / agvs_dist_to_center_) * sin(fBetaRads);
366  robot_pose_pa_ += w * fSamplePeriod;
367 
368  // normalize
369  radnorm(&robot_pose_pa_);
370  //ROS_INFO("Orientation = %.3lf", robot_pose_pa_);
371  // Velocities
372  robot_pose_vx_ = v_mps * cos(fBetaRads) * cos(robot_pose_pa_);
373  robot_pose_vy_ = v_mps * cos(fBetaRads) * sin(robot_pose_pa_);
374 
375  // Positions
376  robot_pose_px_ += robot_pose_vx_ * fSamplePeriod;
377  robot_pose_py_ += robot_pose_vy_ * fSamplePeriod;
378 }
379 
380 // Publish robot odometry tf and topic depending
382 {
383  ros::Time current_time = ros::Time::now();
384 
385  //first, we'll publish the transform over tf
386  geometry_msgs::TransformStamped odom_trans;
387  odom_trans.header.stamp = current_time;
388  odom_trans.header.frame_id = "odom";
389  odom_trans.child_frame_id = "base_footprint";
390 
391  odom_trans.transform.translation.x = robot_pose_px_;
392  odom_trans.transform.translation.y = robot_pose_py_;
393  odom_trans.transform.translation.z = 0.0;
394 
395  // Convert theta from yaw (rads) to quaternion. note that this is only 2D !!!
396  double theta = robot_pose_pa_;
397  geometry_msgs::Quaternion quat = tf::createQuaternionMsgFromYaw( theta );
398  odom_trans.transform.rotation.x = quat.x;
399  odom_trans.transform.rotation.y = quat.y;
400  odom_trans.transform.rotation.z = quat.z;
401  odom_trans.transform.rotation.w = quat.w;
402 
403 
404  // send the transform over /tf
405  // activate / deactivate with param
406  // this tf in needed when not using robot_pose_ekf
407  if (publish_odom_tf_) odom_broadcaster.sendTransform(odom_trans);
408 
409  //next, we'll publish the odometry message over ROS
410  nav_msgs::Odometry odom;
411  odom.header.stamp = current_time;
412  odom.header.frame_id = "odom";
413 
414  //set the position
415  // Position
416  odom.pose.pose.position.x = robot_pose_px_;
417  odom.pose.pose.position.y = robot_pose_py_;
418  odom.pose.pose.position.z = 0.0;
419  // Orientation
420  odom.pose.pose.orientation.x = orientation_diff_x_;
421  odom.pose.pose.orientation.y = orientation_diff_y_;
422  odom.pose.pose.orientation.z = orientation_diff_z_;
423  odom.pose.pose.orientation.w = orientation_diff_w_;
424 
425  // Pose covariance
426  for(int i = 0; i < 6; i++)
427  odom.pose.covariance[i*6+i] = 0.1; // test 0.001
428 
429  //set the velocity
430  odom.child_frame_id = "base_footprint";
431  // Linear velocities
432  odom.twist.twist.linear.x = robot_pose_vx_;
433  odom.twist.twist.linear.y = robot_pose_vy_;
434  odom.twist.twist.linear.z = 0.0;
435  // Angular velocities
436  odom.twist.twist.angular.x = ang_vel_x_;
437  odom.twist.twist.angular.y = ang_vel_y_;
438  odom.twist.twist.angular.z = ang_vel_z_;
439  // Twist covariance
440  for(int i = 0; i < 6; i++)
441  odom.twist.covariance[6*i+i] = 0.1; // test 0.001
442 
443  //publish the message
444  odom_pub_.publish(odom);
445 }
446 
448 {
449  // Ackerman reference messages
450  std_msgs::Float64 vel_ref_msg;
451  std_msgs::Float64 pos_ref_msg;
452  static double ev_ant = 0.0;
453 
454  // Note that the controllers are not in speed mode, but in effort. Therefore the speed ref will be Nm.
455  // Open loop - works well but there is some inertia in the whole system and just setting torque to 0 does not stop the robot.
456  // vel_ref_msg.data = -v_ref_ * 20.0;
457 
458  // If using a JointEffortController Try a velocity control loop
459  // After 1.9.2 VelocityControllers in agvs_control should work
460  /*
461  double ev = v_mps_ - v_ref_;
462  double Kp = 30.0;
463  double Kd = 30.0;
464  vel_ref_msg.data = Kp * ev; //+ Kd * (ev - ev_ant);
465  ev_ant = ev;
466  */
467 
468  // Reference for velocity controllers
469  double Kp = 10.0; // ref is in [m/s] while VelocityController expects ?
470  vel_ref_msg.data = -v_ref_ * Kp;
471 
472  pos_ref_msg.data = a_ref_;
473 
474  // Publish references
475  ref_vel_fwd_.publish( vel_ref_msg );
476  ref_vel_bwd_.publish( vel_ref_msg );
477 
478  ref_pos_fwd_.publish( pos_ref_msg );
479  pos_ref_msg.data = -a_ref_; // symetric angle
480  ref_pos_bwd_.publish( pos_ref_msg );
481 }
482 
483 // Sets the motor position to the desired value
484 void SetElevatorPosition(double val){
485 
486  std_msgs::Float64 ref_msg;
487 
488  ref_msg.data = val;
489 
490  ref_pos_elevator_.publish( ref_msg );
491 }
492 
494 void stopping()
495 {}
496 
497 /*
498  * \brief Checks that the robot is receiving at a correct frequency the command messages. Diagnostics
499  *
500  */
502 {
503  ros::Time current_time = ros::Time::now();
504 
505  double diff = (current_time - last_command_time_).toSec();
506 
507  if(diff > 1.0){
508  stat.summary(diagnostic_msgs::DiagnosticStatus::WARN, "Topic is not receiving commands");
509  //ROS_INFO("check_command_subscriber: %lf seconds without commands", diff);
510  // TODO: Set Speed References to 0
511  }else{
512  stat.summary(diagnostic_msgs::DiagnosticStatus::OK, "Topic receiving commands");
513  }
514 }
515 
516 // Service SetOdometry
517 bool srvCallback_SetOdometry(robotnik_msgs::set_odometry::Request &request, robotnik_msgs::set_odometry::Response &response )
518 {
519  // ROS_INFO("summit_xl_odometry::set_odometry: request -> x = %f, y = %f, a = %f", req.x, req.y, req.orientation);
520  robot_pose_px_ = request.x;
521  robot_pose_py_ = request.y;
522  robot_pose_pa_ = request.orientation;
523 
524  response.ret = true;
525  return true;
526 }
527 
528 // Service Raise Elevator
529 bool srvCallback_RaiseElevator(std_srvs::Empty::Request &request, std_srvs::Empty::Response &response )
530 {
531 
532  SetElevatorPosition(MAX_ELEVATOR_POSITION);
533 
534  return true;
535 }
536 
537 // Service Lower Elevator
538 bool srvCallback_LowerElevator(std_srvs::Empty::Request &request, std_srvs::Empty::Response &response )
539 {
540  SetElevatorPosition(0.0);
541 
542  return true;
543 }
544 
545 
546 // Topic command
547 void jointStateCallback(const sensor_msgs::JointStateConstPtr& msg)
548 {
549  joint_state_ = *msg;
550  read_state_ = true;
551 }
552 
553 // Topic command
554 void commandCallback(const ackermann_msgs::AckermannDriveStamped::ConstPtr& msg)
555 {
556  // Safety check
557  last_command_time_ = ros::Time::now();
558  subs_command_freq->tick(); // For diagnostics
559 
560  double speed_limit = 2.0; // m/s
561  double angle_limit = PI;
562  v_ref_ = saturation(msg->drive.speed, -speed_limit, speed_limit);
563  a_ref_ = saturation(msg->drive.steering_angle, -angle_limit, angle_limit);
564 }
565 
566 // Imu callback
567 void imuCallback( const sensor_msgs::Imu& imu_msg){
568 
569  orientation_diff_x_ = imu_msg.orientation.x;
570  orientation_diff_y_ = imu_msg.orientation.y;
571  orientation_diff_z_ = imu_msg.orientation.z;
572  orientation_diff_w_ = imu_msg.orientation.w;
573 
574  ang_vel_x_ = imu_msg.angular_velocity.x;
575  ang_vel_y_ = imu_msg.angular_velocity.y;
576  ang_vel_z_ = imu_msg.angular_velocity.z;
577 
578  lin_acc_x_ = imu_msg.linear_acceleration.x;
579  lin_acc_y_ = imu_msg.linear_acceleration.y;
580  lin_acc_z_ = imu_msg.linear_acceleration.z;
581 }
582 
583 double saturation(double u, double min, double max)
584 {
585  if (u>max) u=max;
586  if (u<min) u=min;
587  return u;
588 }
589 
590 
591 
593 static inline void radnorm(double* radians)
594 {
595  while (*radians >= (PI)) {
596  *radians -= 2.0 * PI;
597  }
598  while (*radians <= (-PI)) {
599  *radians += 2.0 * PI;
600  }
601 }
602 
603 static inline double radnorm2( double value )
604 {
605  while (value > 2.0*PI) value -= 2.0*PI;
606  while (value < -2.0*PI) value += 2.0*PI;
607  return value;
608 }
609 
610 bool spin()
611 {
612  ROS_INFO("agvs_robot_control::spin()");
613  ros::Rate r(desired_freq_); // 50.0
614 
615  while (!ros::isShuttingDown()) // Using ros::isShuttingDown to avoid restarting the node during a shutdown.
616  {
617  if (starting() == 0)
618  {
619  while(ros::ok() && node_handle_.ok()) {
620  UpdateControl();
621  UpdateOdometry();
622  PublishOdometry();
623  diagnostic_.update();
624  ros::spinOnce();
625  r.sleep();
626  }
627  ROS_INFO("END OF ros::ok() !!!");
628  } else {
629  // No need for diagnostic here since a broadcast occurs in start
630  // when there is an error.
631  usleep(1000000);
632  ros::spinOnce();
633  }
634  }
635 
636  ROS_INFO("agvs_robot_control::spin() - end");
637  return true;
638 }
639 
640 }; // Class AGVSControllerClass
641 
642 int main(int argc, char** argv)
643 {
644  ros::init(argc, argv, "agvs_robot_control");
645 
646  ros::NodeHandle n;
647  AGVSControllerClass sxlrc(n);
648 
649  sxlrc.spin();
650 
651  return (0);
652 
653 
654 }
655 
void UpdateOdometry()
Updates the values of the odometry Ackerman&#39;s odometry calculation (using motor speed and position of...
diagnostic_updater::Updater diagnostic_
void publish(const boost::shared_ptr< M > &message) const
ros::ServiceServer srv_RaiseElevator_
#define PI
void stopping()
Controller stopping.
double saturation(double u, double min, double max)
void summary(unsigned char lvl, const std::string s)
Subscriber subscribe(const std::string &topic, uint32_t queue_size, void(T::*fp)(M), T *obj, const TransportHints &transport_hints=TransportHints())
ros::ServiceServer srv_LowerElevator_
void imuCallback(const sensor_msgs::Imu &imu_msg)
void setHardwareID(const std::string &hwid)
ros::Publisher ref_pos_elevator_
std::string joint_front_motor_wheel
#define AGVS_WHEEL_DIAMETER
void commandCallback(const ackermann_msgs::AckermannDriveStamped::ConstPtr &msg)
ROSCPP_DECL void init(int &argc, char **argv, const std::string &name, uint32_t options=0)
void add(const std::string &name, TaskFunction f)
ros::ServiceServer srv_SetMode_
void check_command_subscriber(diagnostic_updater::DiagnosticStatusWrapper &stat)
bool srvCallback_SetOdometry(robotnik_msgs::set_odometry::Request &request, robotnik_msgs::set_odometry::Response &response)
#define MAX_ELEVATOR_POSITION
ServiceServer advertiseService(const std::string &service, bool(T::*srv_func)(MReq &, MRes &), T *obj)
AGVSControllerClass(ros::NodeHandle h)
Public constructor.
sensor_msgs::JointState joint_state_
diagnostic_updater::FrequencyStatus freq_diag_
void SetElevatorPosition(double val)
ros::ServiceServer srv_GetMode_
ros::Publisher ref_pos_fwd_
ros::Publisher ref_vel_fwd_
tf::TransformBroadcaster odom_broadcaster
diagnostic_updater::FunctionDiagnosticTask command_freq_
bool srvCallback_RaiseElevator(std_srvs::Empty::Request &request, std_srvs::Empty::Response &response)
ros::Publisher ref_vel_bwd_
#define ROS_INFO(...)
bool param(const std::string &param_name, T &param_val, const T &default_val) const
#define AGVS_MIN_COMMAND_REC_FREQ
ROSCPP_DECL bool ok()
ros::NodeHandle private_node_handle_
void sendTransform(const StampedTransform &transform)
bool srvCallback_LowerElevator(std_srvs::Empty::Request &request, std_srvs::Empty::Response &response)
ros::NodeHandle node_handle_
ROSCPP_DECL bool isShuttingDown()
Publisher advertise(const std::string &topic, uint32_t queue_size, bool latch=false)
#define DEFAULT_DIST_CENTER_TO_WHEEL
diagnostic_updater::HeaderlessTopicDiagnostic * subs_command_freq
bool sleep()
ros::Subscriber joint_state_sub_
TFSIMD_FORCE_INLINE const tfScalar & w() const
#define AGVS_MAX_COMMAND_REC_FREQ
std::string joint_back_motor_wheel
int starting()
Controller startup in realtime.
void jointStateCallback(const sensor_msgs::JointStateConstPtr &msg)
static double radnorm2(double value)
static geometry_msgs::Quaternion createQuaternionMsgFromYaw(double yaw)
ros::Subscriber cmd_sub_
bool getParam(const std::string &key, std::string &s) const
static Time now()
ackermann_msgs::AckermannDriveStamped base_vel_msg_
static void radnorm(double *radians)
Normalize in rad.
bool ok() const
ros::ServiceServer srv_SetOdometry_
ROSCPP_DECL void spinOnce()
int main(int argc, char **argv)
ros::Publisher ref_pos_bwd_
#define ROS_ERROR(...)


agvs_robot_control
Author(s): Roberto Guzmán
autogenerated on Mon Jun 10 2019 12:47:24