From e0a0a1688d33b225b570cc821259452ce614872e Mon Sep 17 00:00:00 2001 From: Vignesh Date: Tue, 6 Oct 2026 21:51:17 +0200 Subject: [PATCH 1/7] ci: add baseline ROS 2 CI image Signed-off-by: Vignesh --- .github/workflows/ci-image.yml | 54 ++++++++++++++++++++++++++++++++++ containers/ci/Dockerfile | 46 +++++++++++++++++++++++++++++ 2 files changed, 100 insertions(+) create mode 100644 .github/workflows/ci-image.yml create mode 100644 containers/ci/Dockerfile diff --git a/.github/workflows/ci-image.yml b/.github/workflows/ci-image.yml new file mode 100644 index 0000000..50d19d1 --- /dev/null +++ b/.github/workflows/ci-image.yml @@ -0,0 +1,54 @@ +name: Build CI Image + +on: + push: + branches: + - main + paths: + - "containers/ci/**" + - ".github/workflows/ci-image.yml" + + workflow_dispatch: + +permissions: + contents: read + packages: write + +env: + REGISTRY: ghcr.io + IMAGE_NAME: openamrobot/ci-ros2-jazzy + +jobs: + build-and-push: + name: Build and publish CI image + runs-on: ubuntu-24.04 + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Log in to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build and push CI image + id: build + uses: docker/build-push-action@v6 + with: + context: . + file: containers/ci/Dockerfile + push: true + tags: | + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} + + - name: Print image digest + run: | + echo "Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" + echo "Digest: ${{ steps.build.outputs.digest }}" \ No newline at end of file diff --git a/containers/ci/Dockerfile b/containers/ci/Dockerfile new file mode 100644 index 0000000..90d366b --- /dev/null +++ b/containers/ci/Dockerfile @@ -0,0 +1,46 @@ +FROM ros:jazzy-ros-base@sha256:066420e07f60aa18262f2479981def87ebcfcec42eefb0c0c57c4a46098348ca + +ARG DEBIAN_FRONTEND=noninteractive + +# Common CI and ROS workspace tooling +RUN apt-get update && apt-get install -y --no-install-recommends \ + python3-colcon-common-extensions \ + python3-rosdep \ + python3-vcstool \ + git \ + curl \ + \ + # Platform ROS dependencies \ + ros-jazzy-nav2-bringup \ + ros-jazzy-nav2-common \ + ros-jazzy-slam-toolbox \ + ros-jazzy-nav2-bt-navigator \ + ros-jazzy-nav2-behaviors \ + ros-jazzy-nav2-controller \ + ros-jazzy-nav2-lifecycle-manager \ + ros-jazzy-nav2-map-server \ + ros-jazzy-nav2-amcl \ + ros-jazzy-nav2-planner \ + ros-jazzy-nav2-smoother \ + ros-jazzy-nav2-waypoint-follower \ + ros-jazzy-nav2-velocity-smoother \ + ros-jazzy-nav2-collision-monitor \ + ros-jazzy-opennav-docking \ + ros-jazzy-laser-filters \ + ros-jazzy-rviz2 \ + ros-jazzy-camera-ros \ + ros-jazzy-joint-state-publisher \ + ros-jazzy-joint-state-publisher-gui \ + ros-jazzy-xacro \ + ros-jazzy-ros-gz-sim \ + ros-jazzy-ros-gz-bridge \ + ros-jazzy-rplidar-ros \ + ros-jazzy-apriltag-msgs \ + ros-jazzy-apriltag-ros \ + ros-jazzy-nav2-msgs \ + ros-jazzy-robot-localization \ + ros-jazzy-topic-tools \ + ros-jazzy-rmw-cyclonedds-cpp \ + && rm -rf /var/lib/apt/lists/* + +ENV RMW_IMPLEMENTATION=rmw_cyclonedds_cpp \ No newline at end of file From 31c2913c959b6ebe49fa77024be2cfcf94394f70 Mon Sep 17 00:00:00 2001 From: Vignesh Date: Tue, 6 Oct 2026 23:18:49 +0200 Subject: [PATCH 2/7] ci: pin external actions by commit sha Signed-off-by: Arumuga Vignesh S R <129583467+wikki26@users.noreply.github.com> --- .github/workflows/ci-image.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-image.yml b/.github/workflows/ci-image.yml index 50d19d1..a94c2d0 100644 --- a/.github/workflows/ci-image.yml +++ b/.github/workflows/ci-image.yml @@ -25,13 +25,13 @@ jobs: steps: - name: Check out repository - uses: actions/checkout@v4 + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Log in to GHCR - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -39,7 +39,7 @@ jobs: - name: Build and push CI image id: build - uses: docker/build-push-action@v6 + uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . file: containers/ci/Dockerfile From d9290432dea3848ee6be12a1ef6723d93f3535bb Mon Sep 17 00:00:00 2001 From: Arumuga Vignesh S R <129583467+wikki26@users.noreply.github.com> Date: Thu, 8 Oct 2026 19:48:44 +0200 Subject: [PATCH 3/7] ci: validate Docker image on pull requests Signed-off-by: Arumuga Vignesh S R <129583467+wikki26@users.noreply.github.com> --- .github/workflows/ci-image.yml | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci-image.yml b/.github/workflows/ci-image.yml index a94c2d0..50bf8e2 100644 --- a/.github/workflows/ci-image.yml +++ b/.github/workflows/ci-image.yml @@ -1,6 +1,12 @@ + name: Build CI Image on: + pull_request: + paths: + - "containers/ci/**" + - ".github/workflows/ci-image.yml" + push: branches: - main @@ -12,7 +18,6 @@ on: permissions: contents: read - packages: write env: REGISTRY: ghcr.io @@ -20,9 +25,13 @@ env: jobs: build-and-push: - name: Build and publish CI image + name: Build CI image runs-on: ubuntu-24.04 + permissions: + contents: read + packages: write + steps: - name: Check out repository uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 @@ -31,24 +40,26 @@ jobs: uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Log in to GHCR + if: github.event_name == 'push' && github.ref == 'refs/heads/main' uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build and push CI image + - name: Build CI image and publish from main id: build uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . file: containers/ci/Dockerfile - push: true + push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} tags: | ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} - - name: Print image digest + - name: Print published image digest + if: github.event_name == 'push' && github.ref == 'refs/heads/main' run: | echo "Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" - echo "Digest: ${{ steps.build.outputs.digest }}" \ No newline at end of file + echo "Digest: ${{ steps.build.outputs.digest }}" From a95e751e1cfa62d635ed68d94303e5925c1515e9 Mon Sep 17 00:00:00 2001 From: Arumuga Vignesh S R <129583467+wikki26@users.noreply.github.com> Date: Thu, 8 Oct 2026 20:29:19 +0200 Subject: [PATCH 4/7] fix(ci): remove legacy RPLIDAR driver from baseline image Signed-off-by: Arumuga Vignesh S R <129583467+wikki26@users.noreply.github.com> --- containers/ci/Dockerfile | 1 - 1 file changed, 1 deletion(-) diff --git a/containers/ci/Dockerfile b/containers/ci/Dockerfile index 90d366b..3e3c540 100644 --- a/containers/ci/Dockerfile +++ b/containers/ci/Dockerfile @@ -34,7 +34,6 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ ros-jazzy-xacro \ ros-jazzy-ros-gz-sim \ ros-jazzy-ros-gz-bridge \ - ros-jazzy-rplidar-ros \ ros-jazzy-apriltag-msgs \ ros-jazzy-apriltag-ros \ ros-jazzy-nav2-msgs \ From 574dfc80380fa83137b6fdc68147bf9b84703de6 Mon Sep 17 00:00:00 2001 From: Arumuga Vignesh S R <129583467+wikki26@users.noreply.github.com> Date: Tue, 13 Oct 2026 21:33:02 +0200 Subject: [PATCH 5/7] Merge origin/main into h-ci-1-baseline-image --- WATCHDOG.md | 19 ++- decisions.yaml | 285 +++++++++++++++++++++++++--------- profile/README.md | 2 +- tests/test_check_decisions.py | 113 +++++++++++++- 4 files changed, 327 insertions(+), 92 deletions(-) diff --git a/WATCHDOG.md b/WATCHDOG.md index 1cce153..b27b723 100644 --- a/WATCHDOG.md +++ b/WATCHDOG.md @@ -121,31 +121,34 @@ identical to the register. | Decision | Status | Accepted on the same line (any one; case does not matter) | |---|---|---| -| BOM-ISSUE-IN-FORCE | recorded | *BOM Issue 7.3 is the canonical hardware BOM*: `supersed (superseded, supersedes)`, `replaced`, `previous`, `earlier`
*B-01 is superseded*: `supersed (superseded, supersedes)`
*BOM Issue 7.3 is the canonical hardware BOM*: `supersed (superseded, supersedes)`, `replaced`, `previous`, `earlier`, `historical`
*superseded source still cited (P-03-rev18.1 line 7); cite P-03-rev18.7*: no label; correct the line or add a decision-allow marker | -| MAST-INSTALL-HEIGHT | superseded | `supersed (superseded, supersedes)`, `legacy`, `historical`, `earlier`, `previous`, `rev 18.1 to rev 18.6` | +| BOM-ISSUE-IN-FORCE | recorded | *BOM Issue 7.7 is the canonical hardware BOM*: `supersed (superseded, supersedes)`, `replaced`, `previous`, `earlier`
*B-01 is superseded*: `supersed (superseded, supersedes)`
*BOM Issue 7.7 is the canonical hardware BOM*: `supersed (superseded, supersedes)`, `replaced`, `previous`, `earlier`, `historical`
*superseded source still cited (P-03-rev18.1 line 7); cite P-03-rev19.0*: no label; correct the line or add a decision-allow marker | +| MAST-INSTALL-HEIGHT | superseded | `supersed (superseded, supersedes)`, `legacy`, `historical`, `earlier`, `previous`, `rev 18.1 to rev 18.6`, `lift`, `L1350`, `extended`, `full stroke` | | MAST-POSITIONS | superseded | `supersed (superseded, supersedes)`, `legacy`, `historical`, `earlier`, `previous`, `rev 18.1 to rev 18.6` | | MAST-TOP-HEIGHT | superseded | `supersed (superseded, supersedes)`, `legacy`, `historical`, `earlier`, `previous`, `rev 18.1 to rev 18.6` | | MAX-ASSEMBLED-HEIGHT | recorded | *maximum assembled height is 1700 mm*: no label; correct the line or add a decision-allow marker
*1700 mm is the assembled-height envelope, not a shoulder height or mast position*: `max`, `envelope`, `not shoulder, not the shoulder`, `higher`, `supersed (superseded, supersedes)` | | DATUM-HEIGHT-STACK | recorded | *the steel chassis deck top is 294 mm above the floor*: `supersed (superseded, supersedes)`, `historical`, `legacy`, `earlier`, `previous`
*the lift base-plate top face is 304 mm above the floor, the reference for lift and shoulder heights*: `supersed (superseded, supersedes)`, `historical`, `legacy`, `earlier`, `previous` | | FRAMES-REP105 | recorded | *base_link is at the drive-axle midpoint and axle height; base_footprint is on the floor*: `base_footprint`, `not`, `never`, `supersed (superseded, supersedes)`, `historical`, `legacy`
*base_footprint is on the floor under the drive-axle midpoint*: `not`, `never`, `supersed (superseded, supersedes)`, `historical`, `legacy`
*imu_link sits on the centreline away from motor magnetic fields*: `away`, `not`, `never`, `supersed (superseded, supersedes)`, `historical`, `legacy` | +| NEAR-FIELD-FRAMES | recorded | `screening`, `bench`, `until` | | BATTERY-PLACEMENT | recorded | `supersed (superseded, supersedes)`, `historical`, `previous`, `earlier`, `rev 18.1 to rev 18.6` | | SPEED-CEILING | recorded | *1.5 m/s is a command ceiling, not an operating limit*: `ceiling`, `analytical`
*1.5 m/s is not an accepted operating speed*: `ceiling`, `analytical`, `not` | | DRIVETRAIN | recorded | *the selected motor variant is ZLLG80ASM250-L-B*: no label; correct the line or add a decision-allow marker
*ZLTECH is the selected 2.0 drivetrain, not an option*: no label; correct the line or add a decision-allow marker
*brake fail-safe function and ratings are open supplier-evidence gates*: `pending`, `F2A`, `verif`, `not yet`, `unverified` | | RS485-NOT-IN-2-0 | recorded | *RS485 is not provisioned in 2.0*: `not used`, `no RS485`, `not provisioned`, `without`, `legacy`, `Gate A`, `removed`, `not in 2.0`
*CAN1 and CAN2 are dedicated; no upper-body serial link to the base*: no label; correct the line or add a decision-allow marker | -| BASE-CONTROLLER-GATES | recorded | *Teensy is the Gate A controller and the release fallback, not a bench target*: no label; correct the line or add a decision-allow marker
*ICM-42688-P is gated; MPU6500 remains the Gate A IMU*: `Gate B`, `conditional`, `20 Nov`, `candidate`, `pending`, `not yet`, `after`
*the Gate A IMU is the MPU6500*: no label; correct the line or add a decision-allow marker | -| BASE-CONTROLLER-IO | recorded | *the base controller is the STM32H723ZG on the NUCLEO-H723ZG; label STM32H743 / NUCLEO-H743ZI2 material as superseded*: `supersed (superseded, supersedes)`, `legacy`, `historical`, `replaced`
*the ultrasonic sensors are two MaxBotix MB7060 on dedicated STM32 UARTs at 9600 8N1; no sensor I2C*: `supersed (superseded, supersedes)`, `legacy`, `historical`, `replaced`
*micro-ROS runs over UDP on Ethernet between MCU and Jetson; USB is for the bench only*: `bench`, `legacy`, `Gate A`, `Teensy`, `supersed (superseded, supersedes)`, `historical` | +| BASE-CONTROLLER-GATES | recorded | *Teensy is the Gate A controller and the release fallback, not a bench target*: no label; correct the line or add a decision-allow marker
*the Gate A IMU is the MPU6500*: `would return`, `labeled`, `labelled`, `assumed`, `not a real`, `instead of`, `USE_MPU6050`, `driver` | +| BASE-CONTROLLER-IO | recorded | *the base controller is the STM32H723ZG on the NUCLEO-H723ZG; label STM32H743 / NUCLEO-H743ZI2 material as superseded*: `supersed (superseded, supersedes)`, `legacy`, `historical`, `replaced`
*the ultrasonic sensors are four MaxBotix MB7060 on dedicated STM32 UARTs at 9600 8N1; no sensor I2C*: `supersed (superseded, supersedes)`, `legacy`, `historical`, `replaced`
*micro-ROS runs over UDP on Ethernet between MCU and Jetson; USB is for the bench only*: `bench`, `legacy`, `Gate A`, `Teensy`, `supersed (superseded, supersedes)`, `historical`
*the base has four MaxBotix MB7060 (edge holes) and two TF-Luna ToF cliff sensors (centre holes)*: `supersed (superseded, supersedes)`, `legacy`, `historical` | | IMU-TOPIC-OWNERSHIP | recorded | *firmware publishes /imu/data_raw; /imu/data belongs to the host filter*: `host`, `filter (not unfiltered)`, `EKF`, `madgwick`, `must not`, `never`, `outdated`, `older revision(s)`
*firmware must not publish filtered /imu/data*: no label; correct the line or add a decision-allow marker | -| CAMERAS | recorded | *the base camera is the Orbbec Gemini 336L*: `legacy`, `historical`, `previous`, `not used`, `replaced`
*the base camera tilts about 10 degrees up*: no label; correct the line or add a decision-allow marker
*the 2.0 base camera is the Orbbec Gemini 336L*: `legacy`, `Gate A`, `historical`
*the Gemini 336L up-tilt positions are 5, 10 and 15 degrees, baseline 10*: `supersed (superseded, supersedes)`, `historical`, `legacy` | +| CAMERAS | recorded | *the base camera is the Orbbec Gemini 336L*: `legacy`, `historical`, `previous`, `not used`, `replaced`
*the base camera tilts about 10 degrees up*: no label; correct the line or add a decision-allow marker
*the 2.0 base camera is the Orbbec Gemini 336L*: `legacy`, `Gate A`, `historical`
*the Gemini 336L up-tilt positions are 5, 10 and 15 degrees, baseline 10*: `supersed (superseded, supersedes)`, `historical`, `legacy`
*the Gemini 336L housing centre is 142.5 mm above the floor, base_camera_link (0.376, 0, 0.0445)*: `supersed (superseded, supersedes)`, `historical` | | HEAD-CAMERA-IDENTITY | recorded | `supersed (superseded, supersedes)`, `historical`, `legacy`, `replaced`, `not` | -| POWER-RAILS | recorded | *there is no 12 V rail in 2.0*: `no 12`, `not`, `never`, `legacy`
*there is no 12 V rail in 2.0*: `legacy` | +| POWER-RAILS | recorded | *there is no 12 V rail in 2.0*: `no 12`, `not`, `never`, `legacy`
*there is no 12 V rail in 2.0*: `legacy`, `Gate A` | | DOCK-NO-CONTACTS | recorded | *2.0 docking has no dock contacts*: `no`, `not`, `without`, `3.0`, `never`
*no dock or charge pilot in 2.0*: `no`
*wireless charging belongs to 3.0*: `3.0`, `later`, `deferred`, `not` | | DOCKING-NOT-CHARGING | recorded | *2.0 docking is positioning only*: `not`, `never`, `instead`, `non-charging`, `legacy`
*never report charging from a docking pose*: no label; correct the line or add a decision-allow marker
*docking success never establishes charging*: `not`, `never`, `does not` | | TELEMETRY-NOT-SAFETY-EVIDENCE | recorded | `not`, `never`, `functional`, `no substitute` | | SAFETY-PROCUREMENT | recorded | *the EDM variant is not selected*: `not`, `unselected`, `open`
*no single-channel or uncertified E-stop recommendation*: no label; correct the line or add a decision-allow marker
*CTL-004 is bench-only*: `bench-only`, `until` | | COMPUTE | recorded | `legacy`, `historical`, `removed`, `supersed (superseded, supersedes)`, `Gate A`, `previous`, `earlier` | -| NAV-LIDAR | recorded | *the 2.0 navigation LiDAR is the RPLIDAR S3 (S3M1-R2); the Hokuyo UST-10LX was dropped*: `supersed (superseded, supersedes)`, `dropped`, `legacy`, `historical`
*the 2.0 navigation LiDAR is the RPLIDAR S3 (S3M1-R2); label RPLIDAR A1 material as legacy*: `legacy`, `Gate A`, `existing robot`, `historical`, `replaced` | +| NAV-LIDAR | recorded | *the 2.0 navigation LiDAR is the RPLIDAR S3 (S3M1-R2); the Hokuyo UST-10LX was dropped*: `supersed (superseded, supersedes)`, `dropped`, `legacy`, `historical`
*the 2.0 navigation LiDAR is the RPLIDAR S3 (S3M1-R2); label RPLIDAR A1 material as legacy*: `legacy`, `Gate A`, `existing robot`, `historical`, `replaced`
*lidar_link is (0.330, 0, 0.124) from base_link, yaw pi, with the 7.1 mm spacer plate*: `legacy`, `Gate A`, `supersed (superseded, supersedes)`, `historical` | | RELEASE-MILESTONES | recorded | *the OpenAMRobot 2.0 final release is 18 December 2026*: `supersed (superseded, supersedes)`, `previous`, `earlier`, `historical`
*there is no v0.2 release; development cycle 2 ends 20 November 2026 with v2.0.0-rc.1, and v2.0.0 follows on 18 December 2026*: `supersed (superseded, supersedes)`, `historical`, `earlier`, `previous`
*development cycle 2 ends 20 November 2026 with v2.0.0-rc.1, not 13 November*: `supersed (superseded, supersedes)`, `historical`, `earlier`, `previous` | -| LIFT | recorded | *the lift is approved in principle for 2.0*: `supersed (superseded, supersedes)`, `historical`, `earlier`, `previous`, `no longer`, `rev 18.1 to rev 18.6`
*the fixed mast is no longer the baseline; the lift is approved in principle*: `supersed (superseded, supersedes)`, `historical`, `earlier`, `previous`, `legacy`, `replace (replaced, replacement)`, `instead of`, `no longer`, `rev 18.1 to rev 18.6`
*the lift is not deferred to 3.0; it is approved in principle for 2.0*: `supersed (superseded, supersedes)`, `historical`, `earlier`, `previous`, `no longer`, `rev 18.1 to rev 18.6` | +| LIFT | recorded | *the lift is approved in principle for 2.0*: `supersed (superseded, supersedes)`, `historical`, `earlier`, `previous`, `no longer`, `rev 18.1 to rev 18.6`
*the fixed mast is no longer the baseline; the lift is approved in principle*: `supersed (superseded, supersedes)`, `historical`, `earlier`, `previous`, `legacy`, `replace (replaced, replacement)`, `instead of`, `no longer`, `rev 18.1 to rev 18.6`
*the lift is not deferred to 3.0; it is approved in principle for 2.0*: `supersed (superseded, supersedes)`, `historical`, `earlier`, `previous`, `no longer`, `rev 18.1 to rev 18.6`
*the lift is the DOLD Hexalift V4 350 mm, BS-HM240G350530-MFF24*: `supersed (superseded, supersedes)`, `historical`, `earlier`, `previous`, `replac`, `legacy`, `rev ?18.[1-7]`
*the lift base plate has two fore-aft positions, centre and +50 mm*: `supersed (superseded, supersedes)`, `historical`, `earlier`, `previous`, `replac`, `no longer`, `rev ?18.[1-8]` | +| ARM-MOUNT | recorded | *the upstream OpenArm body is not used; attach openarm_{side}_base_link to the lift carriage*: `not used`, `removed`, `upstream`, `no OpenArm body`, `supersed (superseded, supersedes)`, `historical`
*the column axis is 330 mm behind the front edge, x +0.060 at bp000 and +0.110 at bp050, not on the drive axle*: `supersed (superseded, supersedes)`, `historical` | +| CONFIG-IDS | recorded | `supersed (superseded, supersedes)`, `replac`, `historical`, `legacy`, `no longer` | | NO-SUSPENSION | recorded | `3.0`, `no`, `not fitted`, `without` | | DRIVE-TRACK | open | not scanned until the decision is taken | diff --git a/decisions.yaml b/decisions.yaml index 8916650..d611d27 100644 --- a/decisions.yaml +++ b/decisions.yaml @@ -53,10 +53,13 @@ schema_version: 1 in_force: - source: P-03-rev18.7 - date: 2026-10-06 + source: P-03-rev19.0 + date: 2026-10-12 sources: + Alex decision 2026-10-12: + title: Platform decision of 12 October 2026 (sensor layout, base camera, IMU, column position, LiDAR mount, drive track); history, recorded in P-03 rev19.0 item 19 + evidence: decision record, not held in any repository; provenance only, CI never reads it P-03-rev18.2: title: P-03 Decision Addendum, revision 18.2, 28 September 2026 (earlier revision; superseded by revision 18.7 as the addendum in force) evidence: >- @@ -67,8 +70,17 @@ sources: P-03-rev18.4: title: P-03 Decision Addendum, revision 18.4 (earlier revision) evidence: plan-set document, not held in any repository; cited by item + P-03-rev19.0: + title: P-03 Decision Addendum, revision 19.0, 12 October 2026 (the addendum in force; item 19 records the 12 October decisions D1 to D6) + evidence: plan-set document, not held in any repository; cited by item + P-03-rev18.9: + title: P-03 Decision Addendum, revision 18.9, 9 October 2026 (earlier revision) + evidence: plan-set document, not held in any repository; cited by item + P-03-rev18.8: + title: P-03 Decision Addendum, revision 18.8, 8 October 2026 (earlier revision) + evidence: plan-set document, not held in any repository; cited by item P-03-rev18.7: - title: P-03 Decision Addendum, revision 18.7, 6 October 2026 (the addendum in force) + title: P-03 Decision Addendum, revision 18.7, 6 October 2026 (earlier revision) evidence: plan-set document, not held in any repository; cited by item P-03-rev18.6: title: P-03 Decision Addendum, revision 18.6 (earlier revision) @@ -85,8 +97,14 @@ sources: P-00-rev18.1: title: P-00 Master Coordination Plan, revision 18.1 evidence: plan-set document, not held in any repository; cited by text line + BOM-Issue-7.7: + title: OpenAMRobot 2.0 Detailed Hardware BOM, Issue 7.7, 12 October 2026 (canonical per P-03 rev19.0) + evidence: not held in any repository; provenance only, CI never reads it + BOM-Issue-7.6: + title: OpenAMRobot 2.0 Detailed Hardware BOM, Issue 7.6, 9 October 2026 (earlier issue; canonical per P-03 rev18.9) + evidence: not held in any repository; provenance only, CI never reads it BOM-Issue-7.3: - title: OpenAMRobot 2.0 Detailed Hardware BOM, Issue 7.3 (canonical per P-03 rev18.7) + title: OpenAMRobot 2.0 Detailed Hardware BOM, Issue 7.3 (earlier issue; canonical per P-03 rev18.7) evidence: not held in any repository; provenance only, CI never reads it BOM-Issue-7: title: OpenAMRobot 2.0 Detailed Hardware BOM, Issue 7, 27 September 2026 (earlier issue; canonical per P-03 rev18.2 item 7 until Issue 7.3) @@ -110,16 +128,18 @@ exclude: decisions: - id: BOM-ISSUE-IN-FORCE title: Canonical hardware BOM issue for OpenAMRobot 2.0 - summary: "BOM Issue 7.3 is the canonical OpenAMRobot 2.0 hardware BOM." - fix_hint: "Name Issue 7.3 as canonical, or label older issues (Issue 6, Issue 7, B-01) as superseded." + summary: "BOM Issue 7.7 is the canonical OpenAMRobot 2.0 hardware BOM." + fix_hint: "Name Issue 7.7 as canonical, or label older issues (Issue 6, Issue 7 to 7.6, B-01) as superseded or earlier." kind: value status: recorded - value: OpenAMRobot 2.0 Detailed Hardware BOM, Issue 7.3 + value: OpenAMRobot 2.0 Detailed Hardware BOM, Issue 7.7 unit: none - date: 2026-10-06 - review_by: 2026-11-17 - source: {document: P-03-rev18.7, item: BOM issue in force} + date: 2026-10-12 + review_by: 2026-11-23 + source: {document: P-03-rev19.0, item: "BOM issue in force (BOM Issue 7.7)"} supersedes: + - {value: Issue 7.6, source: "P-03-rev18.9 item 16 (BOM Issue 7.6 carries the change)"} + - {value: Issue 7.3, source: P-03-rev18.7 BOM issue in force} - {value: Issue 7, source: P-03-rev18.2 item 7} - value: Issue 6, or an explicitly approved successor source: P-03-rev18.1 line 7 @@ -129,15 +149,15 @@ decisions: check: - pattern: '(?P(?:canonical|in force|of record)[^\n]{0,40}\bIssue\s*6\b|\bIssue\s*6\b[^\n]{0,40}\b(?:canonical|in force|of record))' unless: 'supersed|replaced|previous|earlier' - message: BOM Issue 7.3 is the canonical hardware BOM (P-03 rev18.7) + message: BOM Issue 7.7 is the canonical hardware BOM (P-03 rev19.0) - pattern: '(?PB-01[^\n]{0,60}\b(?:canonical|current))' unless: 'supersed' message: B-01 is superseded - - pattern: '(?P(?:canonical|in force|of record)[^\n]{0,40}\bIssue\s*7(?!\.3)(?:\.\d+)?\b|\bIssue\s*7(?!\.3)(?:\.\d+)?\b[^\n]{0,40}\b(?:canonical|in force|of record))' + - pattern: '(?P(?:canonical|in force|of record)[^\n]{0,40}\bIssue\s*7(?!\.7)(?:\.\d+)?\b|\bIssue\s*7(?!\.7)(?:\.\d+)?\b[^\n]{0,40}\b(?:canonical|in force|of record))' unless: 'supersed|replaced|previous|earlier|historical' - message: BOM Issue 7.3 is the canonical hardware BOM (P-03 rev18.7) + message: BOM Issue 7.7 is the canonical hardware BOM (P-03 rev19.0) verification: - machine: Issue 6, Issue 7 (other than 7.3) or B-01 presented as the canonical BOM; citations of P-03 rev18.1 line 7 + machine: Issue 6, Issue 7 to 7.6 or B-01 presented as the canonical BOM; citations of P-03 rev18.1 line 7 human: {reviewer: platform-lead, evidence: the BOM file header and issue number in the released BOM} owner: platform-lead @@ -167,7 +187,7 @@ decisions: item: item 8 decision: LIFT citation: '(?P\bmast_1350\b[^\n]{0,60}\b(?:baseline|installation)|(?:shoulder[- ]axis|installation) height\s*(?:at|of|is|:)?\s*1350\s*mm)' - unless: 'supersed|legacy|historical|earlier|previous|rev ?18\.[1-6]\b' + unless: 'supersed|legacy|historical|earlier|previous|rev ?18\.[1-6]\b|\blift\b|L1350|extended|full stroke' verification: machine: text still presenting the superseded fixed-mast value as current (citation pattern) human: {reviewer: platform-lead, evidence: URDF/Xacro mast configuration and the general arrangement drawing at 1350 mm} @@ -204,7 +224,7 @@ decisions: - id: MAST-TOP-HEIGHT title: Mast top height above the floor (own COTS mast, one MISUMI HFS6-60120 profile; superseded by LIFT) summary: "Superseded: the 1500 mm mast top on an HFS6-60120 profile was replaced by LIFT." - fix_hint: "Describe the lift, or label the mast-top or HFS6-60120 text as superseded or historical." + fix_hint: "Describe the lift; HFS6-60120 is now the short arm profile on the lift (ARM-MOUNT), not a mast." kind: value status: superseded value: 1500 @@ -221,7 +241,7 @@ decisions: document: P-03-rev18.7 item: item 8 decision: LIFT - citation: '(?P\bmast top[^\n]{0,20}\b1500\s*mm|\bHFS6-60120\b)' + citation: '(?P\bmast top[^\n]{0,20}\b1500\s*mm|\bHFS6-60120\b[^\n]{0,60}\b(?:mast|centre bracket|center bracket)\b)' unless: 'supersed|legacy|historical|earlier|previous|rev ?18\.[1-6]\b' verification: machine: text still presenting the superseded fixed-mast value as current (citation pattern) @@ -275,7 +295,7 @@ decisions: - pattern: '(?P\bdeck top\b[^\n]{0,25}?\b(?!294\b)\d{3}\s*mm)' unless: 'supersed|historical|legacy|earlier|previous' message: the steel chassis deck top is 294 mm above the floor (P-03 rev18.7 item 15) - - pattern: '(?P\bbase[- ]plate top(?: face)?\b[^\n]{0,25}?\b(?!304\b)\d{3}\s*mm)' + - pattern: '(?P\bbase[- ]plate top(?: face)?\b\s*(?:is\s*|at\s*|of\s*|=\s*|:\s*)?(?:z\s*=?\s*)?(?!304\b)\d{3}\s*mm)' unless: 'supersed|historical|legacy|earlier|previous' message: the lift base-plate top face is 304 mm above the floor, the reference for lift and shoulder heights (P-03 rev18.7 item 15) verification: @@ -293,10 +313,11 @@ decisions: - base_footprint on the floor under the drive-axle midpoint - base_link at the drive-axle midpoint and axle height; x forward, z up - imu_link on the centreline, away from motor magnetic fields + - imu_link (ICM-42688-P) on the centreline at x 0.195 m from base_link, halfway between the drive axle and the front panel, on the base plate (top z -0.044) plus the board stack; axes aligned with base_link unit: none - date: 2026-10-06 - review_by: 2026-11-17 - source: {document: P-03-rev18.7, item: item 15} + date: 2026-10-12 + review_by: 2026-11-23 + source: {document: P-03-rev19.0, item: "item 19 (imu_link position)"} applies_to: {repositories: ["*"], files: ["**/*.md", "**/*.yaml", "**/*.yml", "**/*.html", "**/*.xacro", "**/*.urdf", "**/*.launch.py"]} check: - pattern: '(?P\bbase_link\b[^\n]{0,30}\b(?:on|at) the floor\b)' @@ -313,6 +334,31 @@ decisions: human: {reviewer: software-lead, evidence: URDF frame tree and real TF on the robot matching REP 105} owner: platform-lead + - id: NEAR-FIELD-FRAMES + title: Near-field ultrasonic and ToF sensor frames on the base panels + summary: "Four MB7060 frames us_* at x +/-0.390, y +/-0.130; two TF-Luna frames tof_* at x +/-0.390 on the centreline." + fix_hint: "Use the listed frame origins; the ToF pitch of 20 degrees is a screening value until the bench test." + kind: value + status: recorded + values: + - us_front_left (0.390, +0.130, -0.0066), us_front_right (0.390, -0.130, -0.0066), us_rear_left (-0.390, +0.130, -0.0066, yaw pi), us_rear_right (-0.390, -0.130, -0.0066, yaw pi) from base_link + - "ultrasonic mounting: MB7060 holes 27.5 mm on the existing centres, sensor centred, 3/4 inch NPS lock nut, tilt 0 until the bench test" + - tof_front (0.390, 0, -0.0066) in the existing 22.0 mm front centre hole; tof_rear (-0.390, 0, -0.0066, yaw pi) in a new 22.0 mm rear centre hole + - both ToF sensors pitched down so the beam meets the floor beyond 0.2 m (20 degree screening value until the bench test) + unit: m + date: 2026-10-12 + review_by: 2026-11-23 + source: {document: P-03-rev19.0, item: "item 19 (near-field sensor frames)"} + applies_to: {repositories: ["openamr-platform-*", "openamrobot-docs"], files: ["**/*.md", "**/*.yaml", "**/*.yml", "**/*.html", "**/*.xacro", "**/*.urdf"]} + check: + - pattern: '(?P\b(?:tof_(?:front|rear)|TF-Luna)\b[^\n]{0,60}?\b20\s*(?:°|deg(?:rees?)?)[^\n]{0,40}?\b(?:final|fixed|validated|confirmed)\b)' + unless: 'screening|bench|until' + message: the 20 degree ToF pitch is a screening value until the bench test (P-03 rev19.0 item 19) + verification: + machine: the 20 degree ToF screening pitch presented as final, fixed, validated or confirmed + human: {reviewer: platform-lead, evidence: Rev B panel drawing and URDF joint origins} + owner: platform-lead + - id: BATTERY-PLACEMENT title: Battery pack and placement summary: "One 8S1P LF105 pack, 25.6 V, 105 Ah, as close to the rear edge as practical." @@ -417,32 +463,32 @@ decisions: owner: platform-lead - id: BASE-CONTROLLER-GATES - title: Base-controller gates and IMU gating stay distinct - summary: "Gate A (Teensy, MPU6500) and Gate B (STM32H723ZG) stay distinct; ICM-42688-P is gated." - fix_hint: "Call the Teensy the Gate A controller, the IMU MPU6500, and the ICM-42688-P conditional (Gate B)." + title: Base-controller gates and the 2.0 IMU + summary: "Gate A (Teensy, MPU6500) and Gate B (STM32H723ZG) stay distinct; the ICM-42688-P is the 2.0 IMU." + fix_hint: "Call the Teensy and MPU6500 Gate A (legacy); the 2.0 IMU is the ICM-42688-P (MIKROE-4237, SPI)." kind: distinction status: recorded values: - Gate A, Jetson with the existing Teensy, ZBLD/PWM drivetrain and MPU6500 (legacy test configuration) - Gate B, Jetson with the STM32H723ZG (NUCLEO-H723ZG bench board) and the ZLTECH drivers - - ICM-42688-P enters the manufacturing BOM only after side-by-side robot evidence; adoption decision 20 November 2026 + - the ICM-42688-P (MIKROE-4237, SPI) is the OpenAMRobot 2.0 IMU, WHO_AM_I 0x47 at boot; the MPU6500 stays the Gate A (legacy) IMU - STM32 go/no-go 6 November 2026; fallback is the validated legacy Teensy/PWM build behind I8 unit: none - date: null - review_by: 2026-11-18 # six weeks after this register update (2026-10-07) - source: {document: P-00-rev18.1, item: "txt 63, 101, 106, 344; I8-WP adoption gate; Gate B board per P-03-rev18.5 item 14"} + date: 2026-10-12 + review_by: 2026-11-23 + source: {document: P-03-rev19.0, item: "item 19 (base-controller IMU)"} + supersedes: + - {value: "ICM-42688-P enters the manufacturing BOM only after side-by-side robot evidence; adoption decision 20 November 2026", source: "P-00-rev18.1 txt 63, 101, 106, 344; I8-WP adoption gate"} applies_to: {repositories: ["*"], files: ["**/*.md", "**/*.yaml", "**/*.yml", "**/*.html"]} check: - pattern: '(?PTeensy[^\n]{0,20}\bbench target)' message: Teensy is the Gate A controller and the release fallback, not a bench target - - pattern: '(?PICM-42688-P[^\n]{0,40}\b(?:selected|baseline|chosen)\b)' - unless: 'Gate B|conditional|20 Nov|candidate|pending|not yet|after' - message: ICM-42688-P is gated; MPU6500 remains the Gate A IMU - pattern: '\b(?PMPU6050)\b' + unless: 'would return|labeled|labelled|assumed|not a real|instead of|USE_MPU6050|driver' message: the Gate A IMU is the MPU6500 verification: - machine: Teensy called a bench target, ICM-42688-P called selected without its gate, MPU6050 named as the IMU - human: {reviewer: platform-lead, evidence: gate records (Gate A test log, STM32 go/no-go record, IMU side-by-side data)} + machine: Teensy called a bench target, MPU6050 named as the IMU + human: {reviewer: platform-lead, evidence: "Gate A test log, STM32 go/no-go record, ICM-42688-P WHO_AM_I 0x47 boot log"} owner: platform-lead - id: BASE-CONTROLLER-IO @@ -453,18 +499,20 @@ decisions: status: recorded values: - Base controller STM32H723ZG on NUCLEO-H723ZG - - TF-Luna on UART, one per UART - - two MaxBotix MB7060 serial sensors, each on one dedicated STM32 UART, 9600 8N1; no sensor I2C off the controller board + - four MaxBotix MB7060 XL-MaxSonar-WR (-2XX 3/4 inch NPS housing, RS232 output) in the front and back panel left and right edge holes, each on one dedicated STM32 UART at 9600 8N1 with receive inversion and one trigger GPIO + - two Benewake TF-Luna ToF cliff sensors in the front and back panel centre holes, one UART each, pin 5 tied to 3.3 V - IMU on a dedicated SPI, Mode 0 - CAN1 traction only, CAN2 BMS, CAN3 reserved for upper-body auxiliary actuators (CANopen, no safety function) - MCU to Jetson over Ethernet, micro-ROS over UDP; USB for the bench only unit: none - date: 2026-10-06 - review_by: 2026-11-17 - source: {document: P-03-rev18.7, item: item 14} + date: 2026-10-12 + review_by: 2026-11-23 + source: {document: P-03-rev19.0, item: "item 19 (base-controller sensor I/O)"} supersedes: - {value: STM32H743 on NUCLEO-H743ZI2, source: P-00-rev18.1 (Gate B bench board)} - {value: MB7040 one per I2C bus, source: P-03-rev18.5 item 14} + - {value: "TF-Luna on UART, one per UART", source: P-03-rev18.7 item 14} + - {value: "two MaxBotix MB7060 serial sensors, each on one dedicated STM32 UART, 9600 8N1; no sensor I2C off the controller board", source: P-03-rev18.7 item 14} applies_to: {repositories: ["*"], files: ["**/*.md", "**/*.yaml", "**/*.yml", "**/*.html"]} check: - pattern: '(?PNUCLEO-H743ZI2|STM32H743)' @@ -472,12 +520,15 @@ decisions: message: the base controller is the STM32H723ZG on the NUCLEO-H723ZG; label STM32H743 / NUCLEO-H743ZI2 material as superseded - pattern: '(?P\bMB7040\b)' unless: 'supersed|legacy|historical|replaced' - message: the ultrasonic sensors are two MaxBotix MB7060 on dedicated STM32 UARTs at 9600 8N1; no sensor I2C (P-03 rev18.7 item 14) + message: the ultrasonic sensors are four MaxBotix MB7060 on dedicated STM32 UARTs at 9600 8N1; no sensor I2C (P-03 rev19.0 item 19) - pattern: '(?P\bmicro-?ROS\b[^\n]{0,30}\bover (?:USB|serial)\b)' unless: 'bench|legacy|Gate A|Teensy|supersed|historical' message: micro-ROS runs over UDP on Ethernet between MCU and Jetson; USB is for the bench only (P-03 rev18.7 item 14) + - pattern: '(?P\btwo MaxBotix MB7060\b|\b2\s*x\s*MB7060\b|\bfour TF-Luna\b|\b4\s*x\s*TF-Luna\b)' + unless: 'supersed|legacy|historical' + message: the base has four MaxBotix MB7060 (edge holes) and two TF-Luna ToF cliff sensors (centre holes) (P-03 rev19.0 item 19) verification: - machine: NUCLEO-H743ZI2 or STM32H743 without a superseded, legacy, historical or replaced label; MB7040 without such a label; micro-ROS over USB or serial outside the bench or Gate A + machine: NUCLEO-H743ZI2 or STM32H743 without a superseded, legacy, historical or replaced label; MB7040 without such a label; micro-ROS over USB or serial outside the bench or Gate A; two MB7060 or four TF-Luna as the current count human: {reviewer: platform-lead, evidence: P-03 rev18.7 item 14 and the MCU I/O allocation in openamr-platform-hw} owner: platform-lead @@ -511,20 +562,21 @@ decisions: - id: CAMERAS title: Cameras - summary: "Base camera Orbbec Gemini 336L, about 243 mm up, tilted 5, 10 or 15 degrees up (baseline 10)." + summary: "Base camera Orbbec Gemini 336L, 142.5 mm above the floor, tilted 5, 10 or 15 degrees up (baseline 10)." fix_hint: "Name the Gemini 336L with an up-tilt of 5, 10 or 15 degrees, or label other cameras as legacy." kind: value status: recorded values: - - base camera Orbbec Gemini 336L, fixed to base_link on the front face about 243 mm above the floor; up-tilt positions 5, 10 and 15 degrees, baseline 10 degrees + - base camera Orbbec Gemini 336L, housing centre on the old camera centre, 142.5 mm above the floor, base_camera_link (0.376, 0, 0.0445) from base_link; front-panel opening about 126 x 36 mm on that centre; up-tilt 5, 10 or 15 degrees, baseline 10 - head camera Stereolabs ZED Mini (SKU ZED-121210) on the lift carriage, see HEAD-CAMERA-IDENTITY - two in-hand RGB wrist cameras; no separate torso scene camera unit: none - date: 2026-10-06 - review_by: 2026-11-17 - source: {document: P-03-rev18.7, item: "item 15 (wrist cameras as in P-00-rev18.1 txt 85 and 97)"} + date: 2026-10-12 + review_by: 2026-11-23 + source: {document: P-03-rev19.0, item: "item 19 (base camera position)"} supersedes: - {value: "base camera tilted about 10 degrees upward; head camera identity open", source: P-00-rev18.1 txt 85 and 97} + - {value: "base camera Orbbec Gemini 336L, fixed to base_link on the front face about 243 mm above the floor; up-tilt positions 5, 10 and 15 degrees, baseline 10 degrees", source: P-03-rev18.7 item 15} applies_to: repositories: ["openamr-*", "openamrobot-docs", "openamrobot-manipulation", "openamrobot-ui"] files: ["**/*.md", "**/*.yaml", "**/*.yml", "**/*.html", "**/*.launch.py", "**/*.xacro", "**/*.urdf"] @@ -540,8 +592,11 @@ decisions: - pattern: '(?PGemini 336L[^\n]{0,60}?\b(?!(?:5|10|15)\b)\d{1,2}\s*(?:°|deg(?:rees?)?)\s*(?:up|upward)\b)' unless: 'supersed|historical|legacy' message: the Gemini 336L up-tilt positions are 5, 10 and 15 degrees, baseline 10 (P-03 rev18.7 item 15) + - pattern: '(?P(?:Gemini|base camera)[^\n]{0,60}?\b243\s*mm|\b243\s*mm[^\n]{0,60}?(?:Gemini|base camera))' + unless: 'supersed|historical' + message: the Gemini 336L housing centre is 142.5 mm above the floor, base_camera_link (0.376, 0, 0.0445) (P-03 rev19.0 item 19) verification: - machine: other camera models without a legacy label; a down-tilted base camera; a Gemini 336L up-tilt other than 5, 10 or 15 degrees + machine: other camera models without a legacy label; a down-tilted base camera; a Gemini 336L up-tilt other than 5, 10 or 15 degrees; the base camera at 243 mm human: {reviewer: software-lead, evidence: camera joint rpy in URDF and real TF showing the upward tilt} owner: platform-lead @@ -553,8 +608,9 @@ decisions: status: recorded values: - Stereolabs ZED Mini, SKU ZED-121210, supplied with the OpenArm 2.0 set - - mounted on the lift carriage - - pitch 15 to 35 degrees down in 5 degree steps, baseline 25 degrees + - mounted on the lift carriage, held at its ends by the mount supplied with the OpenArm set, on a pitch bracket on the arm-profile top + - lens 0.022 m ahead of and 0.223 m above the arm mount point, centred; 1223 mm at L1000 and 1573 mm at L1350 + - pitch 15 to 35 degrees down in 5 degree steps about the lens line, baseline 25 degrees unit: none date: 2026-10-06 review_by: 2026-11-17 @@ -594,7 +650,7 @@ decisions: unless: '\bno 12|not|never|legacy' message: there is no 12 V rail in 2.0 - pattern: '(?P24\s*V?\s*(?:->|→|to)\s*5\s*V?\s*/\s*12\s*V)' - unless: 'legacy' + unless: 'legacy|Gate A' message: there is no 12 V rail in 2.0 verification: machine: a 12 V rail or a 24 V to 5/12 V converter in text @@ -735,18 +791,21 @@ decisions: fix_hint: "Name the RPLIDAR S3; label Hokuyo as dropped or superseded and the A1 as legacy (existing robot)." kind: value status: recorded - value: SLAMTEC RPLIDAR S3 (S3M1-R2), connected over USB, powered from the regulated 5 V rail (functional sensing, not a safety device) + values: + - SLAMTEC RPLIDAR S3 (S3M1-R2), connected over USB, powered from the regulated 5 V rail (functional sensing, not a safety device) + - mounted on the existing MMP.07 bracket and 10 mm standoffs with a 7.1 mm spacer plate; scan plane 222.0 mm above the floor; lidar_link (0.330, 0, 0.124) from base_link, yaw pi + - "body filter: openamrobot_perception scan_body_filter with scan_body_filter_real.yaml from v0.0.1, unchanged (side posts at 82.9 to 89.5 degrees in the LiDAR frame lie inside its close-mask sectors)" unit: none backup: RPLIDAR S2E, only if the S3 is unavailable - date: 2026-10-03 - review_by: 2026-11-14 - source: {document: P-03-rev18.4, item: item 13} + date: 2026-10-12 + review_by: 2026-11-23 + source: {document: P-03-rev19.0, item: "item 19 (navigation LiDAR mount)"} supersedes: - {value: Hokuyo UST-10LX, source: P-03-rev18.3 item 11 (dropped on cost)} - {value: RPLIDAR A1, source: existing robot (Gate A)} applies_to: repositories: ["openamr-platform-*", "openamrobot-docs", "openamrobot-release"] - files: ["**/*.md", "**/*.yaml", "**/*.yml", "**/*.launch.py", "**/package.xml", "**/*.html"] + files: ["**/*.md", "**/*.yaml", "**/*.yml", "**/*.launch.py", "**/package.xml", "**/*.html", "**/*.xacro", "**/*.urdf"] check: - pattern: '(?P\bHokuyo\b|\bUST-10LX\b)' unless: 'supersed|dropped|legacy|historical' @@ -754,8 +813,11 @@ decisions: - pattern: '(?P\bRPLIDAR A1(?:M8)?\b|\bA1M8\b)' unless: 'legacy|Gate A|existing robot|historical|replaced' message: the 2.0 navigation LiDAR is the RPLIDAR S3 (S3M1-R2); label RPLIDAR A1 material as legacy (Gate A) + - pattern: '(?P\b0\.335\b[^\n]{0,40}?\b0\.18)' + unless: 'legacy|Gate A|supersed|historical' + message: lidar_link is (0.330, 0, 0.124) from base_link, yaw pi, with the 7.1 mm spacer plate (P-03 rev19.0 item 19) verification: - machine: Hokuyo or UST-10LX without a superseded or legacy label; RPLIDAR A1 or A1M8 without a legacy label + machine: Hokuyo or UST-10LX without a superseded or legacy label; RPLIDAR A1 or A1M8 without a legacy label; a lidar_link pose of 0.335 followed by 0.18 without a legacy label human: {reviewer: software-lead, evidence: bring-up launch and scan topic from the sllidar_ros2 driver with the RPLIDAR S3} owner: software-lead @@ -792,38 +854,109 @@ decisions: - id: LIFT title: Lift approved in principle for OpenAMRobot 2.0 - summary: "The lift is approved in principle for 2.0; shoulder axis 1000 to 1350 mm; release gates open." - fix_hint: "Describe the lift as approved in principle, or label fixed-mast and 3.0 lift text as superseded." + summary: "Lift approved in principle: DOLD Hexalift V4 350 mm, shoulder 1000 to 1350 mm, base plate centre or +50 mm." + fix_hint: "Describe the DOLD V4 lift on a two-position base plate; label V1, five positions and fixed-mast text as superseded." kind: configuration status: recorded values: - lift approved in principle - - DOLD Hexalift V1 350 mm primary; TiMOTION TL3 400 mm fallback - - shoulder axis 1000 to 1350 mm - - base plate fore-aft positions centre, +50, +100, +150 and +200 mm + - DOLD Hexalift V4 350 mm (800 N push, 18 mm/s, order code BS-HM240G350530-MFF24) primary; TiMOTION TL3 400 mm fallback + - column 530 mm retracted, 880 mm extended, mounted with its 240 mm side fore-aft + - shoulder 1000 to 1350 mm (304 + 530 or 880 + 166 mm), see ARM-MOUNT + - lift base plate fore-aft positions centre and +50 mm (bp000, bp050) - lift motion only in the stowed or carry safe pose with the base stopped - hold-and-move limits 0.05 m/s (drawer reversal) and 0.3 m/s (carrying) - - "release gates: holding on E-stop and power loss, supplier CAD, base-plate geometry and the CAN3 lift interface (items 6, 8, 14, 15)" + - "release gates: written DOLD holding on E-stop and power loss, supplier CAD, weighed mass, the CAN3 lift interface and the F2S rerun" unit: none - date: 2026-10-06 - review_by: 2026-11-17 - source: {document: P-03-rev18.7, item: "item 8; release gates items 6, 8, 14, 15"} + date: 2026-10-09 + review_by: 2026-11-20 + source: {document: P-03-rev18.9, item: "items 16 and 18; motion rules item 15; release gates items 6, 8, 14, 15, 16"} supersedes: - {value: "Lift removed from OpenAMRobot 2.0; fixed mast; lift on the 3.0 roadmap (former entry LIFT-REMOVED)", source: P-00-rev18.1 txt 18} + - {value: "DOLD Hexalift V1 350 mm primary", source: P-03-rev18.7 item 15} + - {value: "base plate positions centre, +50, +100, +150 and +200 mm", source: P-03-rev18.7 item 15} applies_to: {repositories: ["*"], files: ["**/*.md", "**/*.yaml", "**/*.yml", "**/*.html", "**/package.xml", "**/*.xacro", "**/*.urdf"]} check: - pattern: '(?P\bno (?:linear |actuated )?lift\b(?=\s*(?:[.,;:)]|$|(?:in|for|on)\b)))' unless: 'supersed|historical|earlier|previous|no longer|rev ?18\.[1-6]\b' - message: the lift is approved in principle for 2.0 (P-03 rev18.7 item 8) + message: the lift is approved in principle for 2.0 (P-03 rev18.9) - pattern: '(?P\bfixed[- ]mast\b)' unless: 'supersed|historical|earlier|previous|legacy|replace|instead of|no longer|rev ?18\.[1-6]\b' - message: the fixed mast is no longer the baseline; the lift is approved in principle (P-03 rev18.7 item 8) + message: the fixed mast is no longer the baseline; the lift is approved in principle (P-03 rev18.9) - pattern: '(?P\blift\b[^\n]{0,40}\b(?:deferred|moved|postponed)\b[^\n]{0,25}\b3\.0\b|\blift\b[^\n]{0,15}\bin (?:OpenAMRobot )?3\.0\b|\blift (?:is |was )?removed\b|\blift\b[^\n]{0,40}\b(?:OpenAMRobot )?3\.0 scope\b|\b3\.0 lift\b)' unless: 'supersed|historical|earlier|previous|no longer|rev ?18\.[1-6]\b' - message: the lift is not deferred to 3.0; it is approved in principle for 2.0 (P-03 rev18.7 item 8) + message: the lift is not deferred to 3.0; it is approved in principle for 2.0 (P-03 rev18.9) + - pattern: '(?P\bHexalift V1\b|\bBS-HD240D350530\b|\bdold_v1_350\b)' + unless: 'supersed|historical|earlier|previous|replac|legacy|rev ?18\.[1-7]\b' + message: the lift is the DOLD Hexalift V4 350 mm, BS-HM240G350530-MFF24 (P-03 rev18.9 item 16) + - pattern: '(?P\bbp(?:100|150|200)\b|\bfive[- ](?:position|fore-aft|base[- ]plate)\b|\+100, \+150 and \+200)' + unless: 'supersed|historical|earlier|previous|replac|no longer|rev ?18\.[1-8]\b' + message: the lift base plate has two fore-aft positions, centre and +50 mm (P-03 rev18.9 item 18) + verification: + machine: text saying 2.0 has no lift, presenting a fixed mast as current, deferring the lift to 3.0, naming Hexalift V1 as current, or base-plate positions beyond +50 mm + human: {reviewer: platform-lead, evidence: "P-03 rev18.9 items 16 and 18, the option B drawing set and the release-gate records: DOLD holding on E-stop and power loss, supplier CAD, weighed mass, CAN3 lift interface, F2S rerun"} + owner: platform-lead + + - id: ARM-MOUNT + title: Shoulder datum and arm mount on the lift (option B) + summary: "Shoulder = height of openarm_{side}_base_link; arm mount 180 mm ahead of the column axis, y +/-31 mm." + fix_hint: "Attach the arm base links to the lift carriage as listed; the upstream openarm_body_link0 is not used." + kind: configuration + status: recorded + values: + - shoulder height is the height above the floor of the OpenArm arm mount point, frame openarm_{side}_base_link (J1_A interface); joint1 and joint2 have no vertical offset from it + - the upstream OpenArm body (openarm_body_link0, arm mounts at z 0.698 m) is not part of OpenAMRobot; the arm base links attach to the lift carriage + - arm mount points at y +/-0.031 m, roll, pitch and yaw 0, one 1 mm spacer under each J1_A plate; shoulder spacing 307 mm + - arm mount point 0.180 m ahead of the lift column axis and 0.166 m above the column top plate + - arm profile MISUMI HFS6-60120 (60 mm lateral, 120 mm fore-aft), 340 mm, end-tapped, standing on a 10 mm adapter plate on the column top + - column axis 330 mm behind the chassis front edge, x +0.060 at bp000 and x +0.110 at bp050 from base_link; chassis 780 x 582 mm; arm mount 150 mm behind the front edge (option B drawing sheet 2 rev A) + - calibrated lift stops L1000, L1175 and L1350 (shoulder height in mm); the lift height is joint state + unit: m + date: 2026-10-12 + review_by: 2026-11-23 + source: {document: P-03-rev19.0, item: "item 19 (lift column position)"} + supersedes: + - {value: "fore-aft offset of the arm mount from the column axis 0 until CAD", source: P-03-rev18.8 item 17} + - {value: "column axis at bp000 on the drive axle (x 0 from base_link), 330 mm behind the chassis front edge; bp050 is +0.050 m", source: P-03-rev18.9 items 17 and 18} + applies_to: {repositories: ["openamr-*", "openamrobot-*"], files: ["**/*.md", "**/*.yaml", "**/*.yml", "**/*.html", "**/*.xacro", "**/*.urdf"]} + check: + - pattern: '(?P(?:parent|attach\w*|mount\w*)[^\n]{0,40}\bopenarm_body_link0\b)' + unless: 'not used|removed|upstream|no OpenArm body|supersed|historical' + message: the upstream OpenArm body is not used; attach openarm_{side}_base_link to the lift carriage (P-03 rev18.9 item 17) + - pattern: '(?P\bcolumn axis\b[^\n]{0,40}?\bdrive axle\b|\bdrive axle\b[^\n]{0,40}?\bcolumn axis\b)' + unless: 'supersed|historical' + message: the column axis is 330 mm behind the front edge, x +0.060 at bp000 and +0.110 at bp050, not on the drive axle (P-03 rev19.0 item 19) verification: - machine: text saying 2.0 has no lift, presenting a fixed mast as the current baseline, or deferring the lift to 3.0 - human: {reviewer: platform-lead, evidence: "P-03 rev18.7 item 8 and the release-gate records: holding on E-stop and power loss, supplier CAD, base-plate geometry and the CAN3 lift interface"} + machine: text or a model that attaches the arms to the upstream openarm_body_link0; the column axis placed on the drive axle + human: {reviewer: software-lead, evidence: "URDF frame tree: openarm_{side}_base_link under the lift carriage at x +0.180, y +/-0.031; shoulder z = 1.000 + lift q"} + owner: platform-lead + + - id: CONFIG-IDS + title: Robot configuration identity + summary: "Configuration IDs: column, base_plate (bp000, bp050), head_pitch (hp15 to hp35), base_tilt; mast_id is gone." + fix_hint: "Use column, base_plate, head_pitch and base_tilt IDs; the lift height is joint state, not a configuration ID." + kind: configuration + status: recorded + values: + - column dold_v4_350 or tl3_400 + - base_plate bp000 or bp050 + - head_pitch hp15, hp20, hp25, hp30, hp35 (baseline hp25) + - base_tilt bt05, bt10, bt15 (baseline bt10) + - lift stops L1000, L1175, L1350 are calibration IDs; the lift height is joint state + unit: none + date: 2026-10-09 + review_by: 2026-11-20 + source: {document: P-03-rev18.9, item: "items 17 and 18"} + supersedes: + - {value: "mast_id (mast_1300 to mast_1450)", source: P-03-rev18.2 shoulder height} + applies_to: {repositories: ["openamr-*", "openamrobot-*"], files: ["**/*.md", "**/*.yaml", "**/*.yml", "**/*.xacro", "**/*.urdf", "**/*.launch.py", "**/*.py"]} + check: + - pattern: '(?P\bmast_id\b)' + unless: 'supersed|replac|historical|legacy|no longer' + message: mast_id is replaced by the column, base_plate, head_pitch and base_tilt IDs (P-03 rev18.9 item 17) + verification: + machine: mast_id used as a current configuration ID + human: {reviewer: software-lead, evidence: configuration hash inputs and dataset metadata carrying the four IDs} owner: platform-lead - id: NO-SUSPENSION @@ -849,15 +982,15 @@ decisions: - id: DRIVE-TRACK title: Drive track - summary: "Open: 400 mm in the general arrangement; the final drive track is still an open input." - fix_hint: "Not scanned while open; give the track as 400 mm (general arrangement) until the value is decided." + summary: "Open: the 2.0 wheel assembly will change the track; placeholder 0.400 m, Gate A unit measured 0.46 m." + fix_hint: "Not scanned while open; call the track open and give 0.400 m only as the model placeholder." kind: value status: open - value: 400 mm in the general arrangement; the final track is an open input - unit: mm - date: null - review_by: 2026-11-18 # six weeks after this register update (2026-10-07) - source: {document: P-00-rev18.1, item: open inputs} + value: "open; the 2.0 wheel assembly will change the dimensions. Model placeholder 0.400 m (2023 STEP and general arrangement); Gate A unit measured 0.46 m (19 June 2026)" + unit: m + date: 2026-10-12 + review_by: 2026-11-23 + source: {document: "Alex decision 2026-10-12", item: "drive track (stays open)"} applies_to: {repositories: ["openamr-platform-*", "openamrobot-ui"], files: ["**/*.xacro", "**/*.urdf", "**/*.yaml", "**/*.sdf"]} check: - pattern: '(?P0\.4075)' diff --git a/profile/README.md b/profile/README.md index d87db8a..289f1ca 100644 --- a/profile/README.md +++ b/profile/README.md @@ -15,7 +15,7 @@ OpenAMRobot combines: - autonomous mobile robotics - dual-arm manipulation -- a lift for the arms, approved in principle for OpenAMRobot 2.0 (release gates still open) +- a lift for the arms, approved in principle for OpenAMRobot 2.0 (release gates still open): DOLD Hexalift V4 350 mm, shoulder 1000 to 1350 mm, lift base plate centre or +50 mm, arm profile 180 mm ahead of the column axis - AI-based perception - wearable embodied AI data collection - ROS 2 software infrastructure diff --git a/tests/test_check_decisions.py b/tests/test_check_decisions.py index e5ab32e..083a02f 100644 --- a/tests/test_check_decisions.py +++ b/tests/test_check_decisions.py @@ -383,12 +383,14 @@ def test_estop_recommendation(self): def test_bom_issue_in_force(self): self.assertEqual(self.ids("docs/a.md", "The canonical BOM is Issue 6.\n", "x"), ["BOM-ISSUE-IN-FORCE"]) self.assertEqual(self.ids("docs/a.md", "BOM per P-03 rev18.1 line 7.\n", "x"), ["BOM-ISSUE-IN-FORCE"]) - self.assertEqual(self.ids("docs/a.md", "Issue 7.3 is canonical; Issue 6 is superseded.\n", "x"), []) + self.assertEqual(self.ids("docs/a.md", "Issue 7.6 is canonical; Issue 6 is superseded.\n", "x"), []) - def test_bom_issue_7_3_in_force(self): - for text in ("The canonical BOM is Issue 7.\n", "BOM Issue 7.2 is the BOM of record.\n"): + def test_bom_issue_7_7_in_force(self): + for text in ("The canonical BOM is Issue 7.\n", "BOM Issue 7.2 is the BOM of record.\n", + "BOM Issue 7.3 is canonical.\n", "BOM Issue 7.6 is canonical.\n"): self.assertEqual(self.ids("docs/a.md", text, "x"), ["BOM-ISSUE-IN-FORCE"], text) - for text in ("BOM Issue 7.3 is canonical.\n", "Issue 7 was canonical until Issue 7.3 superseded it.\n"): + for text in ("BOM Issue 7.7 is canonical.\n", "Issue 7.6 was canonical until Issue 7.7 superseded it.\n", + "The earlier canonical BOM was Issue 7.6.\n"): self.assertEqual(self.ids("docs/a.md", text, "x"), [], text) def test_nav_lidar(self): @@ -422,13 +424,39 @@ def test_lift_approved_in_principle(self): "The linear lift is deferred to OpenAMRobot 3.0.\n", "Fixed mast (lift in 3.0), mounting plates.\n"): self.assertEqual(self.ids("docs/a.md", text, "x"), ["LIFT"], text) - for text in ("Lift approved in principle: DOLD Hexalift V1 350 mm primary, TiMOTION TL3 400 mm fallback.\n", + for text in ("Lift approved in principle: DOLD Hexalift V4 350 mm primary, TiMOTION TL3 400 mm fallback.\n", + "The Hexalift V1 was replaced by the V4 (P-03 rev18.8 item 16).\n", + "Base plate positions centre and +50 mm (bp000, bp050).\n", "Lift motion only in the stowed or carry safe pose with the base stopped.\n", "No lift motion while the base moves.\n", "The fixed mast is superseded by the lift (P-03 rev18.7 item 8).\n", "The lift column moves the shoulder axis from 1000 to 1350 mm.\n"): self.assertEqual(self.ids("docs/a.md", text, "x"), [], text) + def test_lift_v4_and_two_base_plate_positions(self): + for text in ("Lift: DOLD Hexalift V1 350 mm primary.\n", + "Column ID dold_v1_350.\n", + "Base plate: five fore-aft positions, centre to +200 mm.\n", + "Configurations bp000 to bp200, including bp150.\n", + "Positions centre, +50, +100, +150 and +200 mm.\n"): + self.assertEqual(self.ids("docs/a.md", text, "x"), ["LIFT"], text) + + def test_arm_mount_and_config_ids(self): + repo = "openamr-upperbody-sw" + self.assertEqual(self.ids("docs/a.md", "Attach the arm base links to openarm_body_link0.\n", repo), + ["ARM-MOUNT"]) + self.assertEqual(self.ids("docs/a.md", "The upstream openarm_body_link0 is not used.\n", repo), []) + self.assertEqual(self.ids("docs/a.md", "Select the robot with mast_id.\n", repo), ["CONFIG-IDS"]) + self.assertEqual(self.ids("docs/a.md", "mast_id is replaced by column and base_plate.\n", repo), []) + + def test_hfs6_arm_profile_is_current(self): + for text in ("Arm profile MISUMI HFS6-60120, 340 mm, on the lift adapter plate.\n", + "Base-plate top face, arm mount point 180 mm ahead of the column axis.\n", + "Shoulder-axis height 1350 mm at L1350 on the lift.\n"): + self.assertEqual(self.ids("docs/a.md", text, "x"), [], text) + self.assertEqual(self.ids("docs/a.md", "One HFS6-60120 profile bolted to the centre bracket as the mast.\n", "x"), + ["MAST-TOP-HEIGHT"]) + def test_datum_height_stack(self): for text in ("The steel chassis deck top is at 300 mm.\n", "Base-plate top face 310 mm above the floor.\n"): self.assertEqual(self.ids("docs/a.md", text, "x"), ["DATUM-HEIGHT-STACK"], text) @@ -455,7 +483,7 @@ def test_battery_placement_rear_edge(self): def test_base_controller_io_rev18_7(self): for text in ("Two MB7040 sensors, one per I2C bus.\n", "micro-ROS over USB to the Jetson.\n"): self.assertEqual(self.ids("docs/a.md", text, "x"), ["BASE-CONTROLLER-IO"], text) - for text in ("Two MaxBotix MB7060 sensors, each on a dedicated STM32 UART at 9600 8N1.\n", + for text in ("Four MaxBotix MB7060 sensors, each on a dedicated STM32 UART at 9600 8N1.\n", "MCU to Jetson over Ethernet, micro-ROS over UDP; micro-ROS over USB on the bench only.\n", "MB7040 on I2C is superseded.\n"): self.assertEqual(self.ids("docs/a.md", text, "x"), [], text) @@ -466,9 +494,80 @@ def test_head_camera_recorded_and_base_camera_tilt(self): self.assertEqual(self.ids("docs/a.md", "The Gemini 336L is tilted 20 degrees up.\n", "openamrobot-docs"), ["CAMERAS"]) for text in ("Stereolabs ZED Mini (SKU ZED-121210) on the lift carriage, pitch 25 degrees down.\n", - "Gemini 336L about 243 mm above the floor, tilted 10 degrees up (positions 5, 10, 15).\n"): + "Gemini 336L 142.5 mm above the floor, tilted 10 degrees up (positions 5, 10, 15).\n"): self.assertEqual(self.ids("docs/a.md", text, "openamrobot-docs"), [], text) + def test_sensor_layout_alex_2026_10_12(self): + for text in ("Two MaxBotix MB7060 sensors on dedicated UARTs.\n", "Ultrasonics: 2 x MB7060.\n", + "Cliff sensing with four TF-Luna.\n", "Fit 4 x TF-Luna on the panels.\n"): + self.assertEqual(self.ids("docs/a.md", text, "x"), ["BASE-CONTROLLER-IO"], text) + for text in ("Four MaxBotix MB7060 in the edge holes, two TF-Luna cliff sensors in the centre holes.\n", + "Two MaxBotix MB7060 (superseded by four).\n", "Legacy layout: 4 x TF-Luna.\n"): + self.assertEqual(self.ids("docs/a.md", text, "x"), [], text) + + def test_base_camera_height_243_superseded(self): + repo = "openamrobot-docs" + for text in ("Gemini 336L about 243 mm above the floor.\n", "The base camera sits at 243 mm.\n", + "243 mm above the floor: Orbbec Gemini 336L.\n"): + self.assertEqual(self.ids("docs/a.md", text, repo), ["CAMERAS"], text) + for text in ("Gemini 336L 142.5 mm above the floor; base_camera_link (0.376, 0, 0.0445).\n", + "The base camera at 243 mm is superseded.\n", "Historical: Gemini 336L at 243 mm.\n"): + self.assertEqual(self.ids("docs/a.md", text, repo), [], text) + + def test_icm42688p_is_the_2_0_imu(self): + for text in ("The ICM-42688-P is selected as the OpenAMRobot 2.0 IMU.\n", + "ICM-42688-P (MIKROE-4237, SPI) is the baseline IMU; WHO_AM_I 0x47 at boot.\n"): + self.assertEqual(self.ids("docs/a.md", text, "x"), [], text) + self.assertEqual(self.ids("docs/a.md", "The Gate A IMU is the MPU6050.\n", "x"), ["BASE-CONTROLLER-GATES"]) + + def test_mpu6050_explanatory_gate_a_text_is_accepted(self): + # Text explaining why the Gate A chip is not an MPU6050 is not a finding. + for text in ("| `WHO_AM_I` (reg 0x75) | **0x70** (an MPU6050 would return 0x68; Gate A unit) |\n", + "The board labeled \"MPU6050\" is actually an MPU6500.\n", + "the board was labelled / assumed to be an MPU6050, but it is an MPU6500\n", + "A real MPU6500 is not a real MPU6050.\n", + "Use the MPU9250 path instead of MPU6050.\n", + "#define USE_MPU6050 0\n", + "The MPU9250 driver recognises it; the MPU6050 driver rejects it.\n"): + self.assertEqual(self.ids("docs/a.md", text, "x"), [], text) + for text in ("The base uses an MPU6050 IMU.\n", "IMU: MPU6050 on I2C.\n"): + self.assertEqual(self.ids("docs/a.md", text, "x"), ["BASE-CONTROLLER-GATES"], text) + + def test_power_rails_24v_to_5v_12v(self): + repo = "openamr-platform-hw" + self.assertEqual(self.ids("docs/a.md", "DC-DC: 24 V to 5 V / 12 V for the peripherals.\n", repo), + ["POWER-RAILS"]) + for text in ("Gate A unit: DROK converter 24 V to 5 V / 12 V.\n", + "Legacy converter 24V -> 5V/12V.\n"): + self.assertEqual(self.ids("docs/a.md", text, repo), [], text) + + def test_column_axis_not_on_drive_axle(self): + repo = "openamr-upperbody-sw" + for text in ("The column axis at bp000 is on the drive axle.\n", "Drive axle and column axis coincide at bp000.\n"): + self.assertEqual(self.ids("docs/a.md", text, repo), ["ARM-MOUNT"], text) + for text in ("Column axis 330 mm behind the front edge: x +0.060 at bp000, x +0.110 at bp050.\n", + "Column axis on the drive axle (superseded).\n"): + self.assertEqual(self.ids("docs/a.md", text, repo), [], text) + + def test_lidar_link_pose(self): + repo = "openamr-platform-sw" + self.assertEqual(self.ids("config/a.yaml", "lidar_xyz: [0.335, 0.0, 0.18]\n", repo), ["NAV-LIDAR"]) + for path in ("urdf/base.urdf.xacro", "urdf/base.urdf"): + self.assertEqual(self.ids(path, '\n', repo), + ["NAV-LIDAR"], path) + self.assertEqual(self.ids(path, '\n', repo), [], path) + for text in ("lidar_xyz: [0.330, 0.0, 0.124] # yaw pi, 7.1 mm spacer\n", + "lidar_xyz: [0.335, 0.0, 0.18] # legacy Gate A pose\n"): + self.assertEqual(self.ids("config/a.yaml", text, repo), [], text) + + def test_near_field_frames_tof_pitch_is_screening(self): + repo = "openamr-platform-hw" + self.assertEqual(self.ids("docs/a.md", "tof_front pitched 20 degrees down, final.\n", repo), + ["NEAR-FIELD-FRAMES"]) + for text in ("tof_front pitched 20 degrees down (screening value until the bench test).\n", + "us_front_left (0.390, +0.130, -0.0066); tof_rear (-0.390, 0, -0.0066, yaw pi).\n"): + self.assertEqual(self.ids("docs/a.md", text, repo), [], text) + def test_release_milestones_no_v0_2_or_13_november(self): for text in ("v0.2 is the first release built from the harness.\n", "Readiness declaration for v0.2.\n", From 1835d4dfc1c9085f36a057a4e8333d4c32490370 Mon Sep 17 00:00:00 2001 From: Arumuga Vignesh S R <129583467+wikki26@users.noreply.github.com> Date: Tue, 13 Oct 2026 21:47:49 +0200 Subject: [PATCH 6/7] ci: allow controlled H-CI-1 candidate image publishing Signed-off-by: Arumuga Vignesh S R <129583467+wikki26@users.noreply.github.com> --- .github/workflows/ci-image.yml | 34 +++++++++++++++++++++++++++++----- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci-image.yml b/.github/workflows/ci-image.yml index 50bf8e2..c36307e 100644 --- a/.github/workflows/ci-image.yml +++ b/.github/workflows/ci-image.yml @@ -15,6 +15,12 @@ on: - ".github/workflows/ci-image.yml" workflow_dispatch: + inputs: + publish_candidate: + description: "Publish H-CI-1 candidate image to GHCR" + required: true + type: boolean + default: false permissions: contents: read @@ -40,26 +46,44 @@ jobs: uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 # v3.11.1 - name: Log in to GHCR - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + if: >- + (github.event_name == 'push' && + github.ref == 'refs/heads/main') || + (github.event_name == 'workflow_dispatch' && + github.ref == 'refs/heads/h-ci-1-baseline-image' && + inputs.publish_candidate == true) uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - - name: Build CI image and publish from main + - name: Build CI image and publish when authorized id: build uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6.19.2 with: context: . file: containers/ci/Dockerfile - push: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + + push: >- + ${{ (github.event_name == 'push' && + github.ref == 'refs/heads/main') || + (github.event_name == 'workflow_dispatch' && + github.ref == 'refs/heads/h-ci-1-baseline-image' && + inputs.publish_candidate == true) }} + tags: | - ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.sha }} + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && 'latest' || format('candidate-{0}', github.sha) }} - name: Print published image digest - if: github.event_name == 'push' && github.ref == 'refs/heads/main' + if: >- + (github.event_name == 'push' && + github.ref == 'refs/heads/main') || + (github.event_name == 'workflow_dispatch' && + github.ref == 'refs/heads/h-ci-1-baseline-image' && + inputs.publish_candidate == true) run: | echo "Image: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" echo "Digest: ${{ steps.build.outputs.digest }}" + echo "Pinned reference: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}@${{ steps.build.outputs.digest }}" From a1f619307557ad3a0680065127df7e027d47dd83 Mon Sep 17 00:00:00 2001 From: Arumuga Vignesh S R <129583467+wikki26@users.noreply.github.com> Date: Tue, 13 Oct 2026 22:52:10 +0200 Subject: [PATCH 7/7] docs(ci): clarify LiDAR driver policy Signed-off-by: Arumuga Vignesh S R <129583467+wikki26@users.noreply.github.com> --- containers/ci/Dockerfile | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/containers/ci/Dockerfile b/containers/ci/Dockerfile index 3e3c540..f09ae3d 100644 --- a/containers/ci/Dockerfile +++ b/containers/ci/Dockerfile @@ -2,6 +2,12 @@ FROM ros:jazzy-ros-base@sha256:066420e07f60aa18262f2479981def87ebcfcec42eefb0c0c ARG DEBIAN_FRONTEND=noninteractive +# LiDAR driver policy: +# Do not install the legacy ros-jazzy-rplidar-ros package in this baseline. +# OpenAMRobot 2.0 targets RPLIDAR S3 using sllidar_ros2. +# The current workspace manifest does not pin sllidar_ros2 yet. +# Driver source integration and hardware validation remain separate work. +# # Common CI and ROS workspace tooling RUN apt-get update && apt-get install -y --no-install-recommends \ python3-colcon-common-extensions \