Skip to content

Commit 0104d7a

Browse files
committed
Add generate parameter library.
1 parent bb54c12 commit 0104d7a

File tree

5 files changed

+193
-70
lines changed

5 files changed

+193
-70
lines changed

ign_ros2_control/CMakeLists.txt

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,11 @@ find_package(hardware_interface REQUIRED)
2323
find_package(pluginlib REQUIRED)
2424
find_package(rclcpp REQUIRED)
2525
find_package(yaml_cpp_vendor REQUIRED)
26+
find_package(generate_parameter_library REQUIRED)
27+
28+
generate_parameter_library(ign_ros2_control_parameters
29+
src/ign_ros2_control_parameters.yaml
30+
)
2631

2732
if("$ENV{IGNITION_VERSION}" STREQUAL "citadel")
2833
find_package(ignition-gazebo3 REQUIRED)
@@ -58,6 +63,7 @@ target_link_libraries(${PROJECT_NAME}-system
5863
ignition-gazebo${IGN_GAZEBO_VER}::core
5964
ignition-plugin${IGN_PLUGIN_VER}::register
6065
)
66+
target_link_libraries(${PROJECT_NAME}-system ign_ros2_control_parameters)
6167
ament_target_dependencies(${PROJECT_NAME}-system
6268
ament_index_cpp
6369
controller_manager
@@ -73,6 +79,8 @@ ament_target_dependencies(${PROJECT_NAME}-system
7379
add_library(ign_hardware_plugins SHARED
7480
src/ign_system.cpp
7581
)
82+
target_include_directories(ign_hardware_plugins PRIVATE include)
83+
target_link_libraries(ign_hardware_plugins ign_ros2_control_parameters)
7684
ament_target_dependencies(ign_hardware_plugins
7785
rclcpp_lifecycle
7886
hardware_interface
@@ -82,9 +90,14 @@ target_link_libraries(ign_hardware_plugins
8290
ignition-gazebo${IGN_GAZEBO_VER}::core
8391
)
8492

93+
install(DIRECTORY include/
94+
DESTINATION include
95+
)
96+
8597
## Install
8698
install(TARGETS
87-
ign_hardware_plugins
99+
ign_hardware_plugins ign_ros2_control_parameters
100+
EXPORT export_ign_ros2_control
88101
ARCHIVE DESTINATION lib
89102
LIBRARY DESTINATION lib
90103
RUNTIME DESTINATION bin
@@ -98,7 +111,9 @@ endif()
98111

99112
ament_export_include_directories(include)
100113
ament_export_libraries(${PROJECT_NAME} ign_hardware_plugins)
101-
114+
ament_export_targets(
115+
export_ign_ros2_control HAS_LIBRARY_TARGET
116+
)
102117
# Install directories
103118
install(TARGETS ${PROJECT_NAME}-system
104119
DESTINATION lib

ign_ros2_control/include/ign_ros2_control/ign_system.hpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
#include "rclcpp_lifecycle/state.hpp"
2626
#include "rclcpp_lifecycle/node_interfaces/lifecycle_node_interface.hpp"
2727

28+
#include "ign_ros2_control_parameters.hpp"
29+
2830
namespace ign_ros2_control
2931
{
3032
using CallbackReturn = rclcpp_lifecycle::node_interfaces::LifecycleNodeInterface::CallbackReturn;
@@ -88,6 +90,14 @@ class IgnitionSystem : public IgnitionSystemInterface
8890

8991
/// \brief Private data class
9092
std::unique_ptr<IgnitionSystemPrivate> dataPtr;
93+
94+
// Parameters from ROS for ign_ros2_control
95+
std::shared_ptr<ParamListener> param_listener_;
96+
Params params_;
97+
98+
rclcpp::Node::SharedPtr node_;
99+
100+
std::thread spin_thread_;
91101
};
92102

93103
} // namespace ign_ros2_control

ign_ros2_control/package.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
<depend>rclcpp_lifecycle</depend>
2323
<depend>hardware_interface</depend>
2424
<depend>controller_manager</depend>
25+
<depend>generate_parameter_library</depend>
2526

2627
<test_depend>ament_lint_auto</test_depend>
2728
<test_depend>ament_lint_common</test_depend>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
ign_ros2_control:
2+
joints: {
3+
type: string_array,
4+
default_value: [],
5+
description: "Names of joints used by the controller",
6+
validation: {
7+
unique<>: null,
8+
}
9+
}
10+
gains:
11+
__map_joints:
12+
p: {
13+
type: double,
14+
default_value: 0.0,
15+
description: "Proportional gain for PID"
16+
}
17+
i: {
18+
type: double,
19+
default_value: 0.0,
20+
description: "Integral gain for PID"
21+
}
22+
d: {
23+
type: double,
24+
default_value: 0.0,
25+
description: "Derivative gain for PID"
26+
}
27+
iMax: {
28+
type: double,
29+
default_value: 0.0,
30+
description: "Integral positive clamp."
31+
}
32+
iMin: {
33+
type: double,
34+
default_value: 0.0,
35+
description: "Integral negative clamp."
36+
}
37+
cmdMax: {
38+
type: double,
39+
default_value: 0.0,
40+
description: "Maximum value for the PID command."
41+
}
42+
cmdMin: {
43+
type: double,
44+
default_value: 0.0,
45+
description: "Maximum value for the PID command."
46+
}
47+
cmdOffset: {
48+
type: double,
49+
default_value: 0.0,
50+
description: "Offset value for the command which is added to the result of the PID controller."
51+
}

ign_ros2_control/src/ign_system.cpp

Lines changed: 114 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -352,32 +352,39 @@ bool IgnitionSystem::initSim(
352352
// init position PID
353353

354354
// assuming every joint has axis
355-
const auto * jointAxis =
356-
this->dataPtr->ecm->Component<ignition::gazebo::components::JointAxis>(
357-
this->dataPtr->joints_[i].sim_joint);
355+
const auto * jointAxis =
356+
this->dataPtr->ecm->Component<ignition::gazebo::components::JointAxis>(
357+
this->dataPtr->joints_[i].sim_joint);
358358
// PID parameters
359-
double p_gain = 100.0;
360-
double i_gain = 0.0;
361-
double d_gain = 50.0;
359+
double p_gain = 100.0;
360+
double i_gain = 0.0;
361+
double d_gain = 50.0;
362362
// set integral max and min component to 10 percent of the max effort
363-
double iMax = std::isnan(jointAxis->Data().Effort()) ? 1.0 : jointAxis->Data().Effort() * 0.1;
364-
double iMin = std::isnan(jointAxis->Data().Effort()) ? 1.0 : -jointAxis->Data().Effort() * 0.1;
365-
double cmdMax = std::isnan(jointAxis->Data().Effort()) ? 1000.0 : jointAxis->Data().Effort();
366-
double cmdMin = std::isnan(jointAxis->Data().Effort()) ? -1000.0 : -jointAxis->Data().Effort();
363+
double iMax = std::isnan(jointAxis->Data().Effort()) ? 1.0 : jointAxis->Data().Effort() *
364+
0.1;
365+
double iMin = std::isnan(jointAxis->Data().Effort()) ? 1.0 : -jointAxis->Data().Effort() *
366+
0.1;
367+
double cmdMax =
368+
std::isnan(jointAxis->Data().Effort()) ? 1000.0 : jointAxis->Data().Effort();
369+
double cmdMin =
370+
std::isnan(jointAxis->Data().Effort()) ? -1000.0 : -jointAxis->Data().Effort();
367371
double cmdOffset = 0.0;
368372

369-
igndbg << "[JointController "<<joint_name<<"] Position based PID with Force/Torque output:" << std::endl;
370-
igndbg << "p_gain: [" << p_gain << "]" << std::endl;
371-
igndbg << "i_gain: [" << i_gain << "]" << std::endl;
372-
igndbg << "d_gain: [" << d_gain << "]" << std::endl;
373-
igndbg << "i_max: [" << iMax << "]" << std::endl;
374-
igndbg << "i_min: [" << iMin << "]" << std::endl;
375-
igndbg << "cmd_max: [" << cmdMax << "]" << std::endl;
376-
igndbg << "cmd_min: [" << cmdMin << "]" << std::endl;
377-
igndbg << "cmd_offset: [" << cmdOffset << "]" << std::endl;
373+
igndbg << "[JointController " << joint_name <<
374+
"] Position based PID with Force/Torque output:" << std::endl;
375+
igndbg << "p_gain: [" << p_gain << "]" << std::endl;
376+
igndbg << "i_gain: [" << i_gain << "]" << std::endl;
377+
igndbg << "d_gain: [" << d_gain << "]" << std::endl;
378+
igndbg << "i_max: [" << iMax << "]" << std::endl;
379+
igndbg << "i_min: [" << iMin << "]" << std::endl;
380+
igndbg << "cmd_max: [" << cmdMax << "]" << std::endl;
381+
igndbg << "cmd_min: [" << cmdMin << "]" << std::endl;
382+
igndbg << "cmd_offset: [" << cmdOffset << "]" << std::endl;
378383

379384

380-
this->dataPtr->joints_[j].pid.Init(p_gain, i_gain, d_gain, iMax, iMin, cmdMax, cmdMin, cmdOffset);
385+
this->dataPtr->joints_[j].pid.Init(
386+
p_gain, i_gain, d_gain, iMax, iMin, cmdMax, cmdMin,
387+
cmdOffset);
381388

382389
} else if (joint_info.command_interfaces[i].name == "velocity") {
383390
RCLCPP_INFO_STREAM(this->nh_->get_logger(), "\t\t velocity");
@@ -411,6 +418,18 @@ bool IgnitionSystem::initSim(
411418

412419
registerSensors(hardware_info);
413420

421+
this->node_ = rclcpp::Node::make_shared(
422+
hardware_info.name,
423+
rclcpp::NodeOptions().allow_undeclared_parameters(
424+
true).automatically_declare_parameters_from_overrides(true));
425+
426+
auto spin = [this]()
427+
{
428+
rclcpp::spin(node_);
429+
};
430+
431+
spin_thread_ = std::thread(spin);
432+
414433
return true;
415434
}
416435

@@ -487,6 +506,14 @@ CallbackReturn
487506
IgnitionSystem::on_init(const hardware_interface::HardwareInfo & system_info)
488507
{
489508
RCLCPP_WARN(this->nh_->get_logger(), "On init...");
509+
try {
510+
// Create the parameter listener and get the parameters
511+
param_listener_ = std::make_shared<ParamListener>(this->node_);
512+
params_ = param_listener_->get_params();
513+
} catch (const std::exception & e) {
514+
fprintf(stderr, "Exception thrown during init stage with message: %s \n", e.what());
515+
return CallbackReturn::ERROR;
516+
}
490517
if (hardware_interface::SystemInterface::on_init(system_info) != CallbackReturn::SUCCESS) {
491518
return CallbackReturn::ERROR;
492519
}
@@ -623,10 +650,10 @@ hardware_interface::return_type IgnitionSystem::write(
623650
const rclcpp::Duration & period)
624651
{
625652
for (unsigned int i = 0; i < this->dataPtr->joints_.size(); ++i) {
626-
// assuming every joint has axis
627-
const auto * jointAxis =
628-
this->dataPtr->ecm->Component<ignition::gazebo::components::JointAxis>(
629-
this->dataPtr->joints_[i].sim_joint);
653+
// assuming every joint has axis
654+
const auto * jointAxis =
655+
this->dataPtr->ecm->Component<ignition::gazebo::components::JointAxis>(
656+
this->dataPtr->joints_[i].sim_joint);
630657

631658
if (this->dataPtr->joints_[i].joint_control_method & VELOCITY) {
632659
if (!this->dataPtr->ecm->Component<ignition::gazebo::components::JointVelocityCmd>(
@@ -644,27 +671,37 @@ hardware_interface::return_type IgnitionSystem::write(
644671
}
645672
} else if (this->dataPtr->joints_[i].joint_control_method & POSITION) {
646673

647-
// calculate error with clamped position command
648-
double error = this->dataPtr->joints_[i].joint_position - std::clamp(this->dataPtr->joints_[i].joint_position_cmd, jointAxis->Data().Lower(), jointAxis->Data().Upper());
649-
650-
// error can be maximal 10 percent of the range
651-
error = copysign(1.0, error) * std::clamp(std::abs(error), 0.0, std::abs(jointAxis->Data().Upper() - jointAxis->Data().Lower())*0.1);
652-
653-
// calculate target force/torque
654-
double target_force = this->dataPtr->joints_[i].pid.Update(error, std::chrono::duration<double>(period.to_chrono<std::chrono::nanoseconds>()));
655-
656-
auto forceCmd =
657-
this->dataPtr->ecm->Component<ignition::gazebo::components::JointForceCmd>(this->dataPtr->joints_[i].sim_joint);
674+
// calculate error with clamped position command
675+
double error = this->dataPtr->joints_[i].joint_position - std::clamp(
676+
this->dataPtr->joints_[i].joint_position_cmd, jointAxis->Data().Lower(),
677+
jointAxis->Data().Upper());
678+
679+
// error can be maximal 10 percent of the range
680+
error =
681+
copysign(
682+
1.0,
683+
error) *
684+
std::clamp(
685+
std::abs(error), 0.0,
686+
std::abs(jointAxis->Data().Upper() - jointAxis->Data().Lower()) * 0.1);
687+
688+
// calculate target force/torque
689+
double target_force = this->dataPtr->joints_[i].pid.Update(
690+
error, std::chrono::duration<double>(
691+
period.to_chrono<std::chrono::nanoseconds>()));
692+
693+
auto forceCmd =
694+
this->dataPtr->ecm->Component<ignition::gazebo::components::JointForceCmd>(
695+
this->dataPtr->joints_[i].sim_joint);
658696

659-
if (forceCmd == nullptr)
660-
{
661-
this->dataPtr->ecm->CreateComponent(
662-
this->dataPtr->joints_[i].sim_joint,
663-
ignition::gazebo::components::JointForceCmd({0}));
664-
} else {
665-
*forceCmd = ignition::gazebo::components::JointForceCmd(
666-
{target_force});
667-
}
697+
if (forceCmd == nullptr) {
698+
this->dataPtr->ecm->CreateComponent(
699+
this->dataPtr->joints_[i].sim_joint,
700+
ignition::gazebo::components::JointForceCmd({0}));
701+
} else {
702+
*forceCmd = ignition::gazebo::components::JointForceCmd(
703+
{target_force});
704+
}
668705
} else if (this->dataPtr->joints_[i].joint_control_method & EFFORT) {
669706
if (!this->dataPtr->ecm->Component<ignition::gazebo::components::JointForceCmd>(
670707
this->dataPtr->joints_[i].sim_joint))
@@ -701,39 +738,48 @@ hardware_interface::return_type IgnitionSystem::write(
701738
// set values of all mimic joints with respect to mimicked joint
702739
for (const auto & mimic_joint : this->dataPtr->mimic_joints_) {
703740
for (const auto & mimic_interface : mimic_joint.interfaces_to_mimic) {
704-
// assuming every mimic joint has axis
705-
const auto * jointAxis =
706-
this->dataPtr->ecm->Component<ignition::gazebo::components::JointAxis>(
707-
this->dataPtr->joints_[mimic_joint.joint_index].sim_joint);
741+
// assuming every mimic joint has axis
742+
const auto * jointAxis =
743+
this->dataPtr->ecm->Component<ignition::gazebo::components::JointAxis>(
744+
this->dataPtr->joints_[mimic_joint.joint_index].sim_joint);
708745

709746
if (mimic_interface == "position") {
710747
// Get the joint position
711-
double position_mimicked_joint = this->dataPtr->joints_[mimic_joint.mimicked_joint_index].joint_position;
748+
double position_mimicked_joint =
749+
this->dataPtr->joints_[mimic_joint.mimicked_joint_index].joint_position;
712750

713-
double position_mimic_joint = this->dataPtr->joints_[mimic_joint.joint_index].joint_position;
751+
double position_mimic_joint =
752+
this->dataPtr->joints_[mimic_joint.joint_index].joint_position;
714753

715-
// calculate error with clamped position command
716-
double position_error =
717-
position_mimic_joint - std::clamp(position_mimicked_joint * mimic_joint.multiplier, jointAxis->Data().Lower(), jointAxis->Data().Upper());
754+
// calculate error with clamped position command
755+
double position_error =
756+
position_mimic_joint - std::clamp(
757+
position_mimicked_joint * mimic_joint.multiplier,
758+
jointAxis->Data().Lower(), jointAxis->Data().Upper());
718759

719-
// error can be maximal 10 percent of the range
720-
position_error = copysign(1.0, position_error) * std::clamp(std::abs(position_error), 0.0, std::abs(jointAxis->Data().Upper() - jointAxis->Data().Lower())*0.1);
760+
// error can be maximal 10 percent of the range
761+
position_error = copysign(1.0, position_error) * std::clamp(
762+
std::abs(
763+
position_error), 0.0, std::abs(
764+
jointAxis->Data().Upper() - jointAxis->Data().Lower()) * 0.1);
721765

722-
// calculate target force/torque
723-
double target_force = this->dataPtr->joints_[mimic_joint.joint_index].pid.Update(position_error, std::chrono::duration<double>(period.to_chrono<std::chrono::nanoseconds>()));
766+
// calculate target force/torque
767+
double target_force = this->dataPtr->joints_[mimic_joint.joint_index].pid.Update(
768+
position_error,
769+
std::chrono::duration<double>(period.to_chrono<std::chrono::nanoseconds>()));
724770

725-
auto forceCmd =
726-
this->dataPtr->ecm->Component<ignition::gazebo::components::JointForceCmd>(this->dataPtr->joints_[mimic_joint.joint_index].sim_joint);
771+
auto forceCmd =
772+
this->dataPtr->ecm->Component<ignition::gazebo::components::JointForceCmd>(
773+
this->dataPtr->joints_[mimic_joint.joint_index].sim_joint);
727774

728-
if (forceCmd == nullptr)
729-
{
730-
this->dataPtr->ecm->CreateComponent(
731-
this->dataPtr->joints_[mimic_joint.joint_index].sim_joint,
732-
ignition::gazebo::components::JointForceCmd({0}));
733-
} else {
734-
*forceCmd = ignition::gazebo::components::JointForceCmd(
735-
{target_force});
736-
}
775+
if (forceCmd == nullptr) {
776+
this->dataPtr->ecm->CreateComponent(
777+
this->dataPtr->joints_[mimic_joint.joint_index].sim_joint,
778+
ignition::gazebo::components::JointForceCmd({0}));
779+
} else {
780+
*forceCmd = ignition::gazebo::components::JointForceCmd(
781+
{target_force});
782+
}
737783
}/*
738784
if (mimic_interface == "velocity") {
739785
// get the velocity of mimicked joint

0 commit comments

Comments
 (0)