1717#include < chrono>
1818#include < functional>
1919#include < memory>
20-
20+ # include < numeric >
2121#include < stdexcept>
2222#include < string>
2323#include < vector>
4444namespace joint_trajectory_controller
4545{
4646JointTrajectoryController::JointTrajectoryController ()
47- : controller_interface::ControllerInterface(), dof_(0 )
47+ : controller_interface::ControllerInterface(), dof_(0 ), num_cmd_joints_( 0 )
4848{
4949}
5050
@@ -105,16 +105,7 @@ JointTrajectoryController::command_interface_configuration() const
105105{
106106 controller_interface::InterfaceConfiguration conf;
107107 conf.type = controller_interface::interface_configuration_type::INDIVIDUAL;
108- if (dof_ == 0 )
109- {
110- fprintf (
111- stderr,
112- " During ros2_control interface configuration, degrees of freedom is not valid;"
113- " it should be positive. Actual DOF is %zu\n " ,
114- dof_);
115- std::exit (EXIT_FAILURE);
116- }
117- conf.names .reserve (dof_ * params_.command_interfaces .size ());
108+ conf.names .reserve (num_cmd_joints_ * params_.command_interfaces .size ());
118109 for (const auto & joint_name : command_joint_names_)
119110 {
120111 for (const auto & interface_type : params_.command_interfaces )
@@ -291,14 +282,17 @@ controller_interface::return_type JointTrajectoryController::update(
291282 if (use_closed_loop_pid_adapter_)
292283 {
293284 // Update PIDs
294- for (auto i = 0ul ; i < dof_ ; ++i)
285+ for (auto i = 0ul ; i < num_cmd_joints_ ; ++i)
295286 {
296287 // If effort interface only, add desired effort as feed forward
297288 // If velocity interface, ignore desired effort
298- tmp_command_[i] = (command_next_.velocities [i] * ff_velocity_scale_[i]) +
299- (has_effort_command_interface_ ? command_next_.effort [i] : 0.0 ) +
300- pids_[i]->compute_command (
301- state_error_.positions [i], state_error_.velocities [i], period);
289+ size_t index_cmd_joint = map_cmd_to_joints_[i];
290+ tmp_command_[index_cmd_joint] =
291+ (command_next_.velocities [index_cmd_joint] * ff_velocity_scale_[i]) +
292+ (has_effort_command_interface_ ? command_next_.effort [index_cmd_joint] : 0.0 ) +
293+ pids_[i]->compute_command (
294+ state_error_.positions [index_cmd_joint], state_error_.velocities [index_cmd_joint],
295+ period);
302296 }
303297 }
304298
@@ -437,26 +431,38 @@ controller_interface::return_type JointTrajectoryController::update(
437431
438432void JointTrajectoryController::read_state_from_state_interfaces (JointTrajectoryPoint & state)
439433{
440- auto assign_point_from_interface =
434+ auto assign_point_from_state_interface =
441435 [&](std::vector<double > & trajectory_point_interface, const auto & joint_interface)
442436 {
443437 for (size_t index = 0 ; index < dof_; ++index)
444438 {
445439 trajectory_point_interface[index] = joint_interface[index].get ().get_value ();
446440 }
447441 };
442+ auto assign_point_from_command_interface =
443+ [&](std::vector<double > & trajectory_point_interface, const auto & joint_interface)
444+ {
445+ std::fill (
446+ trajectory_point_interface.begin (), trajectory_point_interface.end (),
447+ std::numeric_limits<double >::quiet_NaN ());
448+ for (size_t index = 0 ; index < num_cmd_joints_; ++index)
449+ {
450+ trajectory_point_interface[map_cmd_to_joints_[index]] =
451+ joint_interface[index].get ().get_value ();
452+ }
453+ };
448454
449455 // Assign values from the hardware
450456 // Position states always exist
451- assign_point_from_interface (state.positions , joint_state_interface_[0 ]);
457+ assign_point_from_state_interface (state.positions , joint_state_interface_[0 ]);
452458 // velocity and acceleration states are optional
453459 if (has_velocity_state_interface_)
454460 {
455- assign_point_from_interface (state.velocities , joint_state_interface_[1 ]);
461+ assign_point_from_state_interface (state.velocities , joint_state_interface_[1 ]);
456462 // Acceleration is used only in combination with velocity
457463 if (has_acceleration_state_interface_)
458464 {
459- assign_point_from_interface (state.accelerations , joint_state_interface_[2 ]);
465+ assign_point_from_state_interface (state.accelerations , joint_state_interface_[2 ]);
460466 }
461467 else
462468 {
@@ -473,7 +479,7 @@ void JointTrajectoryController::read_state_from_state_interfaces(JointTrajectory
473479 // No state interface for now, use command interface
474480 if (has_effort_command_interface_)
475481 {
476- assign_point_from_interface (state.effort , joint_command_interface_[3 ]);
482+ assign_point_from_command_interface (state.effort , joint_command_interface_[3 ]);
477483 }
478484}
479485
@@ -484,9 +490,10 @@ bool JointTrajectoryController::read_state_from_command_interfaces(JointTrajecto
484490 auto assign_point_from_interface =
485491 [&](std::vector<double > & trajectory_point_interface, const auto & joint_interface)
486492 {
487- for (size_t index = 0 ; index < dof_ ; ++index)
493+ for (size_t index = 0 ; index < num_cmd_joints_ ; ++index)
488494 {
489- trajectory_point_interface[index] = joint_interface[index].get ().get_value ();
495+ trajectory_point_interface[map_cmd_to_joints_[index]] =
496+ joint_interface[index].get ().get_value ();
490497 }
491498 };
492499
@@ -568,9 +575,10 @@ bool JointTrajectoryController::read_commands_from_command_interfaces(
568575 auto assign_point_from_interface =
569576 [&](std::vector<double > & trajectory_point_interface, const auto & joint_interface)
570577 {
571- for (size_t index = 0 ; index < dof_ ; ++index)
578+ for (size_t index = 0 ; index < num_cmd_joints_ ; ++index)
572579 {
573- trajectory_point_interface[index] = joint_interface[index].get ().get_value ();
580+ trajectory_point_interface[map_cmd_to_joints_[index]] =
581+ joint_interface[index].get ().get_value ();
574582 }
575583 };
576584
@@ -710,12 +718,6 @@ controller_interface::CallbackReturn JointTrajectoryController::on_configure(
710718 return CallbackReturn::FAILURE;
711719 }
712720
713- if (params_.joints .empty ())
714- {
715- // TODO(destogl): is this correct? Can we really move-on if no joint names are not provided?
716- RCLCPP_WARN (logger, " 'joints' parameter is empty." );
717- }
718-
719721 command_joint_names_ = params_.command_joints ;
720722
721723 if (command_joint_names_.empty ())
@@ -724,12 +726,40 @@ controller_interface::CallbackReturn JointTrajectoryController::on_configure(
724726 RCLCPP_INFO (
725727 logger, " No specific joint names are used for command interfaces. Using 'joints' parameter." );
726728 }
727- else if (command_joint_names_.size () != params_.joints .size ())
729+ num_cmd_joints_ = command_joint_names_.size ();
730+
731+ if (num_cmd_joints_ > dof_)
728732 {
729733 RCLCPP_ERROR (
730- logger, " 'command_joints' parameter has to have the same size as 'joints' parameter." );
734+ logger, " The 'command_joints' parameter must not exceed the size of the 'joints' parameter." );
731735 return CallbackReturn::FAILURE;
732736 }
737+ else if (num_cmd_joints_ < dof_)
738+ {
739+ // create a map for the command joints
740+ map_cmd_to_joints_ = mapping (command_joint_names_, params_.joints );
741+ if (map_cmd_to_joints_.size () != num_cmd_joints_)
742+ {
743+ RCLCPP_ERROR (
744+ logger,
745+ " 'command_joints' parameter must be a subset of 'joints' parameter, if their size is not "
746+ " equal." );
747+ return CallbackReturn::FAILURE;
748+ }
749+ for (size_t i = 0 ; i < command_joint_names_.size (); i++)
750+ {
751+ RCLCPP_DEBUG (
752+ logger, " Command joint %lu: '%s' maps to joint %lu: '%s'." , i,
753+ command_joint_names_[i].c_str (), map_cmd_to_joints_[i],
754+ params_.joints .at (map_cmd_to_joints_[i]).c_str ());
755+ }
756+ }
757+ else
758+ {
759+ // create a map for the command joints, trivial if the size is the same
760+ map_cmd_to_joints_.resize (num_cmd_joints_);
761+ std::iota (map_cmd_to_joints_.begin (), map_cmd_to_joints_.end (), 0 );
762+ }
733763
734764 if (params_.command_interfaces .empty ())
735765 {
@@ -761,8 +791,8 @@ controller_interface::CallbackReturn JointTrajectoryController::on_configure(
761791
762792 if (use_closed_loop_pid_adapter_)
763793 {
764- pids_.resize (dof_ );
765- ff_velocity_scale_.resize (dof_ );
794+ pids_.resize (num_cmd_joints_ );
795+ ff_velocity_scale_.resize (num_cmd_joints_ );
766796
767797 update_pids ();
768798 }
@@ -912,10 +942,12 @@ controller_interface::CallbackReturn JointTrajectoryController::on_configure(
912942 std::bind (&JointTrajectoryController::goal_accepted_callback, this , _1));
913943
914944 resize_joint_trajectory_point (state_current_, dof_);
915- resize_joint_trajectory_point_command (command_current_, dof_);
945+ resize_joint_trajectory_point_command (
946+ command_current_, dof_, std::numeric_limits<double >::quiet_NaN ());
916947 resize_joint_trajectory_point (state_desired_, dof_);
917948 resize_joint_trajectory_point (state_error_, dof_);
918- resize_joint_trajectory_point (last_commanded_state_, dof_);
949+ resize_joint_trajectory_point (
950+ last_commanded_state_, dof_, std::numeric_limits<double >::quiet_NaN ());
919951
920952 query_state_srv_ = get_node ()->create_service <control_msgs::srv::QueryTrajectoryState>(
921953 std::string (get_node ()->get_name ()) + " /query_state" ,
@@ -955,8 +987,8 @@ controller_interface::CallbackReturn JointTrajectoryController::on_activate(
955987 command_interfaces_, command_joint_names_, interface, joint_command_interface_[index]))
956988 {
957989 RCLCPP_ERROR (
958- logger, " Expected %zu '%s' command interfaces, got %zu." , dof_, interface. c_str () ,
959- joint_command_interface_[index].size ());
990+ logger, " Expected %zu '%s' command interfaces, got %zu." , num_cmd_joints_ ,
991+ interface. c_str (), joint_command_interface_[index].size ());
960992 return CallbackReturn::ERROR;
961993 }
962994 }
@@ -984,8 +1016,12 @@ controller_interface::CallbackReturn JointTrajectoryController::on_activate(
9841016 // running already)
9851017 trajectory_msgs::msg::JointTrajectoryPoint state;
9861018 resize_joint_trajectory_point (state, dof_);
1019+ // read from cmd joints only if all joints have command interface
1020+ // otherwise it leaves the entries of joints without command interface NaN.
1021+ // if no open_loop control, state_current_ is then used for `set_point_before_trajectory_msg` and
1022+ // future trajectory sampling will always give NaN for these joints
9871023 if (
988- params_.set_last_command_interface_value_as_state_on_activation &&
1024+ params_.set_last_command_interface_value_as_state_on_activation && dof_ == num_cmd_joints_ &&
9891025 read_state_from_command_interfaces (state))
9901026 {
9911027 state_current_ = state;
@@ -1041,7 +1077,7 @@ controller_interface::CallbackReturn JointTrajectoryController::on_deactivate(
10411077 rt_active_goal_.writeFromNonRT (RealtimeGoalHandlePtr ());
10421078 }
10431079
1044- for (size_t index = 0 ; index < dof_ ; ++index)
1080+ for (size_t index = 0 ; index < num_cmd_joints_ ; ++index)
10451081 {
10461082 if (has_position_command_interface_)
10471083 {
@@ -1593,38 +1629,38 @@ bool JointTrajectoryController::contains_interface_type(
15931629}
15941630
15951631void JointTrajectoryController::resize_joint_trajectory_point (
1596- trajectory_msgs::msg::JointTrajectoryPoint & point, size_t size)
1632+ trajectory_msgs::msg::JointTrajectoryPoint & point, size_t size, double value )
15971633{
1598- point.positions .resize (size, 0.0 );
1634+ point.positions .resize (size, value );
15991635 if (has_velocity_state_interface_)
16001636 {
1601- point.velocities .resize (size, 0.0 );
1637+ point.velocities .resize (size, value );
16021638 }
16031639 if (has_acceleration_state_interface_)
16041640 {
1605- point.accelerations .resize (size, 0.0 );
1641+ point.accelerations .resize (size, value );
16061642 }
16071643 point.effort .resize (size, 0.0 );
16081644}
16091645
16101646void JointTrajectoryController::resize_joint_trajectory_point_command (
1611- trajectory_msgs::msg::JointTrajectoryPoint & point, size_t size)
1647+ trajectory_msgs::msg::JointTrajectoryPoint & point, size_t size, double value )
16121648{
16131649 if (has_position_command_interface_)
16141650 {
1615- point.positions .resize (size, 0.0 );
1651+ point.positions .resize (size, value );
16161652 }
16171653 if (has_velocity_command_interface_)
16181654 {
1619- point.velocities .resize (size, 0.0 );
1655+ point.velocities .resize (size, value );
16201656 }
16211657 if (has_acceleration_command_interface_)
16221658 {
1623- point.accelerations .resize (size, 0.0 );
1659+ point.accelerations .resize (size, value );
16241660 }
16251661 if (has_effort_command_interface_)
16261662 {
1627- point.effort .resize (size, 0.0 );
1663+ point.effort .resize (size, value );
16281664 }
16291665}
16301666
@@ -1635,9 +1671,9 @@ bool JointTrajectoryController::has_active_trajectory() const
16351671
16361672void JointTrajectoryController::update_pids ()
16371673{
1638- for (size_t i = 0 ; i < dof_ ; ++i)
1674+ for (size_t i = 0 ; i < num_cmd_joints_ ; ++i)
16391675 {
1640- const auto & gains = params_.gains .joints_map .at (params_.joints [i]);
1676+ const auto & gains = params_.gains .joints_map .at (params_.joints . at (map_cmd_to_joints_ [i]) );
16411677 if (pids_[i])
16421678 {
16431679 // update PIDs with gains from ROS parameters
0 commit comments