Skip to content

Commit e40142c

Browse files
committed
Add cascade control parameter. Code refactoring.
1 parent 9bbb874 commit e40142c

File tree

2 files changed

+107
-46
lines changed

2 files changed

+107
-46
lines changed

ign_ros2_control/src/ign_ros2_control_parameters.yaml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,13 @@ ign_ros2_control:
77
unique<>: null,
88
}
99
}
10+
mode:
11+
__map_joints:
12+
use_cascade_control: {
13+
type: bool,
14+
default_value: false,
15+
description: "Defines if cascade control is ued in position control (outer position based loop and inner velocity based loop with force output)"
16+
}
1017
gains:
1118
__map_joints:
1219
p_pos: {

ign_ros2_control/src/ign_system.cpp

Lines changed: 100 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -254,6 +254,21 @@ bool IgnitionSystem::initSim(
254254
this->dataPtr->ecm->Component<ignition::gazebo::components::JointAxis>(
255255
this->dataPtr->joints_[j].sim_joint);
256256

257+
double use_cascade_control =
258+
(hardware_info.joints[j].parameters.find("use_cascade_control") ==
259+
hardware_info.joints[j].parameters.end() ) ? false : [&](){
260+
if(hardware_info.joints[j].parameters.at(
261+
"use_cascade_control") == "true" || hardware_info.joints[j].parameters.at(
262+
"use_cascade_control") == "True"){
263+
return true;
264+
}else{
265+
return false;
266+
}
267+
}();
268+
269+
param_vec.push_back(rclcpp::Parameter{"mode." + joint_name + ".use_cascade_control", p_gain_pos});
270+
271+
257272
double upper = jointAxis->Data().Upper();
258273
double lower = jointAxis->Data().Lower();
259274
double max_velocity = jointAxis->Data().MaxVelocity();
@@ -834,9 +849,12 @@ hardware_interface::return_type IgnitionSystem::write(
834849

835850
if (this->dataPtr->joints_[i].joint_control_method & VELOCITY) {
836851

837-
double velocity_error = this->dataPtr->joints_[i].joint_velocity - std::clamp(
838-
this->dataPtr->joints_[i].joint_velocity_cmd, -1.0 * jointAxis->Data().MaxVelocity(),
839-
jointAxis->Data().MaxVelocity());
852+
double velocity = this->dataPtr->joints_[i].joint_velocity;
853+
double velocity_cmd_clamped = std::clamp(
854+
this->dataPtr->joints_[i].joint_velocity_cmd, -1.0 * jointAxis->Data().MaxVelocity(),
855+
jointAxis->Data().MaxVelocity());
856+
857+
double velocity_error = velocity - velocity_cmd_clamped;
840858

841859
// calculate target force/torque - output of inner pid
842860
double target_force = this->dataPtr->joints_[i].pid_vel.Update(
@@ -862,31 +880,51 @@ hardware_interface::return_type IgnitionSystem::write(
862880
} else if (this->dataPtr->joints_[i].joint_control_method & POSITION) {
863881

864882
// calculate error with clamped position command
865-
double position_error = this->dataPtr->joints_[i].joint_position - std::clamp(
866-
this->dataPtr->joints_[i].joint_position_cmd, jointAxis->Data().Lower(),
867-
jointAxis->Data().Upper());
868-
position_error =
869-
copysign(
870-
1.0,
871-
position_error) *
872-
std::clamp(
873-
std::abs(position_error), 0.0,
874-
std::abs(jointAxis->Data().Upper() - jointAxis->Data().Lower()));
875-
876-
// calculate target velocity - output of outer pid - input to inner pid
877-
double target_vel = this->dataPtr->joints_[i].pid_pos.Update(
878-
position_error, std::chrono::duration<double>(
879-
period.to_chrono<std::chrono::nanoseconds>()));
883+
double position = this->dataPtr->joints_[i].joint_position;
884+
double position_cmd_clamped = std::clamp(
885+
this->dataPtr->joints_[i].joint_position_cmd, jointAxis->Data().Lower(),
886+
jointAxis->Data().Upper());
880887

881-
double velocity_error = this->dataPtr->joints_[i].joint_velocity - std::clamp(
882-
target_vel, -1.0 * jointAxis->Data().MaxVelocity(),
883-
jointAxis->Data().MaxVelocity());
888+
double position_error = position - position_cmd_clamped;
889+
890+
double position_error_sign = copysign(
891+
1.0,
892+
position_error);
893+
894+
double position_error_abs_clamped = std::clamp(
895+
std::abs(position_error), 0.0,
896+
std::abs(jointAxis->Data().Upper() - jointAxis->Data().Lower()));
897+
898+
// move forward with calculated position error
899+
position_error = position_error_sign * position_error_abs_clamped;
900+
901+
double position_or_velocity_error = 0.0;
902+
903+
// check if cascade control is used for this joint
904+
if( params_.mode.joints_map[this->dataPtr->joints_[i].
905+
name].use_cascade_control)
906+
{
907+
// calculate target velocity - output of outer pid - input to inner pid
908+
double target_vel = this->dataPtr->joints_[i].pid_pos.Update(
909+
position_error, std::chrono::duration<double>(period.to_chrono<std::chrono::nanoseconds>()));
910+
911+
double velocity_error =
912+
this->dataPtr->joints_[i].joint_velocity -
913+
std::clamp(target_vel, -1.0 * jointAxis->Data().MaxVelocity(), jointAxis->Data().MaxVelocity());
914+
915+
// prepare velocity error value for inner pid
916+
position_or_velocity_error = velocity_error;
917+
}else{
918+
// prepare velocity error value for inner pid
919+
position_or_velocity_error = position_error;
920+
}
884921

885922
// calculate target force/torque - output of inner pid
886923
double target_force = this->dataPtr->joints_[i].pid_vel.Update(
887-
position_error, std::chrono::duration<double>(
924+
position_or_velocity_error, std::chrono::duration<double>(
888925
period.to_chrono<std::chrono::nanoseconds>()));
889926

927+
// round the force
890928
target_force = round(target_force * 10000.0)/10000.0;
891929

892930
// remember for potential effort state interface
@@ -939,47 +977,63 @@ hardware_interface::return_type IgnitionSystem::write(
939977
this->dataPtr->ecm->Component<ignition::gazebo::components::JointPosition>(
940978
this->dataPtr->joints_[mimic_joint.joint_index].sim_joint)->Data()[0];
941979

942-
double position_error = position_mimic_joint - std::clamp(
943-
position_mimicked_joint *
944-
mimic_joint.multiplier, jointAxis->Data().Lower(),
945-
jointAxis->Data().Upper());
980+
double position_target_from_mimicked_joint = std::clamp(
981+
position_mimicked_joint *
982+
mimic_joint.multiplier, jointAxis->Data().Lower(),
983+
jointAxis->Data().Upper());
946984

947-
position_error = round(position_error * 10000.0)/10000.0;
985+
double position_error = position_mimic_joint - position_target_from_mimicked_joint;
948986

949-
position_error =
950-
copysign(
951-
1.0,
952-
position_error) *
953-
std::clamp(
954-
std::abs(position_error), 0.0,
955-
std::abs(jointAxis->Data().Upper() - jointAxis->Data().Lower()));
987+
// round position error for simulation stability
988+
position_error = round(position_error * 10000.0)/10000.0;
956989

990+
double position_error_sign = copysign(
991+
1.0,
992+
position_error);
957993

994+
double position_error_abs_clamped = std::clamp(
995+
std::abs(position_error), 0.0,
996+
std::abs(jointAxis->Data().Upper() - jointAxis->Data().Lower()));
958997

959-
// calculate target velocity - output of outer pid - input to inner pid
960-
double target_vel = this->dataPtr->joints_[mimic_joint.joint_index].pid_pos.Update(
961-
position_error, std::chrono::duration<double>(
962-
period.to_chrono<std::chrono::nanoseconds>()));
998+
position_error = position_error_sign * position_error_abs_clamped;
963999

964-
// get mimic joint velocity
965-
double velocity_mimic_joint =
966-
this->dataPtr->ecm->Component<ignition::gazebo::components::JointVelocity>(
967-
this->dataPtr->joints_[mimic_joint.joint_index].sim_joint)->Data()[0];
1000+
double position_or_velocity_error = 0.0;
9681001

969-
double velocity_error = velocity_mimic_joint - std::clamp(
970-
target_vel, -1.0 * jointAxis->Data().MaxVelocity(),
971-
jointAxis->Data().MaxVelocity());
1002+
// check if cascade control is used for this joint
1003+
if( params_.mode.joints_map[this->dataPtr->joints_[mimic_joint.joint_index].
1004+
name].use_cascade_control)
1005+
{
1006+
// calculate target velocity - output of outer pid - input to inner pid
1007+
double target_vel = this->dataPtr->joints_[mimic_joint.joint_index].pid_pos.Update(
1008+
position_error, std::chrono::duration<double>(period.to_chrono<std::chrono::nanoseconds>()));
1009+
1010+
// get mimic joint velocity
1011+
double velocity_mimic_joint = this->dataPtr->ecm
1012+
->Component<ignition::gazebo::components::JointVelocity>(
1013+
this->dataPtr->joints_[mimic_joint.joint_index].sim_joint)
1014+
->Data()[0];
1015+
1016+
position_or_velocity_error = velocity_mimic_joint - std::clamp(target_vel, -1.0 * jointAxis->Data().MaxVelocity(),
1017+
jointAxis->Data().MaxVelocity());
1018+
}else{
1019+
position_or_velocity_error = position_error;
1020+
}
9721021

1022+
// set command offset - feed forward term added to the pid output that is clamped by pid max command value
1023+
// while taking into account mimic multiplier
9731024
this->dataPtr->joints_[mimic_joint.joint_index].pid_vel.SetCmdOffset(
9741025
mimic_joint.multiplier *
9751026
this->dataPtr->joints_[mimic_joint.mimicked_joint_index].joint_effort_cmd);
1027+
9761028
// calculate target force/torque - output of inner pid
9771029
double target_force = this->dataPtr->joints_[mimic_joint.joint_index].pid_vel.Update(
978-
position_error, std::chrono::duration<double>(
1030+
position_or_velocity_error, std::chrono::duration<double>(
9791031
period.to_chrono<std::chrono::nanoseconds>()));
9801032

1033+
// round force value for simulation stability
9811034
target_force = round(target_force * 10000.0)/10000.0;
9821035

1036+
// remember for potential effort state interface
9831037
this->dataPtr->joints_[mimic_joint.joint_index].joint_effort_cmd = target_force;
9841038

9851039
auto forceCmd =

0 commit comments

Comments
 (0)