@@ -254,6 +254,21 @@ bool IgnitionSystem::initSim(
254
254
this ->dataPtr ->ecm ->Component <ignition::gazebo::components::JointAxis>(
255
255
this ->dataPtr ->joints_ [j].sim_joint );
256
256
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
+
257
272
double upper = jointAxis->Data ().Upper ();
258
273
double lower = jointAxis->Data ().Lower ();
259
274
double max_velocity = jointAxis->Data ().MaxVelocity ();
@@ -834,9 +849,12 @@ hardware_interface::return_type IgnitionSystem::write(
834
849
835
850
if (this ->dataPtr ->joints_ [i].joint_control_method & VELOCITY) {
836
851
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;
840
858
841
859
// calculate target force/torque - output of inner pid
842
860
double target_force = this ->dataPtr ->joints_ [i].pid_vel .Update (
@@ -862,31 +880,51 @@ hardware_interface::return_type IgnitionSystem::write(
862
880
} else if (this ->dataPtr ->joints_ [i].joint_control_method & POSITION) {
863
881
864
882
// 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 ());
880
887
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
+ }
884
921
885
922
// calculate target force/torque - output of inner pid
886
923
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 >(
888
925
period.to_chrono <std::chrono::nanoseconds>()));
889
926
927
+ // round the force
890
928
target_force = round (target_force * 10000.0 )/10000.0 ;
891
929
892
930
// remember for potential effort state interface
@@ -939,47 +977,63 @@ hardware_interface::return_type IgnitionSystem::write(
939
977
this ->dataPtr ->ecm ->Component <ignition::gazebo::components::JointPosition>(
940
978
this ->dataPtr ->joints_ [mimic_joint.joint_index ].sim_joint )->Data ()[0 ];
941
979
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 ());
946
984
947
- position_error = round (position_error * 10000.0 )/ 10000.0 ;
985
+ double position_error = position_mimic_joint - position_target_from_mimicked_joint ;
948
986
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 ;
956
989
990
+ double position_error_sign = copysign (
991
+ 1.0 ,
992
+ position_error);
957
993
994
+ double position_error_abs_clamped = std::clamp (
995
+ std::abs (position_error), 0.0 ,
996
+ std::abs (jointAxis->Data ().Upper () - jointAxis->Data ().Lower ()));
958
997
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;
963
999
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 ;
968
1001
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
+ }
972
1021
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
973
1024
this ->dataPtr ->joints_ [mimic_joint.joint_index ].pid_vel .SetCmdOffset (
974
1025
mimic_joint.multiplier *
975
1026
this ->dataPtr ->joints_ [mimic_joint.mimicked_joint_index ].joint_effort_cmd );
1027
+
976
1028
// calculate target force/torque - output of inner pid
977
1029
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 >(
979
1031
period.to_chrono <std::chrono::nanoseconds>()));
980
1032
1033
+ // round force value for simulation stability
981
1034
target_force = round (target_force * 10000.0 )/10000.0 ;
982
1035
1036
+ // remember for potential effort state interface
983
1037
this ->dataPtr ->joints_ [mimic_joint.joint_index ].joint_effort_cmd = target_force;
984
1038
985
1039
auto forceCmd =
0 commit comments