Skip to content

Commit f617d2a

Browse files
Rewrite resource storage and add mimic test (#44)
1 parent cd86811 commit f617d2a

File tree

10 files changed

+1083
-228
lines changed

10 files changed

+1083
-228
lines changed

joint_state_topic_hardware_interface/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,12 +81,19 @@ if(BUILD_TESTING)
8181
rclcpp::rclcpp
8282
rclcpp_action::rclcpp_action
8383
)
84+
add_executable(test_gripper test/gripper/test_gripper.cpp)
85+
target_link_libraries(test_gripper PUBLIC
86+
${std_msgs_TARGETS}
87+
rclcpp::rclcpp
88+
)
8489
function(add_ros_isolated_launch_test path)
8590
set(RUNNER "${ament_cmake_ros_DIR}/run_test_isolated.py")
8691
add_launch_test("${path}" RUNNER "${RUNNER}" ${ARGN})
8792
endfunction()
8893
add_ros_isolated_launch_test(
8994
test/rrr/position.test.py)
95+
add_ros_isolated_launch_test(
96+
test/gripper/position.test.py)
9097
endif()
9198

9299
pluginlib_export_plugin_description_file(hardware_interface joint_state_topic_hardware_interface_plugin_description.xml)

joint_state_topic_hardware_interface/include/joint_state_topic_hardware_interface/joint_state_topic_hardware_interface.hpp

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -38,10 +38,6 @@ class JointStateTopicSystem : public hardware_interface::SystemInterface
3838
public:
3939
CallbackReturn on_init(const hardware_interface::HardwareComponentInterfaceParams& params) override;
4040

41-
std::vector<hardware_interface::StateInterface> export_state_interfaces() override;
42-
43-
std::vector<hardware_interface::CommandInterface> export_command_interfaces() override;
44-
4541
hardware_interface::return_type read(const rclcpp::Time& time, const rclcpp::Duration& period) override;
4642

4743
hardware_interface::return_type write(const rclcpp::Time& /*time*/, const rclcpp::Duration& /*period*/) override;
@@ -52,31 +48,9 @@ class JointStateTopicSystem : public hardware_interface::SystemInterface
5248
sensor_msgs::msg::JointState latest_joint_state_;
5349
bool sum_wrapped_joint_states_{ false };
5450

55-
/// Use standard interfaces for joints because they are relevant for dynamic behavior
56-
std::array<std::string, 4> standard_interfaces_ = {
57-
{ hardware_interface::HW_IF_POSITION, hardware_interface::HW_IF_VELOCITY, hardware_interface::HW_IF_ACCELERATION,
58-
hardware_interface::HW_IF_EFFORT }
59-
};
60-
61-
struct MimicJoint
62-
{
63-
std::size_t joint_index;
64-
std::size_t mimicked_joint_index;
65-
double multiplier = 1.0;
66-
};
67-
std::vector<MimicJoint> mimic_joints_;
68-
69-
/// The size of this vector is (standard_interfaces_.size() x nr_joints)
70-
std::vector<std::vector<double>> joint_command_values_;
71-
std::vector<std::vector<double>> joint_state_values_;
72-
7351
// If the difference between the current joint state and joint command is less than this value,
7452
// the joint command will not be published.
7553
double trigger_joint_command_threshold_ = 1e-5;
76-
77-
template <typename HandleType>
78-
bool getInterface(const std::string& name, const std::string& interface_name, const size_t vector_index,
79-
std::vector<std::vector<double>>& values, std::vector<HandleType>& interfaces);
8054
};
8155

8256
} // namespace joint_state_topic_hardware_interface

joint_state_topic_hardware_interface/package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
<test_depend>ament_cmake_ros</test_depend>
3131
<test_depend>control_msgs</test_depend>
3232
<test_depend>controller_manager</test_depend>
33+
<test_depend>forward_command_controller</test_depend>
3334
<test_depend>joint_state_broadcaster</test_depend>
3435
<test_depend>joint_trajectory_controller</test_depend>
3536
<test_depend>launch_ros</test_depend>

joint_state_topic_hardware_interface/src/joint_state_topic_hardware_interface.cpp

Lines changed: 75 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,14 @@ namespace
2929
{
3030
/** @brief Sums the total rotation for joint states that wrap from 2*pi to -2*pi
3131
when rotating in the positive direction */
32-
void sumRotationFromMinus2PiTo2Pi(const double current_wrapped_rad, double& total_rotation)
32+
double sumRotationFromMinus2PiTo2Pi(const double current_wrapped_rad, double total_rotation_in)
3333
{
3434
double delta = 0;
35-
angles::shortest_angular_distance_with_large_limits(total_rotation, current_wrapped_rad, 2 * M_PI, -2 * M_PI, delta);
35+
angles::shortest_angular_distance_with_large_limits(total_rotation_in, current_wrapped_rad, 2 * M_PI, -2 * M_PI,
36+
delta);
3637

3738
// Add the corrected delta to the total rotation
38-
total_rotation += delta;
39+
return total_rotation_in + delta;
3940
}
4041
} // namespace
4142

@@ -54,64 +55,6 @@ CallbackReturn JointStateTopicSystem::on_init(const hardware_interface::Hardware
5455
return CallbackReturn::ERROR;
5556
}
5657

57-
// Initialize storage for all joints' standard interfaces, regardless of their existence and set all values to nan
58-
joint_command_values_.resize(standard_interfaces_.size());
59-
joint_state_values_.resize(standard_interfaces_.size());
60-
for (auto i = 0u; i < standard_interfaces_.size(); i++)
61-
{
62-
joint_command_values_[i].resize(get_hardware_info().joints.size(), 0.0);
63-
joint_state_values_[i].resize(get_hardware_info().joints.size(), 0.0);
64-
}
65-
66-
// Initial command values
67-
for (auto i = 0u; i < get_hardware_info().joints.size(); i++)
68-
{
69-
const auto& component = get_hardware_info().joints[i];
70-
for (const auto& interface : component.state_interfaces)
71-
{
72-
auto it = std::find(standard_interfaces_.begin(), standard_interfaces_.end(), interface.name);
73-
// If interface name is found in the interfaces list
74-
if (it != standard_interfaces_.end())
75-
{
76-
auto index = static_cast<std::size_t>(std::distance(standard_interfaces_.begin(), it));
77-
// Check the initial_value param is used
78-
if (!interface.initial_value.empty())
79-
{
80-
joint_state_values_[index][i] = std::stod(interface.initial_value);
81-
joint_command_values_[index][i] = std::stod(interface.initial_value);
82-
}
83-
}
84-
}
85-
}
86-
87-
// Search for mimic joints
88-
for (auto i = 0u; i < get_hardware_info().joints.size(); ++i)
89-
{
90-
const auto& joint = get_hardware_info().joints.at(i);
91-
if (joint.parameters.find("mimic") != joint.parameters.cend())
92-
{
93-
const auto mimicked_joint_it = std::find_if(
94-
get_hardware_info().joints.begin(), get_hardware_info().joints.end(),
95-
[&mimicked_joint = joint.parameters.at("mimic")](const hardware_interface::ComponentInfo& joint_info) {
96-
return joint_info.name == mimicked_joint;
97-
});
98-
if (mimicked_joint_it == get_hardware_info().joints.cend())
99-
{
100-
throw std::runtime_error(std::string("Mimicked joint '") + joint.parameters.at("mimic") + "' not found");
101-
}
102-
MimicJoint mimic_joint;
103-
mimic_joint.joint_index = i;
104-
mimic_joint.mimicked_joint_index =
105-
static_cast<std::size_t>(std::distance(get_hardware_info().joints.begin(), mimicked_joint_it));
106-
auto param_it = joint.parameters.find("multiplier");
107-
if (param_it != joint.parameters.end())
108-
{
109-
mimic_joint.multiplier = std::stod(joint.parameters.at("multiplier"));
110-
}
111-
mimic_joints_.push_back(mimic_joint);
112-
}
113-
}
114-
11558
const auto get_hardware_parameter = [this](const std::string& parameter_name, const std::string& default_value) {
11659
if (auto it = get_hardware_info().hardware_parameters.find(parameter_name);
11760
it != get_hardware_info().hardware_parameters.end())
@@ -143,164 +86,130 @@ CallbackReturn JointStateTopicSystem::on_init(const hardware_interface::Hardware
14386
return CallbackReturn::SUCCESS;
14487
}
14588

146-
std::vector<hardware_interface::StateInterface> JointStateTopicSystem::export_state_interfaces()
147-
{
148-
std::vector<hardware_interface::StateInterface> state_interfaces;
149-
150-
// Joints' state interfaces
151-
for (auto i = 0u; i < get_hardware_info().joints.size(); i++)
152-
{
153-
const auto& joint = get_hardware_info().joints[i];
154-
for (const auto& interface : joint.state_interfaces)
155-
{
156-
// Add interface: if not in the standard list then use "other" interface list
157-
if (!getInterface(joint.name, interface.name, i, joint_state_values_, state_interfaces))
158-
{
159-
throw std::runtime_error("Interface is not found in the standard list.");
160-
}
161-
}
162-
}
163-
164-
return state_interfaces;
165-
}
166-
167-
std::vector<hardware_interface::CommandInterface> JointStateTopicSystem::export_command_interfaces()
168-
{
169-
std::vector<hardware_interface::CommandInterface> command_interfaces;
170-
171-
// Joints' state interfaces
172-
for (auto i = 0u; i < get_hardware_info().joints.size(); i++)
173-
{
174-
const auto& joint = get_hardware_info().joints[i];
175-
for (const auto& interface : joint.command_interfaces)
176-
{
177-
if (!getInterface(joint.name, interface.name, i, joint_command_values_, command_interfaces))
178-
{
179-
throw std::runtime_error("Interface is not found in the standard list.");
180-
}
181-
}
182-
}
183-
184-
return command_interfaces;
185-
}
186-
18789
hardware_interface::return_type JointStateTopicSystem::read(const rclcpp::Time& /*time*/,
18890
const rclcpp::Duration& /*period*/)
18991
{
92+
const auto& joints = get_hardware_info().joints;
19093
for (std::size_t i = 0; i < latest_joint_state_.name.size(); ++i)
19194
{
192-
const auto& joints = get_hardware_info().joints;
193-
auto it = std::find_if(joints.begin(), joints.end(),
194-
[&joint_name = std::as_const(latest_joint_state_.name[i])](
195-
const hardware_interface::ComponentInfo& info) { return joint_name == info.name; });
95+
const auto it = std::find_if(joints.begin(), joints.end(),
96+
[name = latest_joint_state_.name[i]](const hardware_interface::ComponentInfo& joint) {
97+
return joint.name == name;
98+
});
19699
if (it != joints.end())
197100
{
198-
auto j = static_cast<std::size_t>(std::distance(joints.begin(), it));
199-
if (sum_wrapped_joint_states_)
101+
if (std::find_if(get_hardware_info().mimic_joints.begin(), get_hardware_info().mimic_joints.end(),
102+
[idx = static_cast<std::size_t>(std::distance(joints.begin(), it))](
103+
const hardware_interface::MimicJoint& mimic_joint) {
104+
return idx == mimic_joint.joint_index;
105+
}) != get_hardware_info().mimic_joints.end())
200106
{
201-
sumRotationFromMinus2PiTo2Pi(latest_joint_state_.position[i], joint_state_values_[POSITION_INTERFACE_INDEX][j]);
107+
// mimic joints are updated at the end of this function
108+
continue;
202109
}
203-
else
110+
111+
if (!latest_joint_state_.position.empty() && std::isfinite(latest_joint_state_.position.at(i)))
204112
{
205-
joint_state_values_[POSITION_INTERFACE_INDEX][j] = latest_joint_state_.position[i];
113+
if (sum_wrapped_joint_states_)
114+
{
115+
auto name = latest_joint_state_.name[i] + "/" + hardware_interface::HW_IF_POSITION;
116+
117+
set_state(name, sumRotationFromMinus2PiTo2Pi(latest_joint_state_.position.at(i), get_state(name)));
118+
}
119+
else
120+
{
121+
set_state(latest_joint_state_.name[i] + "/" + hardware_interface::HW_IF_POSITION,
122+
latest_joint_state_.position.at(i));
123+
}
206124
}
207-
if (!latest_joint_state_.velocity.empty())
125+
if (!latest_joint_state_.velocity.empty() && std::isfinite(latest_joint_state_.velocity.at(i)))
208126
{
209-
joint_state_values_[VELOCITY_INTERFACE_INDEX][j] = latest_joint_state_.velocity[i];
127+
set_state(latest_joint_state_.name[i] + "/" + hardware_interface::HW_IF_VELOCITY,
128+
latest_joint_state_.velocity.at(i));
210129
}
211-
if (!latest_joint_state_.effort.empty())
130+
if (!latest_joint_state_.effort.empty() && std::isfinite(latest_joint_state_.effort.at(i)))
212131
{
213-
joint_state_values_[EFFORT_INTERFACE_INDEX][j] = latest_joint_state_.effort[i];
132+
set_state(latest_joint_state_.name[i] + "/" + hardware_interface::HW_IF_EFFORT,
133+
latest_joint_state_.effort.at(i));
214134
}
215135
}
216136
}
217137

218-
for (const auto& mimic_joint : mimic_joints_)
138+
// Update mimic joints
139+
for (const auto& mimic_joint : get_hardware_info().mimic_joints)
219140
{
220-
for (auto& joint_state : joint_state_values_)
141+
const auto& mimic_joint_name = joints.at(mimic_joint.joint_index).name;
142+
const auto& mimicked_joint_name = joints.at(mimic_joint.mimicked_joint_index).name;
143+
if (has_state(mimic_joint_name + "/" + hardware_interface::HW_IF_POSITION))
221144
{
222-
joint_state[mimic_joint.joint_index] = mimic_joint.multiplier * joint_state[mimic_joint.mimicked_joint_index];
145+
set_state(mimic_joint_name + "/" + hardware_interface::HW_IF_POSITION,
146+
mimic_joint.offset +
147+
mimic_joint.multiplier * get_state(mimicked_joint_name + "/" + hardware_interface::HW_IF_POSITION));
148+
}
149+
if (has_state(mimic_joint_name + "/" + hardware_interface::HW_IF_VELOCITY))
150+
{
151+
set_state(mimic_joint_name + "/" + hardware_interface::HW_IF_VELOCITY,
152+
mimic_joint.multiplier * get_state(mimicked_joint_name + "/" + hardware_interface::HW_IF_VELOCITY));
153+
}
154+
if (has_state(mimic_joint_name + "/" + hardware_interface::HW_IF_ACCELERATION))
155+
{
156+
set_state(mimic_joint_name + "/" + hardware_interface::HW_IF_ACCELERATION,
157+
mimic_joint.multiplier * get_state(mimicked_joint_name + "/" + hardware_interface::HW_IF_ACCELERATION));
223158
}
224159
}
225160

226161
return hardware_interface::return_type::OK;
227162
}
228163

229-
template <typename HandleType>
230-
bool JointStateTopicSystem::getInterface(const std::string& name, const std::string& interface_name,
231-
const size_t vector_index, std::vector<std::vector<double>>& values,
232-
std::vector<HandleType>& interfaces)
233-
{
234-
auto it = std::find(standard_interfaces_.begin(), standard_interfaces_.end(), interface_name);
235-
if (it != standard_interfaces_.end())
236-
{
237-
auto j = static_cast<std::size_t>(std::distance(standard_interfaces_.begin(), it));
238-
interfaces.emplace_back(name, *it, &values[j][vector_index]);
239-
return true;
240-
}
241-
return false;
242-
}
243-
244164
hardware_interface::return_type JointStateTopicSystem::write(const rclcpp::Time& /*time*/,
245165
const rclcpp::Duration& /*period*/)
246166
{
167+
const auto& joints = get_hardware_info().joints;
247168
// To avoid spamming TopicBased's joint command topic we check the difference between the joint states and
248169
// the current joint commands, if it's smaller than a threshold we don't publish it.
249-
const auto diff = std::transform_reduce(
250-
joint_state_values_[POSITION_INTERFACE_INDEX].cbegin(), joint_state_values_[POSITION_INTERFACE_INDEX].cend(),
251-
joint_command_values_[POSITION_INTERFACE_INDEX].cbegin(), 0.0,
252-
[](const auto d1, const auto d2) { return std::abs(d1) + std::abs(d2); }, std::minus<double>{});
170+
auto diff = 0.0;
171+
for (std::size_t i = 0; i < joints.size(); ++i)
172+
{
173+
for (const auto& interface : joints[i].command_interfaces)
174+
{
175+
if (interface.name != hardware_interface::HW_IF_POSITION)
176+
{
177+
continue;
178+
}
179+
// sum the absolute difference for all joints
180+
diff += std::abs(get_state(joints[i].name + "/" + interface.name) -
181+
get_command(joints[i].name + "/" + interface.name));
182+
}
183+
}
253184
if (diff <= trigger_joint_command_threshold_)
254185
{
255186
return hardware_interface::return_type::OK;
256187
}
257188

258189
sensor_msgs::msg::JointState joint_state;
259-
for (std::size_t i = 0; i < get_hardware_info().joints.size(); ++i)
190+
for (std::size_t i = 0; i < joints.size(); ++i)
260191
{
261-
joint_state.name.push_back(get_hardware_info().joints[i].name);
192+
joint_state.name.push_back(joints[i].name);
262193
joint_state.header.stamp = get_node()->now();
263194
// only send commands to the interfaces that are defined for this joint
264-
for (const auto& interface : get_hardware_info().joints[i].command_interfaces)
195+
for (const auto& interface : joints[i].command_interfaces)
265196
{
266197
if (interface.name == hardware_interface::HW_IF_POSITION)
267198
{
268-
joint_state.position.push_back(joint_command_values_[POSITION_INTERFACE_INDEX][i]);
199+
joint_state.position.push_back(get_command(joints[i].name + "/" + interface.name));
269200
}
270201
else if (interface.name == hardware_interface::HW_IF_VELOCITY)
271202
{
272-
joint_state.velocity.push_back(joint_command_values_[VELOCITY_INTERFACE_INDEX][i]);
203+
joint_state.velocity.push_back(get_command(joints[i].name + "/" + interface.name));
273204
}
274205
else if (interface.name == hardware_interface::HW_IF_EFFORT)
275206
{
276-
joint_state.effort.push_back(joint_command_values_[EFFORT_INTERFACE_INDEX][i]);
207+
joint_state.effort.push_back(get_command(joints[i].name + "/" + interface.name));
277208
}
278209
else
279210
{
280211
RCLCPP_WARN_ONCE(get_node()->get_logger(), "Joint '%s' has unsupported command interfaces found: %s.",
281-
get_hardware_info().joints[i].name.c_str(), interface.name.c_str());
282-
}
283-
}
284-
}
285-
286-
for (const auto& mimic_joint : mimic_joints_)
287-
{
288-
for (const auto& interface : get_hardware_info().joints[mimic_joint.mimicked_joint_index].command_interfaces)
289-
{
290-
if (interface.name == hardware_interface::HW_IF_POSITION)
291-
{
292-
joint_state.position[mimic_joint.joint_index] =
293-
mimic_joint.multiplier * joint_state.position[mimic_joint.mimicked_joint_index];
294-
}
295-
else if (interface.name == hardware_interface::HW_IF_VELOCITY)
296-
{
297-
joint_state.velocity[mimic_joint.joint_index] =
298-
mimic_joint.multiplier * joint_state.velocity[mimic_joint.mimicked_joint_index];
299-
}
300-
else if (interface.name == hardware_interface::HW_IF_EFFORT)
301-
{
302-
joint_state.effort[mimic_joint.joint_index] =
303-
mimic_joint.multiplier * joint_state.effort[mimic_joint.mimicked_joint_index];
212+
joints[i].name.c_str(), interface.name.c_str());
304213
}
305214
}
306215
}

0 commit comments

Comments
 (0)