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