@@ -487,6 +487,210 @@ TEST_P(TrajectoryControllerTestParameterized, state_topic_consistency)
487
487
EXPECT_TRUE (state->error .accelerations .empty () || state->error .accelerations == zeros);
488
488
}
489
489
490
+ // Floating-point value comparison threshold
491
+ const double EPS = 1e-6 ;
492
+ /* *
493
+ * @brief check if position error of revolute joints are normalized if not configured so
494
+ */
495
+ TEST_P (TrajectoryControllerTestParameterized, position_error_not_normalized)
496
+ {
497
+ rclcpp::executors::MultiThreadedExecutor executor;
498
+ constexpr double k_p = 10.0 ;
499
+ SetUpAndActivateTrajectoryController (executor, true , {}, true , k_p, 0.0 , false );
500
+ subscribeToState ();
501
+
502
+ size_t n_joints = joint_names_.size ();
503
+
504
+ // send msg
505
+ constexpr auto FIRST_POINT_TIME = std::chrono::milliseconds (250 );
506
+ builtin_interfaces::msg::Duration time_from_start{rclcpp::Duration (FIRST_POINT_TIME)};
507
+ // *INDENT-OFF*
508
+ std::vector<std::vector<double >> points{
509
+ {{3.3 , 4.4 , 6.6 }}, {{7.7 , 8.8 , 9.9 }}, {{10.10 , 11.11 , 12.12 }}};
510
+ std::vector<std::vector<double >> points_velocities{
511
+ {{0.01 , 0.01 , 0.01 }}, {{0.05 , 0.05 , 0.05 }}, {{0.06 , 0.06 , 0.06 }}};
512
+ // *INDENT-ON*
513
+ publish (time_from_start, points, rclcpp::Time (), {}, points_velocities);
514
+ traj_controller_->wait_for_trajectory (executor);
515
+
516
+ // first update
517
+ updateController (rclcpp::Duration (FIRST_POINT_TIME));
518
+
519
+ // Spin to receive latest state
520
+ executor.spin_some ();
521
+ auto state_msg = getState ();
522
+ ASSERT_TRUE (state_msg);
523
+
524
+ const auto allowed_delta = 0.1 ;
525
+
526
+ // no update of state_interface
527
+ EXPECT_EQ (state_msg->actual .positions , INITIAL_POS_JOINTS);
528
+
529
+ // has the msg the correct vector sizes?
530
+ EXPECT_EQ (n_joints, state_msg->desired .positions .size ());
531
+ EXPECT_EQ (n_joints, state_msg->actual .positions .size ());
532
+ EXPECT_EQ (n_joints, state_msg->error .positions .size ());
533
+
534
+ // are the correct desired positions used?
535
+ EXPECT_NEAR (points[0 ][0 ], state_msg->desired .positions [0 ], allowed_delta);
536
+ EXPECT_NEAR (points[0 ][1 ], state_msg->desired .positions [1 ], allowed_delta);
537
+ EXPECT_NEAR (points[0 ][2 ], state_msg->desired .positions [2 ], 3 * allowed_delta);
538
+
539
+ // no normalization of position error
540
+ EXPECT_NEAR (
541
+ state_msg->error .positions [0 ], state_msg->desired .positions [0 ] - INITIAL_POS_JOINTS[0 ], EPS);
542
+ EXPECT_NEAR (
543
+ state_msg->error .positions [1 ], state_msg->desired .positions [1 ] - INITIAL_POS_JOINTS[1 ], EPS);
544
+ EXPECT_NEAR (
545
+ state_msg->error .positions [2 ], state_msg->desired .positions [2 ] - INITIAL_POS_JOINTS[2 ], EPS);
546
+
547
+ if (traj_controller_->has_position_command_interface ())
548
+ {
549
+ // check command interface
550
+ EXPECT_NEAR (points[0 ][0 ], joint_pos_[0 ], allowed_delta);
551
+ EXPECT_NEAR (points[0 ][1 ], joint_pos_[1 ], allowed_delta);
552
+ EXPECT_NEAR (points[0 ][2 ], joint_pos_[2 ], allowed_delta);
553
+ }
554
+
555
+ if (traj_controller_->has_velocity_command_interface ())
556
+ {
557
+ // check command interface
558
+ EXPECT_LE (0.0 , joint_vel_[0 ]);
559
+ EXPECT_LE (0.0 , joint_vel_[1 ]);
560
+ EXPECT_LE (0.0 , joint_vel_[2 ]);
561
+
562
+ // use_closed_loop_pid_adapter_
563
+ if (traj_controller_->use_closed_loop_pid_adapter ())
564
+ {
565
+ // we expect u = k_p * (s_d-s)
566
+ EXPECT_NEAR (
567
+ k_p * (state_msg->desired .positions [0 ] - INITIAL_POS_JOINTS[0 ]), joint_vel_[0 ],
568
+ k_p * allowed_delta);
569
+ EXPECT_NEAR (
570
+ k_p * (state_msg->desired .positions [1 ] - INITIAL_POS_JOINTS[1 ]), joint_vel_[1 ],
571
+ k_p * allowed_delta);
572
+ // no normalization of position error
573
+ EXPECT_NEAR (
574
+ k_p * (state_msg->desired .positions [2 ] - INITIAL_POS_JOINTS[2 ]), joint_vel_[2 ],
575
+ k_p * allowed_delta);
576
+ }
577
+ }
578
+
579
+ if (traj_controller_->has_effort_command_interface ())
580
+ {
581
+ // check command interface
582
+ EXPECT_LE (0.0 , joint_eff_[0 ]);
583
+ EXPECT_LE (0.0 , joint_eff_[1 ]);
584
+ EXPECT_LE (0.0 , joint_eff_[2 ]);
585
+ }
586
+
587
+ executor.cancel ();
588
+ }
589
+
590
+ /* *
591
+ * @brief check if position error of revolute joints are normalized if configured so
592
+ */
593
+ TEST_P (TrajectoryControllerTestParameterized, position_error_normalized)
594
+ {
595
+ rclcpp::executors::MultiThreadedExecutor executor;
596
+ constexpr double k_p = 10.0 ;
597
+ SetUpAndActivateTrajectoryController (executor, true , {}, true , k_p, 0.0 , true );
598
+ subscribeToState ();
599
+
600
+ size_t n_joints = joint_names_.size ();
601
+
602
+ // send msg
603
+ constexpr auto FIRST_POINT_TIME = std::chrono::milliseconds (250 );
604
+ builtin_interfaces::msg::Duration time_from_start{rclcpp::Duration (FIRST_POINT_TIME)};
605
+ // *INDENT-OFF*
606
+ std::vector<std::vector<double >> points{
607
+ {{3.3 , 4.4 , 6.6 }}, {{7.7 , 8.8 , 9.9 }}, {{10.10 , 11.11 , 12.12 }}};
608
+ std::vector<std::vector<double >> points_velocities{
609
+ {{0.01 , 0.01 , 0.01 }}, {{0.05 , 0.05 , 0.05 }}, {{0.06 , 0.06 , 0.06 }}};
610
+ // *INDENT-ON*
611
+ publish (time_from_start, points, rclcpp::Time (), {}, points_velocities);
612
+ traj_controller_->wait_for_trajectory (executor);
613
+
614
+ // first update
615
+ updateController (rclcpp::Duration (FIRST_POINT_TIME));
616
+
617
+ // Spin to receive latest state
618
+ executor.spin_some ();
619
+ auto state_msg = getState ();
620
+ ASSERT_TRUE (state_msg);
621
+
622
+ const auto allowed_delta = 0.1 ;
623
+
624
+ // no update of state_interface
625
+ EXPECT_EQ (state_msg->actual .positions , INITIAL_POS_JOINTS);
626
+
627
+ // has the msg the correct vector sizes?
628
+ EXPECT_EQ (n_joints, state_msg->desired .positions .size ());
629
+ EXPECT_EQ (n_joints, state_msg->actual .positions .size ());
630
+ EXPECT_EQ (n_joints, state_msg->error .positions .size ());
631
+
632
+ // are the correct desired positions used?
633
+ EXPECT_NEAR (points[0 ][0 ], state_msg->desired .positions [0 ], allowed_delta);
634
+ EXPECT_NEAR (points[0 ][1 ], state_msg->desired .positions [1 ], allowed_delta);
635
+ EXPECT_NEAR (points[0 ][2 ], state_msg->desired .positions [2 ], 3 * allowed_delta);
636
+
637
+ // is error.positions[2] normalized?
638
+ EXPECT_NEAR (
639
+ state_msg->error .positions [0 ], state_msg->desired .positions [0 ] - INITIAL_POS_JOINTS[0 ], EPS);
640
+ EXPECT_NEAR (
641
+ state_msg->error .positions [1 ], state_msg->desired .positions [1 ] - INITIAL_POS_JOINTS[1 ], EPS);
642
+ EXPECT_NEAR (
643
+ state_msg->error .positions [2 ],
644
+ state_msg->desired .positions [2 ] - INITIAL_POS_JOINTS[2 ] - 2 * M_PI, EPS);
645
+
646
+ if (traj_controller_->has_position_command_interface ())
647
+ {
648
+ // check command interface
649
+ EXPECT_NEAR (points[0 ][0 ], joint_pos_[0 ], allowed_delta);
650
+ EXPECT_NEAR (points[0 ][1 ], joint_pos_[1 ], allowed_delta);
651
+ EXPECT_NEAR (points[0 ][2 ], joint_pos_[2 ], allowed_delta);
652
+ }
653
+
654
+ if (traj_controller_->has_velocity_command_interface ())
655
+ {
656
+ // check command interface
657
+ EXPECT_LE (0.0 , joint_vel_[0 ]);
658
+ EXPECT_LE (0.0 , joint_vel_[1 ]);
659
+
660
+ // use_closed_loop_pid_adapter_
661
+ if (traj_controller_->use_closed_loop_pid_adapter ())
662
+ {
663
+ EXPECT_GE (0.0 , joint_vel_[2 ]);
664
+ // we expect u = k_p * (s_d-s) for positions[0] and positions[1]
665
+ EXPECT_NEAR (
666
+ k_p * (state_msg->desired .positions [0 ] - INITIAL_POS_JOINTS[0 ]), joint_vel_[0 ],
667
+ k_p * allowed_delta);
668
+ EXPECT_NEAR (
669
+ k_p * (state_msg->desired .positions [1 ] - INITIAL_POS_JOINTS[1 ]), joint_vel_[1 ],
670
+ k_p * allowed_delta);
671
+ // is error of positions[2] normalized?
672
+ EXPECT_NEAR (
673
+ k_p * (state_msg->desired .positions [2 ] - INITIAL_POS_JOINTS[2 ] - 2 * M_PI), joint_vel_[2 ],
674
+ k_p * allowed_delta);
675
+ }
676
+ else
677
+ {
678
+ // interpolated points_velocities only
679
+ EXPECT_LE (0.0 , joint_vel_[2 ]);
680
+ }
681
+ }
682
+
683
+ if (traj_controller_->has_effort_command_interface ())
684
+ {
685
+ // check command interface
686
+ EXPECT_LE (0.0 , joint_eff_[0 ]);
687
+ EXPECT_LE (0.0 , joint_eff_[1 ]);
688
+ EXPECT_LE (0.0 , joint_eff_[2 ]);
689
+ }
690
+
691
+ executor.cancel ();
692
+ }
693
+
490
694
void TrajectoryControllerTest::test_state_publish_rate_target (int target_msg_count)
491
695
{
492
696
rclcpp::Parameter state_publish_rate_param (
0 commit comments