Mujoco KDL Wrapper  0.5.1
MuJoCo + KDL bridge for robot kinematics and dynamics
Loading...
Searching...
No Matches
test Directory Reference

Files

 
test_camera_ros.cpp
 
test_control_modes.cpp
 
test_dual_arm.cpp
 
test_init.cpp
 
test_mjcf_ft_sensor.cpp
 
test_mjcf_load.cpp
 
test_mjcf_pick.cpp
 
test_mjcf_pos_ctrl.cpp
 
test_mjcf_trq_ctrl.cpp
 
test_mjcf_vel_ctrl.cpp
 
test_regressions.cpp
 
test_scene_state.cpp
 
test_table_scene.cpp

Detailed Description

Tests

Tests use GoogleTest and are registered with CTest. Build and run:

git clone https://github.com/vamsikalagaturu/mj_kdl_wrapper.git
cd mj_kdl_wrapper
vcs import < mj_kdl_wrapper.repos
cmake -B build -DCMAKE_BUILD_TYPE=RelWithDebInfo -DBUILD_TESTS=ON
cmake --build build --parallel $(nproc)
# Run all tests
ctest --test-dir build --output-on-failure
# Run a single binary directly
./build/test/test_init

Tests load the bundled models from assets/ and self-skip when one is missing there; the fixture tests (test/fixtures/) always run.

The Python examples run headless under pytest (python/tests/test_examples.py), each checked for exit code 0; the two that always open a window are left out.

Test What it covers
test_init Env/Robot lifecycle: init, reset (hook, ports, options), cleanup, adoption, a chain from outside, offscreen rendering
test_dual_arm two prefixed arms, independent KDL chains, gravity per arm
test_table_scene MJCF table asset, SceneObject quat and prefix, runtime add/remove
test_mjcf_load the TCP chain vs the pinch site, cameras, sites, contact exclusions, attach targets, joint edge cases
test_mjcf_pos_ctrl POSITION trajectory tracking, ctrlrange clamping
test_mjcf_vel_ctrl VELOCITY convergence on the arm
test_mjcf_trq_ctrl gravity with the gripper's mass, impedance drift, jnt_trq_msr
test_mjcf_ft_sensor named force-torque sensor: resolve, read, reset, reject
test_mjcf_pick pick with the gripper: IK waypoints, cube lifted
test_control_modes control modes as actuator groups: added actuators, switching, limits, VELOCITY
test_scene_state Env scene slots, what step() leaves current, what reset() restores
test_regressions fixes from the 0.4.0 audit: rebuilds, re-init, log levels, recorders, screenshot, viewer failure
test_camera_ros ROS camera publisher (built only when configured with ROS)
ex_*_headless each C++ example runs --headless and passes its own self-check

The opt-in viewer test (DISABLED_ prefix, see test_scene_state) opens a Simulate window:

./build/test/test_scene_state --gtest_also_run_disabled_tests --gtest_filter='*Viewer*'

test_init

Scene: single Kinova GEN3 arm from the bundled kinova_gen3/gen3.xml.

  • BasicDOF, SimulationAdvance – 7 joints, the robot is registered; 100 steps advance time by 100 timesteps.
  • ResetRestoresTheKeyframePose – reset() puts the joints on keyframe 0 and time at 0.
  • ResetOptionsPickTheKeyframeOrTheModelDefault – ResetOptions::keyframe = 1 resets to the second keyframe; use_keyframe = false resets to qpos0; ResetInfo says which.
  • ResetSyncsCmdPorts, ResetRestoresEveryPort – every port is re-seeded: msr from the state, pos cmd = pose, vel/trq cmd 0, saturated 0.
  • ResetInvokesOnResetCallback, EnvResetInvokesHookAndSyncsRobot – Env::on_reset runs once per reset() with the Env's context; qfrc_applied is cleared.
  • ResetWithoutAHookStillReseedsTheRobot – no hook set: the robot is still re-seeded.
  • ResetKeepsARequestedControlMode, OnResetPrimesCommandsAndMovesAreReadBack – reset keeps a pending ctrl_mode; on_reset runs after the re-seed and what it moves is read back.
  • CleanupRobotUnregistersIt – after cleanup(Robot *) update() no longer commands it.
  • ChainFromOutsideDrivesTheSameJoints – init_robot_from_chain() reads the same joints as the derived chain; a joint list of the wrong length is refused.
  • TwoEnvs.StepIndependently – two Envs in one process keep their own frames and time.
  • EnvSpec.OwnsItsStringsAcrossARebuild – scene_add_object() rebuilds after the caller's path and prefix strings are gone.
  • EnvAdopt.RunsOnTheCallersPairAndNeverFreesIt – Env::adopt runs the Env on the caller's model/data, rebuilds included, and never frees them.
  • SceneFloor.PlacedAtFloorZ – the ground plane sits at SceneSpec::floor_z.
  • Recorder.OutputPathReachesFfmpegVerbatim – a path with " and $(...) is written as named and runs nothing (skips without EGL or ffmpeg).
  • Offscreen.RendersTheSceneIntoABuffer – init_offscreen() + render_rgb() fill the buffer (skips without EGL).
  • AFailureSaysWhy – a failed call returns a Status whose error names the cause.
  • SceneSpecRequired.AnUnsetFieldFailsTheBuild – unset mass, friction, camera fovy or timestep fails build_scene().

test_dual_arm

Scene: two Kinova GEN3 arms facing each other, the second prefixed r2_.

  • PrefixNamesTheWholeChain – a prefix names every joint of the chain.
  • KdlGravityMatchesMujocoForBothArms – KDL gravity equals qfrc_bias at rest to 1e-9 Nm.
  • DualArmDrift – 500 steps of gravity compensation; EE drift <= 1 um per arm.

test_table_scene

Scene: Kinova GEN3 arm on a table with box and sphere objects.

  • GravityCompDrift – gravity compensation drift <= 1 um after 500 steps.
  • EnvAddRemoveReinitsRobot – runtime scene_add_object / scene_remove_object on the Env: robots and scene slots follow the rebuilt model; a slot whose body is removed is unbound.
  • SceneObjectTransform.PathBackedObjectAppliesQuat – an MJCF-backed object's [x, y, z, w] quat turns its authored site as expected.
  • SceneObjectPrefix.NamesStayAsAuthoredUnlessAPrefixIsSet – the same asset twice needs distinct prefixes.

test_mjcf_load

  • MjcfGripperTest (arm + 2F-85): the TCP chain equals the g_pinch site; the driver joint range is 0..0.8 rad and the actuator's ctrlrange tops out at 0.82; bind_scene_joint() by name; AttachmentSpec::contact_exclusions adds the pair; attaching to a body with an offset; CameraSpec on the world and on a body; SiteSpec adds a site and leaves an authored one.
  • AttachToFrame (fixtures/joint_edge_cases.xml as an object): a robot stands on an object's named <frame>.
  • MjcfPathTest (fixtures/meshdir/): a relative model path to an MJCF with a relative meshdir builds.
  • JointEdgeCaseTest (fixtures/joint_edge_cases.xml): a chain refuses a body with two joints and a ball joint on its path; a plain hinge chain builds; a joint slot refuses a ball joint.

test_mjcf_pos_ctrl

CtrlMode::POSITION. Linearly interpolates from home to a target pose over 1.5 s, settles 0.5 s. Max joint error < 0.01 rad.

  • ClampCtrlrange – position commands are clamped to the actuator ctrlrange and flagged in jnt_saturated (Gen3 joints 2, 4 and 6).

test_mjcf_vel_ctrl

CtrlMode::VELOCITY through the <joint>_velocity actuators added by RobotSpec::modes: a clamped proportional velocity command brings the arm to the target within 0.01 rad in under 2.5 s.

test_mjcf_trq_ctrl

CtrlMode::TORQUE, arm + 2F-85 gripper attached.

  • GravityIncludesTheGripperMass – at home, KDL gravity with the lumped tool equals qfrc_bias to 1e-9 Nm, and a chain without the tool is off by more than 1 Nm.
  • ImpedanceDrift – PD + gravity for 500 steps: EE drift < 10 um.
  • TrqMsrReadsQfrcActuator – nonzero torque commands come back in jnt_trq_msr as qfrc_actuator.

test_mjcf_ft_sensor

Scene: GEN3 + assets/ft_sensor.xml + 2F-85, sensor named through ToolFrameSpec::ft_sensors.

  • ReadsNamedWrench – the logical sensor resolves its <force>/<torque> sensors and frame site; update() reads their sensordata; at rest it carries the weight below it.
  • ResetReReadsTheWrench – after reset() the wrench equals the sensors' sensordata.
  • RejectsMissingTorqueSensor – a sensor naming a missing <torque> sensor fails init_robot_from_mjcf(), and the robot is not registered.

test_mjcf_pick

Scene: GEN3 + Robotiq 2F-85 + 4 cm cube on the floor, driven by the examples' helpers (src/examples/common.hpp).

  • TcpLiesBeyondTheWrist – the TCP chain ends at the pinch site, 21.7 cm out of the bracelet.
  • IkStaysOnTheSeedBranch – consecutive IK waypoints stay within 1.5 rad of each other.
  • CubeLifted – the pick sequence lifts the cube above 0.28 m.

test_scene_state

Scene: GEN3, a falling cube and 50 fixed filler bodies.

  • FreeBodyPoseAndDerivedFrameAgreeAfterAStep – after step(), the cube's body frame equals its qpos pose to 1e-12 (no one-step lag).
  • StepMatchesMjStepBitwise – 200 step() calls give the same qpos/qvel as mj_step.
  • StepHonoursAQposWrittenBetweenSteps – a direct qpos write before step() is integrated as mj_step would, and the frame follows it.
  • AFrameFollowsAQposWrittenDirectly – get_body_frame() sees a direct qpos write with no step in between.
  • UpdateReadsThenAppliesRobotsAndSlots – update(Env*) reads robot ports, then writes robot torque commands and slot wrenches.
  • ResetRestoresEverySlot – reset() zeroes wrench slots, sets actuator slot commands to the reset ctrl, and re-reads joint and free-body slots.
  • BindFreeBodyRejectsFixedUnknownAndDuplicate, SceneJointTracksQposAndRejectsAFreeJoint, ASlotAddressSurvivesFurtherBinds – slot binding rules; slot pointers stay valid.
  • ApplyClearsAWrenchThatIsNoLongerPushed – a wrench set to zero is cleared from xfrc_applied.
  • DISABLED_ViewerKeepsUserWrenchesWhileAnotherThreadReads – opens a Simulate window, so it runs only with --gtest_also_run_disabled_tests: a user wrench survives 1000 steps while the render thread runs and a second thread reads frames.

test_control_modes

Each mode is an actuator group switched with opt.disableactuator.

  • ArmModesTest (GEN3 <position> servos): the <joint>_torque motors are added in a disabled group; POSITION tracks a 0.2 rad ramp within 0.05 rad; POSITION -> TORQUE -> POSITION holds the pose within 0.01 rad; TORQUE saturates at the servo's forcerange (105 Nm); VELOCITY tracks jnt_vel_cmd within 2e-3 rad/s; update() and mode switches never write qfrc_applied; two arms run different modes.
  • GripperModesTest (GEN3 + 2F-85): the gripper gets no torque actuator and stays in group 0; it closes and opens while the arm runs in TORQUE.
  • MotorWheelModesTest (fixtures/motor_wheel.xml): only the listed wheel gets a <velocity> actuator, the pivot is left alone; VELOCITY tracks 5 rad/s through env.scene, then TORQUE takes over without a jump; a scene actuator slot flags a clamped command; a motor-driven robot starts in TORQUE and joint_force_limits() follows the active mode.
  • AttachedArmModesTest (fixtures/arm_mount.xml + two attached GEN3s): each arm gets mode groups of its own; one switches to TORQUE and holds within 0.01 rad while the other holds in POSITION; an attachment without modes gets no actuators.

test_regressions

Fixes from the 0.4.0 audit; headless, self-skips without the bundled Gen3.

  • RebuildTest – scene_add_object() keeps the physics state and the commands; a failed scene_remove_object() keeps the object order; removing a robot's joint fails and leaves the Env; a failed re-init leaves the robot as it was; an on_reset set before init_env() is kept; recorders follow a rebuild and outlive each other; a frame shows the state it was taken at, delivered on the recorder's thread; one recorder keeps every frame it is given; an attachment left at the world is refused rather than dropped; a pointer held to a port element still commands and reads the robot after reset(); a viewer that cannot open returns an error.
  • LogLevel.IsASeverityThreshold – each level shows its own and more severe messages.
  • Screenshot.PathReachesFfmpegVerbatimAndAMissingFfmpegIsAFailure – the screenshot writer takes its path verbatim and reports a missing ffmpeg.

test_camera_ros

Built only when the wrapper is configured with ROS (mj_kdl_wrapper::camera_ros exists).

  • IntrinsicsComeFromTheModelFovy – the published CameraInfo K matrix follows the camera's fovy and image size, in the camera's optical frame.
  • NobodyWatchingCostsNothing – with no subscriber the publisher never asks for a frame.