hardware_interface.cpp
Go to the documentation of this file.
1 /*******************************************************************************
2  * BSD 3-Clause License
3  *
4  * Copyright (c) 2021, Qiayuan Liao
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * * Redistributions of source code must retain the above copyright notice, this
11  * list of conditions and the following disclaimer.
12  *
13  * * Redistributions in binary form must reproduce the above copyright notice,
14  * this list of conditions and the following disclaimer in the documentation
15  * and/or other materials provided with the distribution.
16  *
17  * * Neither the name of the copyright holder nor the names of its
18  * contributors may be used to endorse or promote products derived from
19  * this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE
25  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
28  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32  *******************************************************************************/
33 
34 //
35 // Created by qiayuan on 12/21/20.
36 //
37 
39 
41 
42 namespace rm_hw
43 {
44 bool RmRobotHW::init(ros::NodeHandle& root_nh, ros::NodeHandle& robot_hw_nh)
45 {
46  XmlRpc::XmlRpcValue xml_rpc_value;
47  // Parse actuator coefficient specified by user (stored on ROS parameter server)
48  if (!robot_hw_nh.getParam("actuator_coefficient", xml_rpc_value))
49  ROS_WARN("No actuator coefficient specified");
50  else if (!parseActCoeffs(xml_rpc_value))
51  return false;
52  // Parse actuator specified by user (stored on ROS parameter server)
53  if (!robot_hw_nh.getParam("actuators", xml_rpc_value))
54  ROS_WARN("No actuator specified");
55  else if (!parseActData(xml_rpc_value, robot_hw_nh))
56  return false;
57  // Parse actuator specified by user (stored on ROS parameter server)
58  if (!robot_hw_nh.getParam("imus", xml_rpc_value))
59  ROS_WARN("No imu specified");
60  else if (!parseImuData(xml_rpc_value, robot_hw_nh))
61  return false;
62  if (!robot_hw_nh.getParam("tof_radars", xml_rpc_value))
63  ROS_WARN("No tof_radars specified");
64  else if (!parseTofData(xml_rpc_value, robot_hw_nh))
65  return false;
66  if (!robot_hw_nh.getParam("gpios", xml_rpc_value))
67  ROS_WARN("No gpio specified");
68  else if (!parseGpioData(xml_rpc_value, robot_hw_nh))
69  return false;
70  // CAN Bus
71  if (!robot_hw_nh.getParam("bus", xml_rpc_value))
72  ROS_WARN("No bus specified");
73  else if (xml_rpc_value.getType() == XmlRpc::XmlRpcValue::TypeArray)
74  {
75  ROS_ASSERT(xml_rpc_value[0].getType() == XmlRpc::XmlRpcValue::TypeString);
76  for (int i = 0; i < xml_rpc_value.size(); ++i)
77  {
78  std::string bus_name = xml_rpc_value[i];
79  if (bus_name.find("can") != std::string::npos)
80  can_buses_.push_back(new CanBus(bus_name,
82  .id2act_data_ = &bus_id2act_data_[bus_name],
83  .id2imu_data_ = &bus_id2imu_data_[bus_name],
84  .id2tof_data_ = &bus_id2tof_data_[bus_name] },
86  else
87  ROS_ERROR_STREAM("Unknown bus: " << bus_name);
88  }
89  }
90 
91  if (!loadUrdf(root_nh))
92  {
93  ROS_ERROR("Error occurred while setting up urdf");
94  return false;
95  }
96  // Initialize transmission
97  if (!setupTransmission(root_nh))
98  {
99  ROS_ERROR("Error occurred while setting up transmission");
100  return false;
101  }
102  // Initialize joint limit
103  if (!setupJointLimit(root_nh))
104  {
105  ROS_ERROR("Error occurred while setting up joint limit");
106  return false;
107  }
108 
109  // Other Interface
113 
114  actuator_state_pub_.reset(
115  new realtime_tools::RealtimePublisher<rm_msgs::ActuatorState>(root_nh, "/actuator_states", 100));
116 
117  service_server_ = robot_hw_nh.advertiseService("imu_trigger", &RmRobotHW::enableImuTrigger, this);
118  return true;
119 }
120 
121 void RmRobotHW::read(const ros::Time& time, const ros::Duration& period)
122 {
123  for (auto bus : can_buses_)
124  bus->read(time);
125  for (auto& id2act_datas : bus_id2act_data_)
126  for (auto& act_data : id2act_datas.second)
127  {
128  try
129  { // Duration will be out of dual 32-bit range while motor failure
130  act_data.second.halted = (time - act_data.second.stamp).toSec() > 0.1 || act_data.second.temp > 99;
131  }
132  catch (std::runtime_error& ex)
133  {
134  }
135  if (act_data.second.halted)
136  {
137  act_data.second.seq = 0;
138  act_data.second.vel = 0;
139  act_data.second.effort = 0;
140  act_data.second.calibrated = false; // set the actuator no calibrated
141  }
142  }
145  // Set all cmd to zero to avoid crazy soft limit oscillation when not controller loaded
146  for (auto effort_joint_handle : effort_joint_handles_)
147  effort_joint_handle.setCommand(0.);
148  // Gpio read
150 }
151 
152 void RmRobotHW::write(const ros::Time& time, const ros::Duration& period)
153 {
155  {
156  // Propagate without joint limits
158  // Save commanded effort before enforceLimits
159  for (auto& id2act_datas : bus_id2act_data_)
160  for (auto& act_data : id2act_datas.second)
161  act_data.second.cmd_effort = act_data.second.exe_effort;
162  // enforceLimits will limit cmd_effort into suitable value https://github.com/ros-controls/ros_control/wiki/joint_limits_interface
165  // Propagate with joint limits
167  // Restore the cmd_effort for the calibrating joint
168  for (auto& id2act_datas : bus_id2act_data_)
169  for (auto& act_data : id2act_datas.second)
170  if (act_data.second.need_calibration && !act_data.second.calibrated)
171  act_data.second.exe_effort = act_data.second.cmd_effort;
172  }
173  for (auto& bus : can_buses_)
174  bus->write();
175  // Gpio write
177  publishActuatorState(time);
178 }
179 
180 void RmRobotHW::setCanBusThreadPriority(int thread_priority)
181 {
182  thread_priority_ = thread_priority;
183 }
184 
186 {
188  return;
189  if (last_publish_time_ + ros::Duration(1.0 / 100.0) < time)
190  {
191  if (actuator_state_pub_->trylock())
192  {
193  rm_msgs::ActuatorState actuator_state;
194  for (const auto& id2act_datas : bus_id2act_data_)
195  for (const auto& act_data : id2act_datas.second)
196  {
197  actuator_state.stamp.push_back(act_data.second.stamp);
198  actuator_state.name.push_back(act_data.second.name);
199  actuator_state.type.push_back(act_data.second.type);
200  actuator_state.bus.push_back(id2act_datas.first);
201  actuator_state.id.push_back(act_data.first);
202  actuator_state.halted.push_back(act_data.second.halted);
203  actuator_state.need_calibration.push_back(act_data.second.need_calibration);
204  actuator_state.calibrated.push_back(act_data.second.calibrated);
205  actuator_state.calibration_reading.push_back(act_data.second.calibration_reading);
206  actuator_state.position_raw.push_back(act_data.second.q_raw);
207  actuator_state.velocity_raw.push_back(act_data.second.qd_raw);
208  actuator_state.temperature.push_back(act_data.second.temp);
209  actuator_state.circle.push_back(act_data.second.q_circle);
210  actuator_state.last_position_raw.push_back(act_data.second.q_last);
211  actuator_state.frequency.push_back(act_data.second.frequency);
212  actuator_state.position.push_back(act_data.second.pos);
213  actuator_state.velocity.push_back(act_data.second.vel);
214  actuator_state.effort.push_back(act_data.second.effort);
215  actuator_state.commanded_effort.push_back(act_data.second.cmd_effort);
216  actuator_state.executed_effort.push_back(act_data.second.exe_effort);
217  actuator_state.offset.push_back(act_data.second.offset);
218  }
219  actuator_state_pub_->msg_ = actuator_state;
220  actuator_state_pub_->unlockAndPublish();
221  last_publish_time_ = time;
222  }
223  }
224 }
225 bool RmRobotHW::enableImuTrigger(rm_msgs::EnableImuTrigger::Request& req, rm_msgs::EnableImuTrigger::Response& res)
226 {
227  for (const auto& it_1 : bus_id2imu_data_)
228  {
229  for (const auto& it_2 : it_1.second)
230  {
231  if (it_2.second.imu_name == req.imu_name)
232  {
233  can_frame frame{};
234  frame.can_id = (canid_t)(it_2.first + 2);
235  frame.can_dlc = 1;
236  frame.data[0] = req.enable_trigger;
237  for (auto& bus : can_buses_)
238  {
239  if (bus->bus_name_ == it_1.first)
240  {
241  bus->write(&frame);
242  res.is_success = true;
243  return true;
244  }
245  }
246  }
247  }
248  }
249  res.is_success = false;
250  return false;
251 }
252 
253 } // namespace rm_hw
XmlRpc::XmlRpcValue::size
int size() const
rm_hw::RmRobotHW::jnt_to_act_effort_
transmission_interface::JointToActuatorEffortInterface * jnt_to_act_effort_
Definition: hardware_interface.h:259
rm_hw::RmRobotHW::effort_jnt_saturation_interface_
joint_limits_interface::EffortJointSaturationInterface effort_jnt_saturation_interface_
Definition: hardware_interface.h:260
rm_hw::RmRobotHW::actuator_state_pub_
std::shared_ptr< realtime_tools::RealtimePublisher< rm_msgs::ActuatorState > > actuator_state_pub_
Definition: hardware_interface.h:280
rm_hw::RmRobotHW::publishActuatorState
void publishActuatorState(const ros::Time &time)
Publish actuator's state to a topic named "/actuator_states".
Definition: hardware_interface.cpp:216
rm_hw::RmRobotHW::bus_id2tof_data_
std::unordered_map< std::string, std::unordered_map< int, TofData > > bus_id2tof_data_
Definition: hardware_interface.h:277
ROS_ERROR_STREAM
#define ROS_ERROR_STREAM(args)
rm_hw::GpioManager::readGpio
void readGpio()
Definition: gpio_manager.cpp:45
rm_hw::RmRobotHW::bus_id2imu_data_
std::unordered_map< std::string, std::unordered_map< int, ImuData > > bus_id2imu_data_
Definition: hardware_interface.h:274
rm_hw::RmRobotHW::parseActData
bool parseActData(XmlRpc::XmlRpcValue &act_datas, ros::NodeHandle &robot_hw_nh)
Check whether actuator is specified and load specified params.
Definition: parse.cpp:159
rm_hw::RmRobotHW::gpio_state_interface_
rm_control::GpioStateInterface gpio_state_interface_
Definition: hardware_interface.h:248
rm_hw::RmRobotHW::can_buses_
std::vector< CanBus * > can_buses_
Definition: hardware_interface.h:246
rm_hw::RmRobotHW::act_to_jnt_state_
transmission_interface::ActuatorToJointStateInterface * act_to_jnt_state_
Definition: hardware_interface.h:258
TransmissionInterface< ActuatorToJointStateHandle >::propagate
void propagate()
ros::NodeHandle::getParam
bool getParam(const std::string &key, bool &b) const
hardware_interface::InterfaceManager::registerInterface
void registerInterface(T *iface)
rm_hw::RmRobotHW::robot_state_interface_
rm_control::RobotStateInterface robot_state_interface_
Definition: hardware_interface.h:253
rm_hw::RmRobotHW::parseImuData
bool parseImuData(XmlRpc::XmlRpcValue &imu_datas, ros::NodeHandle &robot_hw_nh)
Check whether some params that are related to imu are set up and load these params.
Definition: parse.cpp:269
rm_hw::RmRobotHW::loadUrdf
bool loadUrdf(ros::NodeHandle &root_nh)
Load urdf of robot from param server.
Definition: parse.cpp:525
rm_hw::RmRobotHW::parseGpioData
bool parseGpioData(XmlRpc::XmlRpcValue &gpio_datas, ros::NodeHandle &robot_hw_nh)
Check whether somme params that are related to gpio are set up and load these params.
Definition: parse.cpp:431
rm_hw::CanDataPtr::type2act_coeffs_
std::unordered_map< std::string, ActCoeff > * type2act_coeffs_
Definition: types.h:126
ros::NodeHandle::advertiseService
ServiceServer advertiseService(AdvertiseServiceOptions &ops)
rm_hw::RmRobotHW::setupTransmission
bool setupTransmission(ros::NodeHandle &root_nh)
Set up transmission.
Definition: parse.cpp:534
rm_hw::RmRobotHW::effort_jnt_soft_limits_interface_
joint_limits_interface::EffortJointSoftLimitsInterface effort_jnt_soft_limits_interface_
Definition: hardware_interface.h:261
rm_hw::RmRobotHW::type2act_coeffs_
std::unordered_map< std::string, ActCoeff > type2act_coeffs_
Definition: hardware_interface.h:270
realtime_tools::RealtimePublisher
rm_hw::RmRobotHW::gpio_command_interface_
rm_control::GpioCommandInterface gpio_command_interface_
Definition: hardware_interface.h:249
rm_hw::RmRobotHW::service_server_
ros::ServiceServer service_server_
Definition: hardware_interface.h:241
rm_hw::RmRobotHW::parseTofData
bool parseTofData(XmlRpc::XmlRpcValue &tof_datas, ros::NodeHandle &robot_hw_nh)
Definition: parse.cpp:476
rm_hw::RmRobotHW::enableImuTrigger
bool enableImuTrigger(rm_msgs::EnableImuTrigger::Request &req, rm_msgs::EnableImuTrigger::Response &res)
Definition: hardware_interface.cpp:256
XmlRpc::XmlRpcValue::TypeString
TypeString
rm_hw::RmRobotHW::setCanBusThreadPriority
void setCanBusThreadPriority(int thread_priority)
Definition: hardware_interface.cpp:211
rm_hw::CanDataPtr
Definition: types.h:124
rm_hw::RmRobotHW::bus_id2act_data_
std::unordered_map< std::string, std::unordered_map< int, ActData > > bus_id2act_data_
Definition: hardware_interface.h:271
rm_hw::RmRobotHW::thread_priority_
int thread_priority_
Definition: hardware_interface.h:244
rm_hw::RmRobotHW::effort_joint_handles_
std::vector< hardware_interface::JointHandle > effort_joint_handles_
Definition: hardware_interface.h:262
rm_hw::RmRobotHW::gpio_manager_
GpioManager gpio_manager_
Definition: hardware_interface.h:247
JointLimitsInterface< EffortJointSaturationHandle >::enforceLimits
void enforceLimits(const ros::Duration &period)
ROS_WARN
#define ROS_WARN(...)
rm_hw::RmRobotHW::read
void read(const ros::Time &time, const ros::Duration &period) override
Comunicate with hardware. Get datas, status of robot.
Definition: hardware_interface.cpp:152
XmlRpc::XmlRpcValue::getType
const Type & getType() const
rm_hw::GpioManager::writeGpio
void writeGpio()
Definition: gpio_manager.cpp:68
XmlRpc::XmlRpcValue::TypeArray
TypeArray
rm_hw::CanBus
Definition: can_bus.h:86
hardware_interface.h
ros::Time
ROS_ERROR
#define ROS_ERROR(...)
rm_hw::RmRobotHW::is_actuator_specified_
bool is_actuator_specified_
Definition: hardware_interface.h:243
ros_utilities.h
rm_hw::RmRobotHW::last_publish_time_
ros::Time last_publish_time_
Definition: hardware_interface.h:279
rm_hw::RmRobotHW::setupJointLimit
bool setupJointLimit(ros::NodeHandle &root_nh)
Set up joint limit.
Definition: parse.cpp:575
rm_hw
Definition: control_loop.h:48
ROS_ASSERT
#define ROS_ASSERT(cond)
rm_hw::RmRobotHW::parseActCoeffs
bool parseActCoeffs(XmlRpc::XmlRpcValue &act_coeffs)
Check whether some coefficients that are related to actuator are set up and load these coefficients.
Definition: parse.cpp:81
ros::Duration
rm_hw::RmRobotHW::write
void write(const ros::Time &time, const ros::Duration &period) override
Comunicate with hardware. Publish command to robot.
Definition: hardware_interface.cpp:183
XmlRpc::XmlRpcValue
rm_hw::RmRobotHW::init
bool init(ros::NodeHandle &root_nh, ros::NodeHandle &robot_hw_nh) override
Get necessary params from param server. Init hardware_interface.
Definition: hardware_interface.cpp:75
ros::NodeHandle


rm_hw
Author(s): Qiayuan Liao
autogenerated on Tue May 6 2025 02:23:44