@@ -542,6 +542,137 @@ TEST_F(PidControllerTest, receive_message_and_publish_updated_status)
542542 }
543543}
544544
545+ /* *
546+ * @brief check chained pid controller with feedforward and gain as non-zero, single interface
547+ */
548+ TEST_F (PidControllerTest, test_update_chained_feedforward_with_gain)
549+ {
550+ // state interface value is 1.1 as defined in test fixture
551+ // with p gain 0.5, the command value should be 0.5 * (5.0 - 1.1) = 1.95
552+ // with feedforward gain 1.0, the command value should be 1.95 + 1.0 * 5.0 = 6.95
553+ const double target_value = 5.0 ;
554+ const double expected_command_value = 6.95 ;
555+
556+ SetUpController (" test_pid_controller_with_feedforward_gain" );
557+ ASSERT_EQ (controller_->on_configure (rclcpp_lifecycle::State ()), NODE_SUCCESS);
558+
559+ // check on interfaces & pid gain parameters
560+ for (const auto & dof_name : dof_names_)
561+ {
562+ ASSERT_EQ (controller_->params_ .gains .dof_names_map [dof_name].p , 0.5 );
563+ ASSERT_EQ (controller_->params_ .gains .dof_names_map [dof_name].feedforward_gain , 1.0 );
564+ }
565+ ASSERT_EQ (controller_->params_ .command_interface , command_interface_);
566+ EXPECT_THAT (
567+ controller_->params_ .reference_and_state_interfaces ,
568+ testing::ElementsAreArray (state_interfaces_));
569+ ASSERT_FALSE (controller_->params_ .use_external_measured_states );
570+
571+ // setup executor
572+ rclcpp::executors::MultiThreadedExecutor executor;
573+ executor.add_node (controller_->get_node ()->get_node_base_interface ());
574+ executor.add_node (service_caller_node_->get_node_base_interface ());
575+
576+ controller_->set_chained_mode (true );
577+
578+ // activate controller
579+ ASSERT_EQ (controller_->on_activate (rclcpp_lifecycle::State ()), NODE_SUCCESS);
580+ ASSERT_TRUE (controller_->is_in_chained_mode ());
581+
582+ // turn on feedforward
583+ controller_->control_mode_ .writeFromNonRT (feedforward_mode_type::ON);
584+ ASSERT_EQ (*(controller_->control_mode_ .readFromRT ()), feedforward_mode_type::ON);
585+
586+ // send a message to update reference interface
587+ std::shared_ptr<ControllerCommandMsg> msg = std::make_shared<ControllerCommandMsg>();
588+ msg->dof_names = controller_->params_ .dof_names ;
589+ msg->values .resize (msg->dof_names .size (), 0.0 );
590+ for (size_t i = 0 ; i < msg->dof_names .size (); ++i)
591+ {
592+ msg->values [i] = target_value;
593+ }
594+ msg->values_dot .resize (msg->dof_names .size (), std::numeric_limits<double >::quiet_NaN ());
595+ controller_->input_ref_ .writeFromNonRT (msg);
596+ ASSERT_EQ (
597+ controller_->update_reference_from_subscribers (
598+ rclcpp::Time (0 ), rclcpp::Duration::from_seconds (0.01 )),
599+ controller_interface::return_type::OK);
600+
601+ // run update
602+ ASSERT_EQ (
603+ controller_->update (rclcpp::Time (0 ), rclcpp::Duration::from_seconds (0.01 )),
604+ controller_interface::return_type::OK);
605+
606+ // check on result from update
607+ ASSERT_EQ (controller_->command_interfaces_ [0 ].get_value (), expected_command_value);
608+ }
609+
610+ /* *
611+ * @brief check chained pid controller with feedforward OFF and gain as non-zero, single interface
612+ */
613+ TEST_F (PidControllerTest, test_update_chained_feedforward_off_with_gain)
614+ {
615+ // state interface value is 1.1 as defined in test fixture
616+ // given target value 5.0
617+ // with p gain 0.5, the command value should be 0.5 * (5.0 - 1.1) = 1.95
618+ // with feedforward off, the command value should be still 1.95 even though feedforward gain
619+ // is 1.0
620+ const double target_value = 5.0 ;
621+ const double expected_command_value = 1.95 ;
622+
623+ SetUpController (" test_pid_controller_with_feedforward_gain" );
624+ ASSERT_EQ (controller_->on_configure (rclcpp_lifecycle::State ()), NODE_SUCCESS);
625+
626+ // check on interfaces & pid gain parameters
627+ for (const auto & dof_name : dof_names_)
628+ {
629+ ASSERT_EQ (controller_->params_ .gains .dof_names_map [dof_name].p , 0.5 );
630+ ASSERT_EQ (controller_->params_ .gains .dof_names_map [dof_name].feedforward_gain , 1.0 );
631+ }
632+ ASSERT_EQ (controller_->params_ .command_interface , command_interface_);
633+ EXPECT_THAT (
634+ controller_->params_ .reference_and_state_interfaces ,
635+ testing::ElementsAreArray (state_interfaces_));
636+ ASSERT_FALSE (controller_->params_ .use_external_measured_states );
637+
638+ // setup executor
639+ rclcpp::executors::MultiThreadedExecutor executor;
640+ executor.add_node (controller_->get_node ()->get_node_base_interface ());
641+ executor.add_node (service_caller_node_->get_node_base_interface ());
642+
643+ controller_->set_chained_mode (true );
644+
645+ // activate controller
646+ ASSERT_EQ (controller_->on_activate (rclcpp_lifecycle::State ()), NODE_SUCCESS);
647+ ASSERT_TRUE (controller_->is_in_chained_mode ());
648+
649+ // feedforward by default is OFF
650+ ASSERT_EQ (*(controller_->control_mode_ .readFromRT ()), feedforward_mode_type::OFF);
651+
652+ // send a message to update reference interface
653+ std::shared_ptr<ControllerCommandMsg> msg = std::make_shared<ControllerCommandMsg>();
654+ msg->dof_names = controller_->params_ .dof_names ;
655+ msg->values .resize (msg->dof_names .size (), 0.0 );
656+ for (size_t i = 0 ; i < msg->dof_names .size (); ++i)
657+ {
658+ msg->values [i] = target_value;
659+ }
660+ msg->values_dot .resize (msg->dof_names .size (), std::numeric_limits<double >::quiet_NaN ());
661+ controller_->input_ref_ .writeFromNonRT (msg);
662+ ASSERT_EQ (
663+ controller_->update_reference_from_subscribers (
664+ rclcpp::Time (0 ), rclcpp::Duration::from_seconds (0.01 )),
665+ controller_interface::return_type::OK);
666+
667+ // run update
668+ ASSERT_EQ (
669+ controller_->update (rclcpp::Time (0 ), rclcpp::Duration::from_seconds (0.01 )),
670+ controller_interface::return_type::OK);
671+
672+ // check on result from update
673+ ASSERT_EQ (controller_->command_interfaces_ [0 ].get_value (), expected_command_value);
674+ }
675+
545676int main (int argc, char ** argv)
546677{
547678 ::testing::InitGoogleTest (&argc, argv);
0 commit comments