Skip to content

Commit e11a614

Browse files
authored
Move hw activate (#585)
1 parent 23f6945 commit e11a614

6 files changed

Lines changed: 96 additions & 89 deletions

File tree

husarion_ugv_controller/launch/controller.launch.py

Lines changed: 10 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,8 @@
1717

1818
from husarion_ugv_utils.logging import limit_log_level_to_info
1919
from launch import LaunchDescription
20-
from launch.actions import (
21-
DeclareLaunchArgument,
22-
GroupAction,
23-
IncludeLaunchDescription,
24-
RegisterEventHandler,
25-
Shutdown,
26-
)
20+
from launch.actions import DeclareLaunchArgument, IncludeLaunchDescription, Shutdown
2721
from launch.conditions import UnlessCondition
28-
from launch.event_handlers import OnProcessExit
2922
from launch.launch_description_sources import PythonLaunchDescriptionSource
3023
from launch.substitutions import (
3124
EnvironmentVariable,
@@ -200,54 +193,20 @@ def generate_launch_description():
200193
limit_log_level_to_info("rcl", log_level),
201194
]
202195

203-
joint_state_broadcaster_spawner = Node(
204-
package="controller_manager",
205-
executable="spawner",
206-
arguments=["joint_state_broadcaster", *spawner_common_args],
207-
namespace=namespace,
208-
emulate_tty=True,
209-
)
210-
211-
drive_controller_spawner = Node(
212-
package="controller_manager",
213-
executable="spawner",
214-
arguments=["drive_controller", *spawner_common_args],
215-
namespace=namespace,
216-
emulate_tty=True,
217-
)
218-
219-
imu_broadcaster_spawner = Node(
196+
controllers_spawner = Node(
220197
package="controller_manager",
221198
executable="spawner",
222-
arguments=["imu_broadcaster", *spawner_common_args],
199+
arguments=[
200+
"joint_state_broadcaster",
201+
"drive_controller",
202+
"imu_broadcaster",
203+
"--activate-as-group",
204+
*spawner_common_args,
205+
],
223206
namespace=namespace,
224207
emulate_tty=True,
225208
)
226209

227-
# Launch spawner one after another
228-
# when spawning without delay ros2_control_node sometimes crashed
229-
delay_drive_controller_spawner = RegisterEventHandler(
230-
event_handler=OnProcessExit(
231-
target_action=joint_state_broadcaster_spawner,
232-
on_exit=[drive_controller_spawner],
233-
),
234-
)
235-
236-
delay_imu_broadcaster_spawner = RegisterEventHandler(
237-
event_handler=OnProcessExit(
238-
target_action=drive_controller_spawner,
239-
on_exit=[imu_broadcaster_spawner],
240-
),
241-
)
242-
243-
spawners = GroupAction(
244-
actions=[
245-
joint_state_broadcaster_spawner,
246-
delay_drive_controller_spawner,
247-
delay_imu_broadcaster_spawner,
248-
]
249-
)
250-
251210
actions = [
252211
declare_common_dir_path_arg,
253212
declare_robot_model_arg, # robot_model is used by wheel_type
@@ -259,7 +218,7 @@ def generate_launch_description():
259218
SetParameter(name="use_sim_time", value=use_sim),
260219
load_urdf,
261220
control_node,
262-
spawners,
221+
controllers_spawner,
263222
]
264223

265224
return LaunchDescription(actions)

husarion_ugv_hardware_interfaces/include/husarion_ugv_hardware_interfaces/robot_system/ugv_system.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ class UGVSystem : public hardware_interface::SystemInterface
9494
void ConfigureRobotDriver();
9595
virtual void DefineRobotDriver() = 0;
9696
virtual void ConfigureEStop(); // virtual for mocking
97+
void ResetEStop();
9798

9899
void UpdateMotorsState();
99100
void UpdateDriverState();

husarion_ugv_hardware_interfaces/src/robot_system/ugv_system.cpp

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -80,22 +80,6 @@ CallbackReturn UGVSystem::on_configure(const rclcpp_lifecycle::State &)
8080
return CallbackReturn::ERROR;
8181
}
8282

83-
return CallbackReturn::SUCCESS;
84-
}
85-
86-
CallbackReturn UGVSystem::on_cleanup(const rclcpp_lifecycle::State &)
87-
{
88-
robot_driver_->Deinitialize();
89-
robot_driver_.reset();
90-
91-
gpio_controller_.reset();
92-
e_stop_.reset();
93-
94-
return CallbackReturn::SUCCESS;
95-
}
96-
97-
CallbackReturn UGVSystem::on_activate(const rclcpp_lifecycle::State &)
98-
{
9983
std::fill(hw_commands_velocities_.begin(), hw_commands_velocities_.end(), 0.0);
10084
std::fill(hw_states_positions_.begin(), hw_states_positions_.end(), 0.0);
10185
std::fill(hw_states_velocities_.begin(), hw_states_velocities_.end(), 0.0);
@@ -139,7 +123,7 @@ CallbackReturn UGVSystem::on_activate(const rclcpp_lifecycle::State &)
139123
auto e_stop_reset_qos = rclcpp::ServicesQoS();
140124
e_stop_reset_qos.keep_last(1);
141125
system_ros_interface_->AddService<TriggerSrv, std::function<void()>>(
142-
"hardware/e_stop_reset", std::bind(&EStopInterface::ResetEStop, e_stop_), 2,
126+
"hardware/e_stop_reset", std::bind(&UGVSystem::ResetEStop, this), 2,
143127
rclcpp::CallbackGroupType::MutuallyExclusive, e_stop_reset_qos);
144128

145129
system_ros_interface_->AddDiagnosticTask(
@@ -159,6 +143,24 @@ CallbackReturn UGVSystem::on_activate(const rclcpp_lifecycle::State &)
159143
return CallbackReturn::SUCCESS;
160144
}
161145

146+
CallbackReturn UGVSystem::on_cleanup(const rclcpp_lifecycle::State &)
147+
{
148+
robot_driver_->Deinitialize();
149+
robot_driver_.reset();
150+
151+
gpio_controller_.reset();
152+
153+
system_ros_interface_.reset();
154+
e_stop_.reset();
155+
156+
return CallbackReturn::SUCCESS;
157+
}
158+
159+
CallbackReturn UGVSystem::on_activate(const rclcpp_lifecycle::State &)
160+
{
161+
return CallbackReturn::SUCCESS;
162+
}
163+
162164
CallbackReturn UGVSystem::on_deactivate(const rclcpp_lifecycle::State &)
163165
{
164166
try {
@@ -168,8 +170,6 @@ CallbackReturn UGVSystem::on_deactivate(const rclcpp_lifecycle::State &)
168170
return CallbackReturn::ERROR;
169171
}
170172

171-
system_ros_interface_.reset();
172-
173173
return CallbackReturn::SUCCESS;
174174
}
175175

@@ -263,9 +263,10 @@ return_type UGVSystem::read(const rclcpp::Time & time, const rclcpp::Duration &
263263

264264
return_type UGVSystem::write(const rclcpp::Time & /* time */, const rclcpp::Duration & /* period */)
265265
{
266+
const auto lifecycle_state = this->get_lifecycle_state().id();
266267
const bool e_stop = e_stop_->ReadEStopState();
267268

268-
if (!e_stop) {
269+
if (lifecycle_state == lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE && !e_stop) {
269270
HandleRobotDriverWriteOperation([this] {
270271
const auto speed_cmds = GetSpeedCommands();
271272
robot_driver_->SendSpeedCommands(speed_cmds);
@@ -456,6 +457,18 @@ void UGVSystem::ConfigureEStop()
456457
RCLCPP_INFO(logger_, "Successfully configured E-Stop");
457458
}
458459

460+
void UGVSystem::ResetEStop()
461+
{
462+
const auto lifecycle_state = this->get_lifecycle_state().id();
463+
464+
if (lifecycle_state != lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE) {
465+
throw std::runtime_error(
466+
"Can't reset E-Stop when the hardware interface is not in ACTIVE state.");
467+
}
468+
469+
e_stop_->ResetEStop();
470+
}
471+
459472
void UGVSystem::UpdateMotorsState()
460473
{
461474
try {

husarion_ugv_hardware_interfaces/test/unit/robot_system/test_lynx_system.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,8 @@ class TestLynxSystem : public ::testing::Test
8686
public:
8787
TestLynxSystem()
8888
{
89+
rclcpp::init(0, nullptr);
90+
8991
lynx_system_ = std::make_shared<LynxSystemWrapper>();
9092

9193
hardware_info_ = husarion_ugv_hardware_interfaces_test::GenerateDefaultHardwareInfo();
@@ -95,7 +97,7 @@ class TestLynxSystem : public ::testing::Test
9597
lynx_system_->on_configure(rclcpp_lifecycle::State());
9698
}
9799

98-
~TestLynxSystem() {}
100+
~TestLynxSystem() { rclcpp::shutdown(); }
99101

100102
protected:
101103
std::shared_ptr<LynxSystemWrapper> lynx_system_;

husarion_ugv_hardware_interfaces/test/unit/robot_system/test_panther_system.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,8 @@ class TestPantherSystem : public ::testing::Test
100100
public:
101101
TestPantherSystem()
102102
{
103+
rclcpp::init(0, nullptr);
104+
103105
panther_system_ = std::make_shared<PantherSystemWrapper>();
104106

105107
hardware_info_ = husarion_ugv_hardware_interfaces_test::GenerateDefaultHardwareInfo();
@@ -110,7 +112,7 @@ class TestPantherSystem : public ::testing::Test
110112
panther_system_->on_configure(rclcpp_lifecycle::State());
111113
}
112114

113-
~TestPantherSystem() {}
115+
~TestPantherSystem() { rclcpp::shutdown(); }
114116

115117
protected:
116118
std::shared_ptr<PantherSystemWrapper> panther_system_;

husarion_ugv_hardware_interfaces/test/unit/robot_system/test_ugv_system.cpp

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,6 @@ class MockUGVSystem : public husarion_ugv_hardware_interfaces::UGVSystem
6767
MOCK_METHOD(void, DiagnoseErrors, (diagnostic_updater::DiagnosticStatusWrapper &), (override));
6868
MOCK_METHOD(void, DiagnoseStatus, (diagnostic_updater::DiagnosticStatusWrapper &), (override));
6969

70-
void DefaultDefineRobotDriver()
71-
{
72-
robot_driver_ =
73-
std::make_shared<husarion_ugv_hardware_interfaces_test::MockRobotDriver::NiceMock>();
74-
}
75-
7670
void SetHwCommandVelocity(const std::vector<double> & velocity)
7771
{
7872
hw_commands_velocities_ = velocity;
@@ -140,27 +134,36 @@ TEST_F(TestUGVSystem, OnInit)
140134

141135
TEST_F(TestUGVSystem, OnConfigure)
142136
{
137+
rclcpp::init(0, nullptr);
138+
143139
ASSERT_NO_THROW(ugv_system_->on_init(hardware_info_));
144140

145-
EXPECT_CALL(*ugv_system_, DefineRobotDriver()).WillOnce(::testing::Invoke([&]() {
146-
ugv_system_->DefaultDefineRobotDriver();
147-
}));
141+
EXPECT_CALL(*ugv_system_, DefineRobotDriver()).Times(1);
148142
EXPECT_CALL(*ugv_system_, ConfigureGPIOController()).Times(1);
149143
EXPECT_CALL(*ugv_system_, ConfigureEStop()).Times(1);
144+
EXPECT_CALL(*ugv_system_->GetMockRobotDriver(), Activate()).Times(1);
145+
EXPECT_CALL(*ugv_system_->GetMockGPIOController(), QueryControlInterfaceIOStates()).Times(1);
146+
EXPECT_CALL(*ugv_system_->GetMockEStop(), ReadEStopState()).Times(1);
150147
auto callback_return = ugv_system_->on_configure(rclcpp_lifecycle::State());
151148

152149
EXPECT_EQ(callback_return, hardware_interface::CallbackReturn::SUCCESS);
150+
151+
rclcpp::shutdown();
153152
}
154153

155154
TEST_F(TestUGVSystem, OnCleanup)
156155
{
156+
rclcpp::init(0, nullptr);
157+
157158
ASSERT_NO_THROW(ugv_system_->on_init(hardware_info_));
158159
ASSERT_NO_THROW(ugv_system_->on_configure(rclcpp_lifecycle::State()));
159160

160161
EXPECT_CALL(*ugv_system_->GetMockRobotDriver(), Deinitialize()).Times(1);
161162
auto callback_return = ugv_system_->on_cleanup(rclcpp_lifecycle::State());
162163

163164
EXPECT_EQ(callback_return, hardware_interface::CallbackReturn::SUCCESS);
165+
166+
rclcpp::shutdown();
164167
}
165168

166169
TEST_F(TestUGVSystem, OnActivate)
@@ -169,10 +172,6 @@ TEST_F(TestUGVSystem, OnActivate)
169172

170173
ASSERT_NO_THROW(ugv_system_->on_init(hardware_info_));
171174
ASSERT_NO_THROW(ugv_system_->on_configure(rclcpp_lifecycle::State()));
172-
173-
EXPECT_CALL(*ugv_system_->GetMockRobotDriver(), Activate()).Times(1);
174-
EXPECT_CALL(*ugv_system_->GetMockGPIOController(), QueryControlInterfaceIOStates()).Times(1);
175-
EXPECT_CALL(*ugv_system_->GetMockEStop(), ReadEStopState()).Times(1);
176175
auto callback_return = ugv_system_->on_activate(rclcpp_lifecycle::State());
177176

178177
EXPECT_EQ(callback_return, hardware_interface::CallbackReturn::SUCCESS);
@@ -198,6 +197,8 @@ TEST_F(TestUGVSystem, OnDeactivate)
198197

199198
TEST_F(TestUGVSystem, OnShutdown)
200199
{
200+
rclcpp::init(0, nullptr);
201+
201202
ASSERT_NO_THROW(ugv_system_->on_init(hardware_info_));
202203
ASSERT_NO_THROW(ugv_system_->on_configure(rclcpp_lifecycle::State()));
203204

@@ -206,10 +207,14 @@ TEST_F(TestUGVSystem, OnShutdown)
206207
auto callback_return = ugv_system_->on_shutdown(rclcpp_lifecycle::State());
207208

208209
EXPECT_EQ(callback_return, hardware_interface::CallbackReturn::SUCCESS);
210+
211+
rclcpp::shutdown();
209212
}
210213

211214
TEST_F(TestUGVSystem, OnError)
212215
{
216+
rclcpp::init(0, nullptr);
217+
213218
ASSERT_NO_THROW(ugv_system_->on_init(hardware_info_));
214219
ASSERT_NO_THROW(ugv_system_->on_configure(rclcpp_lifecycle::State()));
215220

@@ -218,6 +223,8 @@ TEST_F(TestUGVSystem, OnError)
218223
auto callback_return = ugv_system_->on_error(rclcpp_lifecycle::State());
219224

220225
EXPECT_EQ(callback_return, hardware_interface::CallbackReturn::SUCCESS);
226+
227+
rclcpp::shutdown();
221228
}
222229

223230
TEST_F(TestUGVSystem, ExportStateInterfacesInitialValues)
@@ -359,19 +366,42 @@ TEST_F(TestUGVSystem, Write)
359366

360367
const auto velocity = std::vector<float>{1.0, 2.0, 3.0, 4.0};
361368

369+
// System is deactivated, no speed commands sent
362370
ASSERT_NO_THROW(ugv_system_->on_init(hardware_info_));
363371
ASSERT_NO_THROW(ugv_system_->on_configure(rclcpp_lifecycle::State()));
364-
ASSERT_NO_THROW(ugv_system_->on_activate(rclcpp_lifecycle::State()));
365372

366-
EXPECT_CALL(*ugv_system_, GetSpeedCommands()).WillOnce(::testing::Return(velocity));
367373
EXPECT_CALL(*ugv_system_->GetMockEStop(), ReadEStopState()).Times(1);
368-
EXPECT_CALL(*ugv_system_->GetMockRobotDriver(), SendSpeedCommands(velocity)).Times(1);
374+
EXPECT_CALL(*ugv_system_, GetSpeedCommands()).Times(0);
375+
EXPECT_CALL(*ugv_system_->GetMockRobotDriver(), SendSpeedCommands(velocity)).Times(0);
369376

370377
auto callback_return = ugv_system_->write(
371378
rclcpp::Time(0, 0, RCL_ROS_TIME), rclcpp::Duration(0, 0));
372379

373380
EXPECT_EQ(callback_return, hardware_interface::return_type::OK);
374381

382+
// System is activated, speed commands sent
383+
ugv_system_->set_lifecycle_state(
384+
rclcpp_lifecycle::State(lifecycle_msgs::msg::State::PRIMARY_STATE_ACTIVE, "test_active"));
385+
386+
ASSERT_NO_THROW(ugv_system_->on_activate(rclcpp_lifecycle::State()));
387+
388+
EXPECT_CALL(*ugv_system_->GetMockEStop(), ReadEStopState()).Times(1);
389+
EXPECT_CALL(*ugv_system_, GetSpeedCommands()).WillOnce(::testing::Return(velocity));
390+
EXPECT_CALL(*ugv_system_->GetMockRobotDriver(), SendSpeedCommands(velocity)).Times(1);
391+
392+
callback_return = ugv_system_->write(rclcpp::Time(0, 0, RCL_ROS_TIME), rclcpp::Duration(0, 0));
393+
394+
EXPECT_EQ(callback_return, hardware_interface::return_type::OK);
395+
396+
// System is activated, but e-stop was triggered
397+
EXPECT_CALL(*ugv_system_->GetMockEStop(), ReadEStopState()).WillOnce(::testing::Return(true));
398+
EXPECT_CALL(*ugv_system_, GetSpeedCommands()).Times(0);
399+
EXPECT_CALL(*ugv_system_->GetMockRobotDriver(), SendSpeedCommands(velocity)).Times(0);
400+
401+
callback_return = ugv_system_->write(rclcpp::Time(0, 0, RCL_ROS_TIME), rclcpp::Duration(0, 0));
402+
403+
EXPECT_EQ(callback_return, hardware_interface::return_type::OK);
404+
375405
rclcpp::shutdown();
376406
}
377407

0 commit comments

Comments
 (0)