3636//
3737#include " rm_hw/control_loop.h"
3838
39- rm_hw::RmRobotHWLoop::RmRobotHWLoop (ros::NodeHandle& nh, std::shared_ptr<RmRobotHW> hardware_interface)
39+ namespace rm_hw
40+ {
41+ RmRobotHWLoop::RmRobotHWLoop (ros::NodeHandle& nh, std::shared_ptr<RmRobotHW> hardware_interface)
4042 : nh_(nh), hardware_interface_(std::move(hardware_interface))
4143{
42- // Create the controller manager
43- controller_manager_.reset (new controller_manager::ControllerManager (hardware_interface_.get (), nh_));
44-
45- // Load rosparams
46- int error = 0 ;
44+ // Load ros params
45+ int error = 0 , thread_priority;
4746 ros::NodeHandle nh_p (" ~" );
4847 error += !nh_p.getParam (" loop_frequency" , loop_hz_);
4948 error += !nh_p.getParam (" cycle_time_error_threshold" , cycle_time_error_threshold_);
49+ error += !nh_p.getParam (" thread_priority" , thread_priority);
5050 if (error > 0 )
5151 {
52- char error_message[] =
53- " could not retrieve one of the required parameters\n\t rm_hw/loop_hz or rm_hw/cycle_time_error_threshold" ;
52+ char error_message[] = " could not retrieve one of the required parameters\n\t rm_hw/loop_hz or "
53+ " rm_hw/cycle_time_error_threshold or "
54+ " rm_hw/thread_priority" ;
5455 ROS_ERROR_STREAM (error_message);
5556 throw std::runtime_error (error_message);
5657 }
5758
59+ // Initialise the hardware interface:
60+ // 1. retrieve configuration from rosparam
61+ // 2. initialise the hardware and interface it with ros_control
62+ hardware_interface_->setCanBusThreadPriority (thread_priority);
63+ hardware_interface_->init (nh, nh_p);
64+ // Create the controller manager
65+ controller_manager_.reset (new controller_manager::ControllerManager (hardware_interface_.get (), nh_));
66+
5867 // Get current time for use with first update
59- last_time_ = steady_clock ::now ();
68+ last_time_ = clock ::now ();
6069
61- // Start timer that will periodically call RmRobotHWLoop::update
62- desired_update_freq_ = ros::Duration (1 / loop_hz_);
63- loop_timer_ = nh_.createTimer (desired_update_freq_, &RmRobotHWLoop::update, this );
70+ // Setup loop thread
71+ loop_thread_ = std::thread ([&]() {
72+ while (loop_running_)
73+ {
74+ if (loop_running_)
75+ update ();
76+ }
77+ });
78+ sched_param sched{ .sched_priority = thread_priority };
79+ if (pthread_setschedparam (loop_thread_.native_handle (), SCHED_FIFO, &sched) != 0 )
80+ ROS_WARN (" Failed to set threads priority (one possible reason could be that the user and the group permissions "
81+ " are not set properly.).\n " );
6482}
6583
66- void rm_hw:: RmRobotHWLoop::update (const ros::TimerEvent& )
84+ void RmRobotHWLoop::update ()
6785{
86+ const auto current_time = clock::now ();
87+ // Compute desired duration rounded to clock decimation
88+ const duration<double > desired_duration (1.0 / loop_hz_);
6889 // Get change in time
69- current_time_ = steady_clock::now ();
70- duration<double > time_span = duration_cast<duration<double >>(current_time_ - last_time_);
90+ duration<double > time_span = duration_cast<duration<double >>(current_time - last_time_);
7191 elapsed_time_ = ros::Duration (time_span.count ());
72- last_time_ = current_time_ ;
92+ last_time_ = current_time ;
7393
7494 // Check cycle time for excess delay
75- const double cycle_time_error = (elapsed_time_ - desired_update_freq_ ).toSec ();
95+ const double cycle_time_error = (elapsed_time_ - ros::Duration (desired_duration. count ()) ).toSec ();
7696 if (cycle_time_error > cycle_time_error_threshold_)
77- {
7897 ROS_WARN_STREAM (" Cycle time exceeded error threshold by: " << cycle_time_error - cycle_time_error_threshold_
7998 << " s, "
8099 << " cycle time: " << elapsed_time_ << " s, "
81100 << " threshold: " << cycle_time_error_threshold_ << " s" );
82- }
83-
84101 // Input
85102 // get the hardware's state
86103 hardware_interface_->read (ros::Time::now (), elapsed_time_);
@@ -92,4 +109,16 @@ void rm_hw::RmRobotHWLoop::update(const ros::TimerEvent&)
92109 // Output
93110 // send the new command to hardware
94111 hardware_interface_->write (ros::Time::now (), elapsed_time_);
112+
113+ // Sleep
114+ const auto sleep_till = current_time + duration_cast<clock::duration>(desired_duration);
115+ std::this_thread::sleep_until (sleep_till);
116+ }
117+
118+ RmRobotHWLoop::~RmRobotHWLoop ()
119+ {
120+ loop_running_ = false ;
121+ if (loop_thread_.joinable ())
122+ loop_thread_.join ();
95123}
124+ } // namespace rm_hw
0 commit comments