11from dynamic_payload_analysis_core .core import TorqueCalculator
22import unittest
33import os
4+ import numpy as np
45
56
67class TestTorqueCalculator (unittest .TestCase ):
@@ -24,13 +25,15 @@ def test_init_torque_calculator(self):
2425
2526 def test_get_root_name (self ):
2627 root_name = self .robot_handler .get_root_joint_name (self .xml_string )
28+ self .assertIsInstance (root_name , str , "Root name should be a string" )
2729 self .assertEqual (self .robot_handler .get_root_name (), "base_footprint" )
2830 self .assertEqual (root_name , self .robot_handler .get_root_name ())
2931 print ("✅ Root name assertion passed" )
3032
3133 def test_subtree (self ):
3234 subtrees = self .robot_handler .get_subtrees ()
3335
36+ self .assertIsInstance (subtrees , np .ndarray , "Subtrees should be a list" )
3437 self .assertEqual (len (subtrees ), 7 )
3538 self .assertEqual (subtrees [0 ]["tip_link_name" ], "wheel_front_left_link" )
3639 self .assertEqual (subtrees [1 ]["tip_link_name" ], "wheel_front_right_link" )
@@ -49,8 +52,97 @@ def test_compute_mimic_joints(self):
4952 self .assertNotIn ("arm_1_joint" , mimic_joints )
5053 print ("✅ Mimic joints assertion passed" )
5154
52- def
55+ def test_create_external_force (self ):
56+ ext_forces = self .robot_handler .create_ext_force (masses = 1 , frame_name = "arm_left_3_link" , q = self .robot_handler .get_zero_configuration ())
57+ self .assertIsInstance (ext_forces , list , "External forces should be a numpy array" )
58+ self .assertNotEqual (ext_forces [8 ], [0 ,0 ,0 ], "External force should not be zero" )
59+ print ("✅ External force assertion passed" )
5360
61+ def test_compute_inverse_dynamics (self ):
62+ standard_config = self .robot_handler .get_zero_configuration ()
63+
64+ torques = self .robot_handler .compute_inverse_dynamics (standard_config , self .robot_handler .get_zero_velocity (), self .robot_handler .get_zero_acceleration ())
65+
66+ self .assertIsNotNone (torques , "Torques should not be None" )
67+ self .assertIsInstance (torques , np .ndarray , "Torques should be a list" )
68+ self .assertTrue (all (isinstance (torque , float ) for torque in torques ), "All torques should be floats" )
69+
70+ # add external forces to the end-effector
71+ external_forces = self .robot_handler .create_ext_force (masses = 1 , frame_name = "arm_left_3_link" , q = standard_config )
72+ torques_with_ext = self .robot_handler .compute_inverse_dynamics (standard_config , self .robot_handler .get_zero_velocity (), self .robot_handler .get_zero_acceleration (), external_forces )
73+
74+ np .testing .assert_raises (AssertionError , np .testing .assert_array_equal , torques , torques_with_ext )
75+ print ("✅ Inverse dynamics assertion passed" )
76+
77+ def test_update_configuration (self ):
78+ zero_config = self .robot_handler .get_zero_configuration ()
79+ new_config = zero_config + 5
80+
81+ self .robot_handler .update_configuration (new_config )
82+ joint_placement = self .robot_handler .get_joint_placement (joint_id = 20 ,q = new_config ) # just to ensure the configuration is updated internally
83+
84+ self .assertIsInstance (joint_placement , dict , "Joint placement should be a dict" )
85+
86+ self .robot_handler .update_configuration (zero_config )
87+ updated_joint_placement = self .robot_handler .get_joint_placement (joint_id = 20 ,q = zero_config )
88+
89+ self .assertNotEqual (joint_placement ["x" ], updated_joint_placement ["x" ], "Joint placement should differ after configuration update" )
90+ self .assertNotEqual (joint_placement ["y" ], updated_joint_placement ["y" ], "Joint placement should differ after configuration update" )
91+ self .assertNotEqual (joint_placement ["z" ], updated_joint_placement ["z" ], "Joint placement should differ after configuration update" )
92+
93+ print ("✅ Update configuration assertion passed" )
94+
95+ def test_compute_inverse_kinematics (self ):
96+ initial_config = self .robot_handler .get_zero_configuration ()
97+
98+ end_effector_pos = self .robot_handler .get_end_effector_position_array (- 0.4 , - 0.6 , 0.6 ) # reachable position
99+ computed_config = self .robot_handler .compute_inverse_kinematics (q = initial_config , end_effector_position = end_effector_pos , joint_id = 25 )
100+
101+ self .assertIsNotNone (computed_config , "Computed configuration should not be None if IK is successful" )
102+ self .assertIsInstance (computed_config , np .ndarray , "Computed configuration should be a numpy array" )
103+
104+ end_effector_pos_not_reachable = self .robot_handler .get_end_effector_position_array (4 , 6 , 6 ) # not reachable position
105+ computed_config_not_reachable = self .robot_handler .compute_inverse_kinematics (q = initial_config , end_effector_position = end_effector_pos_not_reachable , joint_id = 25 )
106+
107+ self .assertIsNone (computed_config_not_reachable , "Computed configuration should be None if IK is not successful" )
108+
109+ print ("✅ Inverse kinematics assertion passed" )
110+
111+
112+ def test_compute_valid_workspace (self ):
113+ computed_configurations = self .robot_handler .compute_all_configurations (range = 1 , resolution = 0.3 , end_joint_id = 25 ) # used 1 meter range and 0.3 resolution to speed up the test
114+ len_configs = len (computed_configurations )
115+ self .assertIsInstance (computed_configurations , np .ndarray , "Computed configuration should be a numpy array" )
116+
117+ self .assertTrue (np .all (computed_configurations [round (len_configs / 2 )]["end_effector_pos" ] <= np .array ([1 , 1 , 1 ])), "End effector positions should be within the specified range" )
118+ self .assertTrue (np .all (computed_configurations [round (len_configs / 3 )]["end_effector_pos" ] <= np .array ([1 , 1 , 1 ])), "End effector positions should be within the specified range" )
119+
120+ verified_configs = self .robot_handler .verify_configurations (computed_configurations , masses = None , checked_frames = None , tree_id = 5 , selected_joint_id = 25 )
121+
122+ self .assertIsInstance (verified_configs , np .ndarray , "Verified configuration should be a numpy array" )
123+
124+ self .assertEqual (verified_configs [0 ]["tree_id" ], 5 , "Tree ID should match the provided tree ID" )
125+ self .assertEqual (verified_configs [0 ]["selected_joint_id" ], 25 , "Selected joint ID should match the provided joint ID" )
126+
127+
128+ # should be None because there is no selected joint id inside the object
129+ valid_workspace = self .robot_handler .get_valid_workspace (range = 1 , resolution = 0.3 , masses = None , checked_frames = None )
130+
131+ self .assertIsInstance (valid_workspace , np .ndarray , "Valid workspace should be a numpy array" )
132+ self .assertEqual (len (valid_workspace ), 0 , "Valid workspace length should be zero if there is no selected joint id" )
133+
134+ # modify selected joint id to test valid workspace
135+ self .robot_handler .subtrees [5 ]["selected_joint_id" ] = 25
136+ valid_workspace = self .robot_handler .get_valid_workspace (range = 1 , resolution = 0.3 , masses = None , checked_frames = None )
137+
138+ self .assertEqual (len (valid_workspace ), len (verified_configs ), "Valid workspace length should match the verified configurations length" )
139+
140+ print ("✅ Compute valid workspace assertion passed" )
141+
142+
143+
144+
145+
54146
55147if __name__ == "__main__" :
56148 unittest .main ()
0 commit comments