import unittest import numpy as np import pinocchio as pin from core.model_contract import ( MASTER_FRAMES, MASTER_JOINT_NAMES, SLAVE_FRAMES, SLAVE_JOINT_NAMES, clip_configuration, finite_joint_limits, joint_q_indices, load_models, require_frame, safe_configuration, ) class ModelContractTest(unittest.TestCase): @classmethod def setUpClass(cls): cls.models = load_models() def test_canonical_models_and_simulated_tcp_load(self): self.assertEqual(self.models.master.nq, 7) self.assertEqual(self.models.slave.nq, 7) for name in MASTER_FRAMES.values(): require_frame(self.models.master, name) for name in SLAVE_FRAMES.values(): require_frame(self.models.slave, name) def test_safe_slave_configuration_is_strictly_inside_limits(self): q = safe_configuration(self.models.slave, SLAVE_JOINT_NAMES) qidx = joint_q_indices(self.models.slave, SLAVE_JOINT_NAMES) lower, upper = finite_joint_limits(self.models.slave, SLAVE_JOINT_NAMES) self.assertTrue(np.all(q[qidx] > lower)) self.assertTrue(np.all(q[qidx] < upper)) def test_clipping_reports_limit_event(self): q = pin.neutral(self.models.slave) qidx = joint_q_indices(self.models.slave, SLAVE_JOINT_NAMES) lower, upper = finite_joint_limits(self.models.slave, SLAVE_JOINT_NAMES) q[qidx] = upper + 0.1 clipped, event = clip_configuration( self.models.slave, q, SLAVE_JOINT_NAMES, margin=1e-4 ) self.assertTrue(event) self.assertTrue(np.all(clipped[qidx] <= upper - 1e-4 + 1e-12)) self.assertTrue(np.all(clipped[qidx] >= lower + 1e-4 - 1e-12)) if __name__ == "__main__": unittest.main()