Skip to content

Contributing ​

HotDog follows the conventions of the Dharma stack it is built on; the stack's own guide is in the Dharma hub.

Code ​

Rule
Layout<pkg>/core/ pure Python + numpy (no rclpy, messages, tf2, launch), <pkg>/utils/ ROS-side helpers, thin *_node.py nodes; config/<pkg>.yaml, launch/<pkg>.launch.py, test/unit, test/ros, test/test_style.py
Sizemodules <= 300 lines, tests <= 400; ruff's complexity limits (12) are on: split, do not noqa
Familiesan abstract base in base.py, one implementation per file, a dharma_utils.plugins.Registry (open to entry points, so a product adds one without forking)
Nodessubclass dharma_utils.ros.DharmaNode, start with run(MyNode); declare_config / declare_robot, self.log, self.tf, every()
Robotnothing robot-specific in code: geometry, limits and frames come from the robot.* profile (dharma_utils.robot.RobotProfile)
Parametersdataclasses with param(default, doc=, unit=, min=, max=), validated on start and on every ros2 param set; safety limits live=False; units in names (_sec, _m), radians inside
StyleEnglish, one-line docstrings on public API, type hints, frozen dataclasses, Enum states, no print, no bare except, no commented-out code
CompatibilityROS 2 Foxy on Ubuntu 20.04 (the robot), Python 3.8 (from __future__ import annotations, no 3.9+ runtime features), numpy >= 1.17; distro differences only through dharma_utils.ros
Interfacesrelative topic names, typed latched status messages, separate Trigger services for safety actions (never a SetBool "true = on")
Launchparams_file, robot_params, use_sim_time, log_level; parameters [defaults, robot_params?, params_file?, {non-empty overrides}]; no launch file includes another package's launch file (the product bringup composes them)
Testsevery fixed defect gets a regression test; ROS tests use unique node names and rclpy.init() / try_shutdown() per test; never name a module-level helper setup / teardown

Lint and format run through pre-commit, locally and in CI:

bash
pip install pre-commit && pre-commit install
pre-commit run --all-files          # ruff, clang-format, prettier, shellcheck, yaml/xml checks

Build and test ​

bash
scripts/dev.sh up && scripts/dev.sh build && scripts/dev.sh test   # dev container, foxy
colcon build && colcon test && colcon test-result --verbose         # natively

ament_python packages declare extras_require={'test': ['pytest']}, otherwise colcon runs no tests; check that colcon test-result reports your tests, not 0.

Commits, branches and pull requests ​

  • Conventional Commits, one short line: fix(patrol): the way back starts at the nearest point, feat(reports): retention, feat(bringup)!: ... for a breaking change. Scopes are the packages without hotdog_ (bringup for hotdog) and scripts, docs, ci, docker.
  • Branches fix/<topic>, feat/<topic>, refactor/<topic>, docs/<topic>, ci/<topic>; one topic per pull request into main, merged with a merge commit (no squash). CI must be green on Foxy.
  • A change that needs a Dharma change uses the same branch name in both repositories: CI builds the dharma_* repositories from that branch when it exists, so they are tested together; afterwards pin the merged Dharma commit in dharma.repos.
  • Commits are authored by you, unsigned or signed with your own key.
  • Safety-relevant changes (speeds, limits, e-stop, avoidance, the control mux, the robot profile) need a test that drives the logic, a note on how it was tried on the robot (slow, open area, someone at the e-stop) and a CHANGELOG entry.

Releases ​

Every repository follows SemVer with a Keep a Changelog CHANGELOG.md. A release bumps package.xml (and setup.py) of every package, moves [Unreleased] to ## [x.y.z] - date, rebuilds the PDF guides and is tagged vx.y.z on main. HotDog pins the Dharma commits it was tested with in dharma.repos and the robot packages in external.repos.

Released under the Apache License 2.0. Built on the Dharma stack.