Skip to content

Commit b085d50

Browse files
fmauchurmahp
andauthored
Foxy controller stopper (#324)
* Added controller stopper node (Backport #309) * Add state interface to ur_description * Async tasks to seperate thread and initialized state interface (Backport parts of #206) (#372) * Add system_interface initialized Co-authored-by: Mads Holm Peters <[email protected]>
1 parent c57f17b commit b085d50

File tree

11 files changed

+393
-13
lines changed

11 files changed

+393
-13
lines changed

ur_bringup/launch/ur_control.launch.py

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,24 @@ def generate_launch_description():
243243
parameters=[{"robot_ip": robot_ip}],
244244
)
245245

246+
controller_stopper_node = Node(
247+
package="ur_robot_driver",
248+
executable="controller_stopper_node",
249+
name="controller_stopper",
250+
output="screen",
251+
emulate_tty=True,
252+
parameters=[
253+
{
254+
"consistent_controllers": [
255+
"io_and_status_controller",
256+
"force_torque_sensor_broadcaster",
257+
"joint_state_broadcaster",
258+
"speed_scaling_state_broadcaster",
259+
]
260+
},
261+
],
262+
)
263+
246264
robot_state_publisher_node = Node(
247265
package="robot_state_publisher",
248266
executable="robot_state_publisher",
@@ -300,6 +318,7 @@ def generate_launch_description():
300318
nodes_to_start = [
301319
control_node,
302320
dashboard_client_node,
321+
controller_stopper_node,
303322
robot_state_publisher_node,
304323
rviz_node,
305324
joint_state_broadcaster_spawner,

ur_controllers/include/ur_controllers/gpio_controller.hpp

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "ur_dashboard_msgs/msg/safety_mode.hpp"
3737
#include "ur_msgs/srv/set_io.hpp"
3838
#include "ur_msgs/srv/set_speed_slider_fraction.hpp"
39+
#include "std_msgs/msg/bool.hpp"
3940

4041
namespace ur_controllers
4142
{
@@ -64,7 +65,9 @@ enum StateInterfaces
6465
ROBOT_MODE = 52,
6566
ROBOT_STATUS_BITS = 53,
6667
SAFETY_MODE = 57,
67-
SAFETY_STATUS_BITS = 58
68+
SAFETY_STATUS_BITS = 58,
69+
INITIALIZED_FLAG = 69,
70+
PROGRAM_RUNNING = 70,
6871
};
6972

7073
class GPIOController : public controller_interface::ControllerInterface
@@ -98,6 +101,8 @@ class GPIOController : public controller_interface::ControllerInterface
98101

99102
void publishSafetyMode();
100103

104+
void publishProgramRunning();
105+
101106
protected:
102107
void initMsgs();
103108

@@ -116,14 +121,16 @@ class GPIOController : public controller_interface::ControllerInterface
116121
std::shared_ptr<rclcpp::Publisher<ur_msgs::msg::ToolDataMsg>> tool_data_pub_;
117122
std::shared_ptr<rclcpp::Publisher<ur_dashboard_msgs::msg::RobotMode>> robot_mode_pub_;
118123
std::shared_ptr<rclcpp::Publisher<ur_dashboard_msgs::msg::SafetyMode>> safety_mode_pub_;
124+
std::shared_ptr<rclcpp::Publisher<std_msgs::msg::Bool>> program_state_pub_;
119125

120126
ur_msgs::msg::IOStates io_msg_;
121127
ur_msgs::msg::ToolDataMsg tool_data_msg_;
122128
ur_dashboard_msgs::msg::RobotMode robot_mode_msg_;
123129
ur_dashboard_msgs::msg::SafetyMode safety_mode_msg_;
130+
std_msgs::msg::Bool program_running_msg_;
124131

125132
static constexpr double ASYNC_WAITING = 2.0;
126-
// TODO(anyone) publishers to add: program_state_pub_, tcp_pose_pub_
133+
// TODO(anyone) publishers to add: tcp_pose_pub_
127134
// TODO(anyone) subscribers to add: script_command_sub_
128135
// TODO(anyone) service servers to add: resend_robot_program_srv_, deactivate_srv_, set_payload_srv_, tare_sensor_srv_
129136
};

ur_controllers/src/gpio_controller.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,10 @@ controller_interface::InterfaceConfiguration ur_controllers::GPIOController::sta
100100
for (size_t i = 0; i < 11; ++i) {
101101
config.names.emplace_back("gpio/safety_status_bit_" + std::to_string(i));
102102
}
103+
config.names.emplace_back("system_interface/initialized");
104+
105+
// program running
106+
config.names.emplace_back("gpio/program_running");
103107

104108
return config;
105109
}
@@ -117,6 +121,7 @@ controller_interface::return_type ur_controllers::GPIOController::update()
117121
publishToolData();
118122
publishRobotMode();
119123
publishSafetyMode();
124+
publishProgramRunning();
120125
return controller_interface::return_type::OK;
121126
}
122127

@@ -194,9 +199,24 @@ void GPIOController::publishSafetyMode()
194199
}
195200
}
196201

202+
void GPIOController::publishProgramRunning()
203+
{
204+
auto program_running_value = static_cast<uint8_t>(state_interfaces_[StateInterfaces::PROGRAM_RUNNING].get_value());
205+
bool program_running = program_running_value == 1.0 ? true : false;
206+
if (program_running_msg_.data != program_running) {
207+
program_running_msg_.data = program_running;
208+
program_state_pub_->publish(program_running_msg_);
209+
}
210+
}
211+
197212
rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn
198213
ur_controllers::GPIOController::on_activate(const rclcpp_lifecycle::State& /*previous_state*/)
199214
{
215+
while (state_interfaces_[StateInterfaces::INITIALIZED_FLAG].get_value() == 0.0) {
216+
RCLCPP_INFO(get_node()->get_logger(), "Waiting for system interface to initialize...");
217+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
218+
}
219+
200220
try {
201221
// register publisher
202222
io_pub_ = get_node()->create_publisher<ur_msgs::msg::IOStates>("~/io_states", rclcpp::SystemDefaultsQoS());
@@ -210,6 +230,11 @@ ur_controllers::GPIOController::on_activate(const rclcpp_lifecycle::State& /*pre
210230
safety_mode_pub_ =
211231
get_node()->create_publisher<ur_dashboard_msgs::msg::SafetyMode>("~/safety_mode", rclcpp::SystemDefaultsQoS());
212232

233+
auto program_state_pub_qos = rclcpp::SystemDefaultsQoS();
234+
program_state_pub_qos.transient_local();
235+
program_state_pub_ =
236+
get_node()->create_publisher<std_msgs::msg::Bool>("~/robot_program_running", program_state_pub_qos);
237+
213238
set_io_srv_ = get_node()->create_service<ur_msgs::srv::SetIO>(
214239
"~/set_io", std::bind(&GPIOController::setIO, this, std::placeholders::_1, std::placeholders::_2));
215240

@@ -231,6 +256,7 @@ ur_controllers::GPIOController::on_deactivate(const rclcpp_lifecycle::State& /*p
231256
tool_data_pub_.reset();
232257
robot_mode_pub_.reset();
233258
safety_mode_pub_.reset();
259+
program_state_pub_.reset();
234260
set_io_srv_.reset();
235261
set_speed_slider_srv_.reset();
236262
} catch (...) {

ur_description/urdf/ur.ros2_control.xacro

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,13 @@
244244
<state_interface name="safety_status_bit_8"/>
245245
<state_interface name="safety_status_bit_9"/>
246246
<state_interface name="safety_status_bit_10"/>
247+
<state_interface name="program_running"/>
247248
</joint>
248249

250+
<gpio name="system_interface">
251+
<state_interface name="initialized"/>
252+
</gpio>
253+
249254
</ros2_control>
250255
</xacro:macro>
251256

ur_robot_driver/CMakeLists.txt

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ find_package(rclcpp REQUIRED)
1818
find_package(std_srvs REQUIRED)
1919
find_package(ur_client_library REQUIRED)
2020
find_package(ur_dashboard_msgs REQUIRED)
21+
find_package(rclpy REQUIRED)
22+
find_package(std_msgs REQUIRED)
23+
find_package(controller_manager_msgs REQUIRED)
2124

2225
include_directories(
2326
include
@@ -30,6 +33,8 @@ set(THIS_PACKAGE_INCLUDE_DEPENDS
3033
std_srvs
3134
ur_client_library
3235
ur_dashboard_msgs
36+
std_msgs
37+
controller_manager_msgs
3338
)
3439

3540
add_library(ur_robot_driver_plugin
@@ -62,8 +67,14 @@ add_executable(dashboard_client
6267
target_link_libraries(dashboard_client ${catkin_LIBRARIES} ur_client_library::urcl)
6368
ament_target_dependencies(dashboard_client ${${PROJECT_NAME}_EXPORTED_TARGETS} ${THIS_PACKAGE_INCLUDE_DEPENDS})
6469

70+
add_executable(controller_stopper_node
71+
src/controller_stopper.cpp
72+
src/controller_stopper_node.cpp
73+
)
74+
ament_target_dependencies(controller_stopper_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${THIS_PACKAGE_INCLUDE_DEPENDS})
75+
6576
install(
66-
TARGETS dashboard_client
77+
TARGETS dashboard_client controller_stopper_node
6778
DESTINATION lib/${PROJECT_NAME}
6879
)
6980

ur_robot_driver/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,3 +92,7 @@ execution without the teach pendant. The **headless** mode might be removed in f
9292

9393
**Note for the e-Series:** In order to leverage the **headless** mode on the e-Series the robot must
9494
be in **remote_control_mode** as explained above.
95+
96+
## controller_stopper
97+
A small helper node that stops and restarts ROS controllers based on a boolean status topic. When the status goes to `false`, all running controllers except a set of predefined *consistent_controllers* gets stopped. If status returns to `true` the stopped controllers are restarted.
98+
This is done by Subscribing to a robot's running state topic. Ideally this topic is latched and only publishes on changes. However, this node only reacts on state changes, so a state published each cycle would also be fine.
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// Copyright 2019 FZI Forschungszentrum Informatik, Created on behalf of Universal Robots A/S
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
//----------------------------------------------------------------------
16+
/*!\file
17+
*
18+
* \author Felix Exner [email protected]
19+
* \date 2019-06-12
20+
*
21+
* \author Mads Holm Peters
22+
* \date 2022-02-25
23+
*
24+
*/
25+
//----------------------------------------------------------------------
26+
#ifndef UR_ROBOT_DRIVER__CONTROLLER_STOPPER_HPP_
27+
#define UR_ROBOT_DRIVER__CONTROLLER_STOPPER_HPP_
28+
29+
#include <memory>
30+
#include <string>
31+
#include <vector>
32+
33+
#include "rclcpp/rclcpp.hpp"
34+
#include "controller_manager_msgs/srv/list_controllers.hpp"
35+
#include "controller_manager_msgs/srv/switch_controller.hpp"
36+
#include "std_msgs/msg/bool.hpp"
37+
38+
class ControllerStopper
39+
{
40+
public:
41+
ControllerStopper() = delete;
42+
ControllerStopper(const rclcpp::Node::SharedPtr& node, bool stop_controllers_on_startup);
43+
virtual ~ControllerStopper() = default;
44+
45+
private:
46+
void robotRunningCallback(const std_msgs::msg::Bool::ConstSharedPtr msg);
47+
48+
/*!
49+
* \brief Queries running stoppable controllers and the controllers are stopped.
50+
*
51+
* Queries the controller manager for running controllers and compares the result with the
52+
* consistent_controllers_. The remaining running controllers are stored in stopped_controllers_
53+
* and stopped afterwards.
54+
*/
55+
void findAndStopControllers();
56+
57+
/*!
58+
* \brief Starts the controllers stored in stopped_controllers_.
59+
*
60+
*/
61+
void startControllers();
62+
63+
std::shared_ptr<rclcpp::Node> node_;
64+
rclcpp::Client<controller_manager_msgs::srv::SwitchController>::SharedPtr controller_manager_srv_;
65+
rclcpp::Client<controller_manager_msgs::srv::ListControllers>::SharedPtr controller_list_srv_;
66+
67+
rclcpp::Subscription<std_msgs::msg::Bool>::SharedPtr robot_running_sub_;
68+
69+
std::vector<std::string> consistent_controllers_;
70+
std::vector<std::string> stopped_controllers_;
71+
72+
bool stop_controllers_on_startup_;
73+
bool robot_running_;
74+
};
75+
#endif // UR_ROBOT_DRIVER__CONTROLLER_STOPPER_HPP_

ur_robot_driver/include/ur_robot_driver/hardware_interface.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ class URPositionHardwareInterface : public hardware_interface::SystemInterface
100100

101101
static constexpr double NO_NEW_CMD_ = std::numeric_limits<double>::quiet_NaN();
102102

103+
void asyncThread();
104+
103105
protected:
104106
template <typename T>
105107
void readData(const std::unique_ptr<urcl::rtde_interface::DataPackage>& data_pkg, const std::string& var_name,
@@ -155,6 +157,9 @@ class URPositionHardwareInterface : public hardware_interface::SystemInterface
155157
double target_speed_fraction_cmd_;
156158
double scaling_async_success_;
157159
bool first_pass_;
160+
bool initialized_;
161+
double system_interface_initialized_;
162+
bool async_thread_shutdown_;
158163

159164
// copy of non double values
160165
std::array<double, 18> actual_dig_out_bits_copy_;
@@ -170,11 +175,13 @@ class URPositionHardwareInterface : public hardware_interface::SystemInterface
170175

171176
bool robot_program_running_;
172177
bool non_blocking_read_;
178+
double robot_program_running_copy_;
173179

174180
PausingState pausing_state_;
175181
double pausing_ramp_up_increment_;
176182

177183
std::unique_ptr<urcl::UrDriver> ur_driver_;
184+
std::shared_ptr<std::thread> async_thread_;
178185
};
179186
} // namespace ur_robot_driver
180187

0 commit comments

Comments
 (0)