Repository navigation
Conversation
A rostest per robot starts it in Gazebo without a GUI (no display needed), with the diff drive controller, and runs two tests: - publishtest: joint states and odometry are published - test_drive.py: 0.2 m/s for 3 s and 0.5 rad/s for 3 s; checks the controller's odometry and the robot's true pose from Gazebo (/gazebo/model_states), and that the two agree The true pose catches mistakes the odometry repeats: with the wheel joints swapped the robot turns right while the odometry reports left, and a wheel radius 20 % too big makes odometry and true distance differ. A wrong joint name stops the controller, so no odometry is published. - diffbot_gazebo/test: sim_drive.launch, sim_drive_diffbot.test, sim_drive_remo.test, test_drive.py; registered with add_rostest - Each test file gets its own Gazebo port (GAZEBO_MASTER_URI): catkin runs them in parallel, and two Gazebo servers on the default port made the second one fail - diffbot_control.launch: argument rqt_robot_steering (default true), so the test can leave out the GUI - diffbot_view.launch: the default world pointed to the missing worlds/db_world.launch; it's worlds/db_world.world - CI: industrial_ci builds remo_description from diffbot_dev.repos Closes #110
…ription test_depend - diffbot_description, diffbot_control and diffbot_gazebo install their files (urdf, config, meshes, launch, rviz, worlds, models). industrial_ci builds with an install space only, and xacro couldn't find diffbot.urdf.xacro there. remo_description gets the same rule in ros-mobile-robots/remo_description#1. - diffbot_gazebo no longer declares remo_description as a test_depend: the dev container's Dockerfile installs the dependencies of every package.xml before setup.sh clones remo_description, so rosdep couldn't resolve it. Both workflows clone it with diffbot_dev.repos.
"industrial_ci tests from one" left open what "one" is. Say what the install space is, what goes missing without the rules and who builds from it.
fjp
force-pushed
the
feat/simulation-test
branch
from
October 14, 2026 18:53
52a9908 to
5dd9f82
Compare
fjp
added a commit
to ros-mobile-robots/remo_description
that referenced
this pull request
Oct 14, 2026
* Install the model files, so the package works from an install space catkin's install space had only package.xml and the CMake files: config, launch, meshes, rviz and urdf weren't installed. diffbot's simulation test (ros-mobile-robots/diffbot#112) builds this package in industrial_ci, which always uses an install space, and xacro then can't find urdf/remo.urdf.xacro. * Explain the install rule's comment more clearly "industrial_ci tests from one" left open what "one" is. Say what the install space is, what goes missing without the rule and who builds from it.
…ering - test_drive.py: moved() (was change()) explains why the moves are compared in the robot's start frame and where the rotation comes from; the yaw comes from tf's euler_from_quaternion instead of a hand-written formula; topic constants end in _TOPIC; the tests are test_forward and test_turn, since they don't depend on each other's order; why cmd_vel is sent repeatedly. - .test files: what publishtest does, with a link to its documentation. - diffbot_control.launch: why rqt_robot_steering can be turned off; final newline.
relative_motion() (was moved()) describes the motion between two poses as in the odometry motion model of Probabilistic Robotics (Thrun, Burgard, Fox, section 5.4): a rotation rot1 towards the end position, a translation trans, and a rotation rot2 to the end heading. Like ROS amcl, rot1 is 0 for translations under 1 cm. The forward test checks trans and that rot1 and the total turn stay small (straight ahead); the turn test checks the total turn and trans. Fault checks unchanged: a 20 % too big wheel radius gives 3 failures, swapped wheels 2.
5 tasks
- relative_motion() takes start_pose and end_pose, typed Pose2D (x, y, theta); Motion is a typing.NamedTuple - drive() only sends the velocity command (end_time instead of end); stop() sends zero and waits; measure_motion() remembers both poses, calls the two and returns the odometry and true pose motions - The tests call measure_motion() with named arguments - odom_pose, true_pose and cmd_vel are declared on the class, with a comment why they belong to it - planar(), wrap() and relative_motion() explain the quaternion, the atan2 wrap and hypot - Type hints; PEP 8 with ROS 2's line length of 99 (flake8 with ament_flake8's settings and mypy pass) - test_turn's comment names the cause of the short turn, Gazebo's P-only wheel velocity controller, and the follow-up #116
10 tasks
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The first tests that check how the robot behaves, not only that everything builds. Both CI workflows run them on every pull request: CI with industrial_ci, and Dev container.
What the test does
A rostest per robot,
diffbot_gazebo/test/sim_drive_diffbot.testandsim_drive_remo.test, starts the robot in Gazebo without a GUI, on the empty world, with the diff drive controller. It needs no display. Two tests then run:publishtest, a test node that comes with rostest:/diffbot/joint_statesand/diffbot/mobile_base_controller/odomare published.test_drive.py: drives 0.2 m/s for 3 s, then turns at 0.5 rad/s for 3 s, and checks each move twice:/gazebo/model_states).Both must be in range (forward: 0.4–0.75 m, straight ahead; turn: 0.5–2.0 rad to the left), and they must agree: within 0.05 m forward and 0.25 rad when turning.
The odometry and Gazebo report poses in different frames (odometry starts at 0, 0, 0, Gazebo spawns the robot at x = -2, y = -0.5). So the test compares motions, not poses.
relative_motion()describes the motion between two poses as in the odometry motion model of Probabilistic Robotics (Thrun, Burgard, Fox, section 5.4): a rotationrot1towards the end position, a translationtrans, and a rotationrot2to the end heading. These don't depend on the frame. Like ROS amcl's odometry model,rot1is 0 for translations under 1 cm (turning on the spot). The heading comes from tf'seuler_from_quaternion. Each method does one step:drive()sends the velocity command,stop()stops the robot,measure_motion()returns the motion from the odometry and from the true pose, and the tests call it with named arguments. The two tests,test_forwardandtest_turn, each check only their own motion, so their order doesn't matter. The script has type hints and passes flake8 with ROS 2'sament_flake8settings (PEP 8, line length 99) and mypy.The true pose is what makes the test useful. The odometry repeats some configuration mistakes, so on its own it would still look right.
What it catches
Each case was checked by breaking
diffbot_control.yamlin a copy and running the tests:publishtestfails,test_driveerrorsChanges
diffbot_gazebo/test/:sim_drive.launch(Gazebo headless withdiffbot_empty.world, controllers withoutrqt_robot_steering), the two.testfiles andtest_drive.py. They're registered withadd_rostestin CMakeLists.txt, withtest_depends in package.xml.remo_descriptioncan't be one: it isn't a released ROS package, and the dev container's Dockerfile resolves everypackage.xmlbeforesetup.shclones it. Both workflows clone it withdiffbot_dev.repos.diffbot_description,diffbot_controlanddiffbot_gazebo(urdf,config,meshes,launch,rviz,worlds,models). None of the packages installed its files. industrial_ci builds into an install space by default (catkin config --install), wherexacrocouldn't finddiffbot.urdf.xacro.remo_descriptiongets the same rule in Install the model files, so the package works from an install space remo_description#1. The other packages, includingdiffbot_base's nodes, still have no install rules: Install rules for all packages, so they work from an install space #113.GAZEBO_MASTER_URI, 11351 and 11352). catkin runs the two test files in parallel, each with its own ROS master. On Gazebo's default port 11345, the second Gazebo server couldn't start, and Remo's test timed out. The two ports also don't collide with a simulation that's open in the dev container.diffbot_control.launch: a new argumentrqt_robot_steering(defaulttrue, so nothing changes), so the test can leave out the GUI.diffbot_view.launch: the default world pointed toworlds/db_world.launch, which doesn't exist; it'sworlds/db_world.world.diffbot.launchalways overrode it, so this only mattered when the file was launched on its own.remo_descriptionfrom source withUPSTREAM_WORKSPACE: diffbot_dev.repos, like the dev container, because it isn't a released ROS package.Turning on the spot reaches about 1.3 rad for DiffBot and 1.0–1.2 rad for Remo, instead of the commanded 1.5 rad. Gazebo's wheel velocity controller (
diffbot_control/config/pid.yaml) has only a P gain, which leaves Remo's wheels at about 80 % of the commanded speed when turning, and the wheels slip. The test therefore only checks that the robot turns left by a clear amount, and that odometry and true pose agree. #116 tunes the gains (measurements there) and then tightens the turn check.Testing
In the dev container image, with the commands of the Dev container workflow (
catkin build --catkin-make-args run_tests,catkin_test_results build):Six clean runs: 10 tests, 0 errors, 0 failures, about 50 s each for both robots in parallel.
The three broken cases above fail as described.
From an install space, as industrial_ci builds (
catkin config --install, with the install rule added toremo_description): 10 tests, 0 errors, 0 failures.industrial_ci's Remo test needs ros-mobile-robots/remo_description#1 merged first, because industrial_ci clones
remo_description'smainbranch.Closes #110