Skip to content

Commit 279b2d4

Browse files
authored
Introduce fault controller (#63)
* Add fault controller. * Prepare for switching * Fix controller switching and starting. * Keep servoing mode on startup. * Don t change servoing mode on deactivation. * Fix mode switching. * Move all mode switching into constructor. * Add fault publisher. * Read servoing mode in the loop. * Implement required prettyfing changes. * Add realtime publisher. * Add additional debug statement on fault reset. * Formatting fix. * Pre-commit on kortex2_controllers and kortex2_driver.
1 parent 3616fa8 commit 279b2d4

File tree

5 files changed

+244
-1
lines changed

5 files changed

+244
-1
lines changed

fault_controller/kortex2_controllers/CMakeLists.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,18 @@ find_package(ament_cmake REQUIRED)
1010
find_package(ament_cmake_ros REQUIRED)
1111
find_package(controller_interface REQUIRED)
1212
find_package(geometry_msgs REQUIRED)
13+
find_package(example_interfaces REQUIRED)
1314
find_package(rclcpp REQUIRED)
1415

1516
set(THIS_PACKAGE_INCLUDE_DEPENDS
1617
controller_interface
1718
geometry_msgs
19+
example_interfaces
1820
)
1921

2022
include_directories(include)
2123

22-
add_library(${PROJECT_NAME} SHARED src/twist_controller.cpp)
24+
add_library(${PROJECT_NAME} SHARED src/twist_controller.cpp src/fault_controller.cpp)
2325
target_include_directories(${PROJECT_NAME} PRIVATE
2426
include
2527
)

fault_controller/kortex2_controllers/controller_plugins.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,9 @@
44
6dof twist controller
55
</description>
66
</class>
7+
<class name="kortex2_controllers/FaultController" type="kortex2_controllers::FaultController" base_class_type="controller_interface::ControllerInterface">
8+
<description>
9+
ros2 fault controller for kinova api
10+
</description>
11+
</class>
712
</library>
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// Copyright 2021, PickNik Inc.
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 Lovro Ivanov [email protected]
19+
* \date 2021-11-25
20+
*
21+
*/
22+
//----------------------------------------------------------------------
23+
24+
#ifndef KORTEX2_CONTROLLERS__FAULT_CONTROLLER_HPP_
25+
#define KORTEX2_CONTROLLERS__FAULT_CONTROLLER_HPP_
26+
27+
#include <limits>
28+
#include <memory>
29+
30+
#include "controller_interface/controller_interface.hpp"
31+
#include "example_interfaces/msg/bool.hpp"
32+
#include "example_interfaces/srv/trigger.hpp"
33+
#include "kortex2_controllers/visibility_control.h"
34+
#include "realtime_tools/realtime_publisher.h"
35+
36+
namespace kortex2_controllers
37+
{
38+
enum CommandInterfaces
39+
{
40+
RESET_FAULT_CMD = 0u,
41+
RESET_FAULT_ASYNC_SUCCESS = 1u,
42+
};
43+
enum StateInterfaces
44+
{
45+
IN_FAULT = 0u,
46+
};
47+
using CmdType = example_interfaces::srv::Trigger;
48+
using FbkType = example_interfaces::msg::Bool;
49+
using CallbackReturn = rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn;
50+
51+
class FaultController : public controller_interface::ControllerInterface
52+
{
53+
public:
54+
KORTEX2_CONTROLLERS_PUBLIC
55+
FaultController();
56+
57+
KORTEX2_CONTROLLERS_PUBLIC
58+
controller_interface::InterfaceConfiguration command_interface_configuration() const override;
59+
60+
KORTEX2_CONTROLLERS_PUBLIC
61+
controller_interface::InterfaceConfiguration state_interface_configuration() const override;
62+
63+
KORTEX2_CONTROLLERS_PUBLIC
64+
CallbackReturn on_init() override;
65+
66+
KORTEX2_CONTROLLERS_PUBLIC
67+
CallbackReturn on_configure(const rclcpp_lifecycle::State & previous_state) override;
68+
69+
KORTEX2_CONTROLLERS_PUBLIC
70+
CallbackReturn on_activate(const rclcpp_lifecycle::State & previous_state) override;
71+
72+
KORTEX2_CONTROLLERS_PUBLIC
73+
CallbackReturn on_deactivate(const rclcpp_lifecycle::State & previous_state) override;
74+
75+
KORTEX2_CONTROLLERS_PUBLIC
76+
controller_interface::return_type update(
77+
const rclcpp::Time & time, const rclcpp::Duration & period) override;
78+
79+
private:
80+
bool resetFault(const CmdType::Request::SharedPtr req, CmdType::Response::SharedPtr resp);
81+
82+
using StatePublisher = realtime_tools::RealtimePublisher<FbkType>;
83+
rclcpp::Publisher<FbkType>::SharedPtr fault_pub_;
84+
std::unique_ptr<StatePublisher> realtime_publisher_;
85+
FbkType state_;
86+
rclcpp::Service<CmdType>::SharedPtr trigger_command_srv_;
87+
88+
static constexpr double ISSUE_CMD = 1.0;
89+
static constexpr double ASYNC_WAITING = 2.0;
90+
static constexpr double NO_CMD = std::numeric_limits<double>::quiet_NaN();
91+
};
92+
93+
} // namespace kortex2_controllers
94+
95+
#endif // KORTEX2_CONTROLLERS__FAULT_CONTROLLER_HPP_

fault_controller/kortex2_controllers/package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
<depend>controller_interface</depend>
1313
<depend>geometry_msgs</depend>
14+
<depend>example_interfaces</depend>
1415
<depend>rclcpp</depend>
1516

1617
<export>
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
// Copyright 2021, PickNik Inc.
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 Lovro Ivanov [email protected]
19+
* \date 2021-11-25
20+
*
21+
*/
22+
//----------------------------------------------------------------------
23+
24+
#include "kortex2_controllers/fault_controller.hpp"
25+
#include <memory>
26+
#include "hardware_interface/loaned_command_interface.hpp"
27+
28+
namespace kortex2_controllers
29+
{
30+
using hardware_interface::LoanedCommandInterface;
31+
32+
FaultController::FaultController()
33+
: controller_interface::ControllerInterface(), trigger_command_srv_(nullptr)
34+
{
35+
}
36+
37+
controller_interface::InterfaceConfiguration FaultController::command_interface_configuration()
38+
const
39+
{
40+
controller_interface::InterfaceConfiguration config;
41+
config.type = controller_interface::interface_configuration_type::INDIVIDUAL;
42+
43+
config.names.emplace_back("reset_fault/command");
44+
config.names.emplace_back("reset_fault/async_success");
45+
46+
return config;
47+
}
48+
49+
controller_interface::InterfaceConfiguration FaultController::state_interface_configuration() const
50+
{
51+
controller_interface::InterfaceConfiguration config;
52+
config.type = controller_interface::interface_configuration_type::INDIVIDUAL;
53+
54+
config.names.emplace_back("reset_fault/internal_fault");
55+
56+
return config;
57+
}
58+
59+
CallbackReturn FaultController::on_init() { return CallbackReturn::SUCCESS; }
60+
61+
controller_interface::return_type FaultController::update(
62+
const rclcpp::Time & /*time*/, const rclcpp::Duration & /*period*/)
63+
{
64+
if (realtime_publisher_ && realtime_publisher_->trylock())
65+
{
66+
state_.data = static_cast<bool>(state_interfaces_[StateInterfaces::IN_FAULT].get_value());
67+
realtime_publisher_->msg_.data = state_.data;
68+
realtime_publisher_->unlockAndPublish();
69+
}
70+
71+
return controller_interface::return_type::OK;
72+
}
73+
74+
CallbackReturn FaultController::on_configure(const rclcpp_lifecycle::State & /*previous_state*/)
75+
{
76+
return CallbackReturn::SUCCESS;
77+
}
78+
79+
CallbackReturn FaultController::on_activate(const rclcpp_lifecycle::State & /*previous_state*/)
80+
{
81+
command_interfaces_[CommandInterfaces::RESET_FAULT_CMD].set_value(NO_CMD);
82+
command_interfaces_[CommandInterfaces::RESET_FAULT_ASYNC_SUCCESS].set_value(NO_CMD);
83+
try
84+
{
85+
fault_pub_ = node_->create_publisher<FbkType>("~/internal_fault", 1);
86+
realtime_publisher_ = std::make_unique<StatePublisher>(fault_pub_);
87+
}
88+
catch (const std::exception & e)
89+
{
90+
fprintf(
91+
stderr, "Exception thrown during publisher creation at configure stage with message : %s \n",
92+
e.what());
93+
return CallbackReturn::ERROR;
94+
}
95+
trigger_command_srv_ = node_->create_service<example_interfaces::srv::Trigger>(
96+
"~/reset_fault",
97+
std::bind(&FaultController::resetFault, this, std::placeholders::_1, std::placeholders::_2));
98+
99+
return CallbackReturn::SUCCESS;
100+
}
101+
102+
CallbackReturn FaultController::on_deactivate(const rclcpp_lifecycle::State & /*previous_state*/)
103+
{
104+
trigger_command_srv_.reset();
105+
command_interfaces_[CommandInterfaces::RESET_FAULT_CMD].set_value(NO_CMD);
106+
command_interfaces_[CommandInterfaces::RESET_FAULT_ASYNC_SUCCESS].set_value(NO_CMD);
107+
108+
return CallbackReturn::SUCCESS;
109+
}
110+
111+
bool FaultController::resetFault(
112+
const CmdType::Request::SharedPtr /*req*/, CmdType::Response::SharedPtr resp)
113+
{
114+
command_interfaces_[CommandInterfaces::RESET_FAULT_ASYNC_SUCCESS].set_value(ASYNC_WAITING);
115+
command_interfaces_[CommandInterfaces::RESET_FAULT_CMD].set_value(ISSUE_CMD);
116+
117+
RCLCPP_INFO(node_->get_logger(), "Trying to reset faults on kinova controller.");
118+
119+
while (command_interfaces_[CommandInterfaces::RESET_FAULT_ASYNC_SUCCESS].get_value() ==
120+
ASYNC_WAITING)
121+
{
122+
// Asynchronous wait until the hardware interface has set the io value
123+
std::this_thread::sleep_for(std::chrono::milliseconds(50));
124+
}
125+
resp->success = static_cast<bool>(
126+
command_interfaces_[CommandInterfaces::RESET_FAULT_ASYNC_SUCCESS].get_value());
127+
128+
RCLCPP_INFO(
129+
node_->get_logger(), "Resetting fault on kinova controller '%s'!",
130+
resp->success ? "succeeded" : "failed");
131+
132+
return resp->success;
133+
}
134+
135+
} // namespace kortex2_controllers
136+
137+
#include "pluginlib/class_list_macros.hpp"
138+
139+
PLUGINLIB_EXPORT_CLASS(
140+
kortex2_controllers::FaultController, controller_interface::ControllerInterface)

0 commit comments

Comments
 (0)