@@ -677,6 +677,141 @@ TEST_F(PidControllerTest, test_update_chained_feedforward_off_with_gain)
677
677
ASSERT_EQ (controller_->command_interfaces_ [0 ].get_value (), expected_command_value);
678
678
}
679
679
680
+ /* *
681
+ * @brief Test if retention of the integral state is deactivated
682
+ *
683
+ */
684
+
685
+ TEST_F (PidControllerTest, test_save_i_term_off)
686
+ {
687
+ SetUpController (" test_save_i_term_off" );
688
+ rclcpp::executors::MultiThreadedExecutor executor;
689
+ executor.add_node (controller_->get_node ()->get_node_base_interface ());
690
+ executor.add_node (service_caller_node_->get_node_base_interface ());
691
+
692
+ ASSERT_EQ (controller_->on_configure (rclcpp_lifecycle::State ()), NODE_SUCCESS);
693
+ controller_->set_chained_mode (false );
694
+ for (const auto & dof_name : dof_names_)
695
+ {
696
+ ASSERT_FALSE (controller_->params_ .gains .dof_names_map [dof_name].save_i_term );
697
+ }
698
+ ASSERT_EQ (controller_->on_activate (rclcpp_lifecycle::State ()), NODE_SUCCESS);
699
+ ASSERT_FALSE (controller_->is_in_chained_mode ());
700
+
701
+ std::shared_ptr<ControllerCommandMsg> msg = std::make_shared<ControllerCommandMsg>();
702
+ msg->dof_names = dof_names_;
703
+ msg->values .resize (dof_names_.size (), 0.0 );
704
+ for (size_t i = 0 ; i < dof_command_values_.size (); ++i)
705
+ {
706
+ msg->values [i] = dof_command_values_[i];
707
+ }
708
+ msg->values_dot .resize (dof_names_.size (), std::numeric_limits<double >::quiet_NaN ());
709
+ controller_->input_ref_ .writeFromNonRT (msg);
710
+
711
+ ASSERT_EQ (
712
+ controller_->update (rclcpp::Time (0 ), rclcpp::Duration::from_seconds (0.01 )),
713
+ controller_interface::return_type::OK);
714
+
715
+ // check the command value
716
+ // error = ref - state = 100.001, error_dot = error/ds = 10000.1,
717
+ // p_term = 100.001 * 1, i_term = 1.00001 * 2 = 2.00002, d_term = error/ds = 10000.1 * 3
718
+ // feedforward OFF -> cmd = p_term + i_term + d_term = 30102.3
719
+ auto expected_command_value = 30102.30102 ;
720
+
721
+ double actual_value = std::round (controller_->command_interfaces_ [0 ].get_value () * 1e5 ) / 1e5 ;
722
+ EXPECT_NEAR (actual_value, expected_command_value, 1e-5 );
723
+
724
+ // deactivate the controller and set command=state
725
+ ASSERT_EQ (controller_->on_deactivate (rclcpp_lifecycle::State ()), NODE_SUCCESS);
726
+
727
+ msg = std::make_shared<ControllerCommandMsg>();
728
+ msg->dof_names = dof_names_;
729
+ msg->values .resize (dof_names_.size (), 0.0 );
730
+ for (size_t i = 0 ; i < dof_command_values_.size (); ++i)
731
+ {
732
+ msg->values [i] = dof_state_values_[i];
733
+ }
734
+ msg->values_dot .resize (dof_names_.size (), std::numeric_limits<double >::quiet_NaN ());
735
+ controller_->input_ref_ .writeFromNonRT (msg);
736
+
737
+ // reactivate the controller, the integral term should NOT be saved
738
+ ASSERT_EQ (controller_->on_activate (rclcpp_lifecycle::State ()), NODE_SUCCESS);
739
+
740
+ ASSERT_EQ (
741
+ controller_->update (rclcpp::Time (0 ), rclcpp::Duration::from_seconds (0.01 )),
742
+ controller_interface::return_type::OK);
743
+ actual_value = std::round (controller_->command_interfaces_ [0 ].get_value () * 1e5 ) / 1e5 ;
744
+ EXPECT_NEAR (actual_value, 0.0 , 1e-5 );
745
+ }
746
+
747
+ /* *
748
+ * @brief Test if retention of the integral state is working
749
+ *
750
+ */
751
+
752
+ TEST_F (PidControllerTest, test_save_i_term_on)
753
+ {
754
+ SetUpController (" test_save_i_term_on" );
755
+ rclcpp::executors::MultiThreadedExecutor executor;
756
+ executor.add_node (controller_->get_node ()->get_node_base_interface ());
757
+ executor.add_node (service_caller_node_->get_node_base_interface ());
758
+
759
+ ASSERT_EQ (controller_->on_configure (rclcpp_lifecycle::State ()), NODE_SUCCESS);
760
+ for (const auto & dof_name : dof_names_)
761
+ {
762
+ ASSERT_TRUE (controller_->params_ .gains .dof_names_map [dof_name].save_i_term );
763
+ }
764
+ controller_->set_chained_mode (false );
765
+ ASSERT_EQ (controller_->on_activate (rclcpp_lifecycle::State ()), NODE_SUCCESS);
766
+ ASSERT_FALSE (controller_->is_in_chained_mode ());
767
+
768
+ std::shared_ptr<ControllerCommandMsg> msg = std::make_shared<ControllerCommandMsg>();
769
+ msg->dof_names = dof_names_;
770
+ msg->values .resize (dof_names_.size (), 0.0 );
771
+ for (size_t i = 0 ; i < dof_command_values_.size (); ++i)
772
+ {
773
+ msg->values [i] = dof_command_values_[i];
774
+ }
775
+ msg->values_dot .resize (dof_names_.size (), std::numeric_limits<double >::quiet_NaN ());
776
+ controller_->input_ref_ .writeFromNonRT (msg);
777
+
778
+ ASSERT_EQ (
779
+ controller_->update (rclcpp::Time (0 ), rclcpp::Duration::from_seconds (0.01 )),
780
+ controller_interface::return_type::OK);
781
+
782
+ // check the command value
783
+ // error = ref - state = 100.001, error_dot = error/ds = 10000.1,
784
+ // p_term = 100.001 * 1, i_term = 1.00001 * 2 = 2.00002, d_term = error/ds = 10000.1 * 3
785
+ // feedforward OFF -> cmd = p_term + i_term + d_term = 30102.3
786
+ auto expected_command_value = 30102.30102 ;
787
+
788
+ double actual_value = std::round (controller_->command_interfaces_ [0 ].get_value () * 1e5 ) / 1e5 ;
789
+ EXPECT_NEAR (actual_value, expected_command_value, 1e-5 );
790
+
791
+ // deactivate the controller and set command=state
792
+ ASSERT_EQ (controller_->on_deactivate (rclcpp_lifecycle::State ()), NODE_SUCCESS);
793
+
794
+ msg = std::make_shared<ControllerCommandMsg>();
795
+ msg->dof_names = dof_names_;
796
+ msg->values .resize (dof_names_.size (), 0.0 );
797
+ for (size_t i = 0 ; i < dof_command_values_.size (); ++i)
798
+ {
799
+ msg->values [i] = dof_state_values_[i];
800
+ }
801
+ msg->values_dot .resize (dof_names_.size (), std::numeric_limits<double >::quiet_NaN ());
802
+ controller_->input_ref_ .writeFromNonRT (msg);
803
+
804
+ // reactivate the controller, the integral term should be saved
805
+ ASSERT_EQ (controller_->on_activate (rclcpp_lifecycle::State ()), NODE_SUCCESS);
806
+
807
+ ASSERT_EQ (
808
+ controller_->update (rclcpp::Time (0 ), rclcpp::Duration::from_seconds (0.01 )),
809
+ controller_interface::return_type::OK);
810
+ expected_command_value = 2.00002 ; // i_term from above
811
+ actual_value = std::round (controller_->command_interfaces_ [0 ].get_value () * 1e5 ) / 1e5 ;
812
+ EXPECT_NEAR (actual_value, expected_command_value, 1e-5 );
813
+ }
814
+
680
815
int main (int argc, char ** argv)
681
816
{
682
817
::testing::InitGoogleTest (&argc, argv);
0 commit comments