diff --git a/README.md b/README.md index 8a45a97..d71a46e 100644 --- a/README.md +++ b/README.md @@ -170,10 +170,11 @@ unmodified. The sim dependencies live in a separate pixi environment so the robot install stays lean: ```bash -pixi run -e sim sim # headless gz + robot + controllers +pixi run sim # headless gz + robot + controllers +pixi run teleop # drive it around +# Ad-hoc commands need the sim environment named explicitly: pixi run -e sim -- ros2 launch mote_bringup slam_launch.py use_sim_time:=true pixi run -e sim -- gz sim -g # optional: attach the Gazebo GUI -pixi run teleop # drive it around ``` The world (`mote_bringup/worlds/mote_world.sdf`) is a simple walled room with @@ -192,12 +193,10 @@ For now, I currently develop on a workstation and push to the Pi with rsync. The [`pixi.toml`](pixi.toml) `[tasks]` `sync` entry to match your Pi, then: ```bash -pixi run sync +pixi run sync # one-shot push +pixi run sync-watch # keep pushing on every save (needs the dev env) ``` -I want to try [pixi pack](https://pixi.prefix.dev/latest/deployment/pixi_pack/) -for this eventually but haven't had a chance yet. - ## SO-101 Follower Arm ![Mote with SO-101 arm](docs/images/mote_SO_101.webp) diff --git a/design/ASSEMBLY.md b/design/ASSEMBLY.md new file mode 100644 index 0000000..f66a99f --- /dev/null +++ b/design/ASSEMBLY.md @@ -0,0 +1,79 @@ +# Printing & Assembly + +How to print the parts and put Mote together. Wiring is covered separately in +[WIRING.md](WIRING.md); the part files live in +[`step/`](step/) (editable in CAD), [`stl/`](stl/) (mesh) and +[`3mf/`](3mf/) (mesh + print setup). + +> ⚠️ Print settings below are sensible starting points, not measured-optimal — +> confirm against your printer/filament. The `.3mf` files carry their own plate +> setup; prefer them if your slicer reads 3mf. + +## Printing + +All parts fit a 256 mm bed (the chassis is 235 mm — see +[design rationale](README.md#chassis-diameter-235mm)). + +Suggested defaults: **PLA**, 0.2 mm layer height, 3 walls, 15–20% infill, brim on +the large flat plates to prevent corner lift. + +| Part (qty) | Material | +| --------------------------- | -------------- | +| Chassis Base (1) | PLA | +| Chassis Top (1) | PLA | +| Motor Support (2) | PLA | +| Pi Bottom + Pi Top (1 each) | PLA | +| Waveshare Mount (1) | PLA | +| C1 Lidar Mount (1) | PLA | +| Camera Mount (1) | PLA | +| Battery Mount (1) | PLA | +| Wheel Inner (2) | PLA | +| Wheel Tyre (2) | **TPU** (grip) | +| Caster (1) | PLA | +| SO Base ORP (1, optional) | PLA | + +Notes: + +- **Wheels are two-part**: a rigid `Wheel Inner` hub plus a `Wheel Tyre` printed + in **TPU** for traction. +- **Caster is unresolved** — printed and several off-the-shelf options have all + been unsatisfactory so far; treat this part as provisional. A bought ball + caster of the right height may be preferable (see Assembly step 6). + +## Assembly + +**Hardware:** the M3 button-head hex set from the [BOM](BOM.md) (screws, nuts) +covers all fasteners. Most joints take **M3×12**: the screw passes through a ~6 +mm plate into a part with a ~6 mm captive-nut pocket. Use **M3×10** for thinner +stacks. + +> **Note:** I am not convinced yet that screws and nuts are the optimal choice +> here. Nuts have a tendency to loosen up due to vibrations while driving around +> so we may want something more reliable. + +Suggested order: + +1. **Servos.** Mount each STS3215 to the `Motor Support`, then press a + `Wheel Inner` onto the servo horn and fit the `Wheel Tyre` over it. Wheels + are centred and inset so the footprint stays circular. It's easiest to set + the servo ID's before going further. Left servo is **ID 7**, right is **ID + 9** (assign with `pixi run setup-ids` — see the + [README](../README.md#4-configure-the-servos)). +2. **Lower plate.** Fasten the `Motor Support`/servos, the `Battery Mount`, the + `Waveshare Mount`, and the `C1 Lidar Mount`, to the `Chassis Base`. +3. **Caster.** Fit the front `Caster` to the underside of the base for the third + contact point (provisional — see Printing notes). +4. **Sensors.** Mount the camera in the `Camera Mount`. +5. **Top plate.** Attach the `Pi Bottom` holder and the `Camera/Camera Mount` to + the `Chassis Top`. +6. **Close it up.** Fix the `Chassis Top` onto the standoffs. +7. **Power bank.** Seat the power bank in the `Battery Mount` between the + plates. +8. **Wire it.** Follow [WIRING.md](WIRING.md): bank Out1 → servo board (barrel), + bank Out2 → Pi, servo board USB → Pi, lidar/camera USB → Pi. Route cables + through the standoff gap and keep the lidar's 360° view clear. +9. **(Optional) SO-101 arm.** The `SO Base ORP` adapter mounts the + [SO-101 follower arm](https://github.com/TheRobotStudio/SO-ARM100) on the ORP + grid. + +Then bring the software up per the [main README](../README.md#5-launch). diff --git a/design/README.md b/design/README.md index 50585d0..e5364c5 100644 --- a/design/README.md +++ b/design/README.md @@ -51,3 +51,8 @@ Out1 to stop them stalling. The Pi runs fine on the 45W port. ## Bill of Materials See [BOM.md](BOM.md). + +## Build guides + +- [WIRING.md](WIRING.md) — connections, power topology and budget, IMU pinout. +- [ASSEMBLY.md](ASSEMBLY.md) — print settings per part and assembly steps. diff --git a/design/WIRING.md b/design/WIRING.md new file mode 100644 index 0000000..8bd4950 --- /dev/null +++ b/design/WIRING.md @@ -0,0 +1,80 @@ +# Wiring & Power + +How the Mote electronics connect. Everything runs from a single USB-C power +bank at **5 V** (see [the 5 V-only rationale](README.md#power-5v-only)). Device +names in the launch stack (`/dev/mote_*`) are created by the udev rules in +[`mote_bringup/udev/`](../mote_bringup/udev/). + +Every data link is plain USB (standard male plugs into the device ports), so +there's no special connector wiring — just the cables in the [BOM](BOM.md). +A few electrical details still want bench confirmation; those are marked **Verify**. + +## Diagram + +```mermaid +flowchart LR + BANK["UGREEN 140W power bank"] + BANK -->|"Out1 high-current · USB-C to DC barrel · 5V"| MCB["Waveshare Serial Bus
Servo Driver Board"] + BANK -->|"Out2 · USB-C to USB-C · 5V"| PI["Raspberry Pi 5"] + + MCB ==>|"3-pin bus: 5V + serial"| SL["Left STS3215
ID 7, inverted"] + MCB ==>|"3-pin bus: 5V + serial"| SR["Right STS3215
ID 9"] + + MCB -->|"USB serial to /dev/mote_servos"| PI + LIDAR["RPLIDAR C1"] -->|"USB to /dev/mote_lidar"| PI + CAM["USB webcam"] -->|"USB to /dev/mote_camera"| PI + IMU["BNO085 IMU
in testing"] -.->|"I2C to GPIO"| PI + + classDef power fill:#cde,stroke:#369; + class BANK,MCB,PI power; +``` + +Solid lines = power and/or wired data. The lidar, camera and IMU are powered by +the Pi over their data connection (USB / GPIO), not from the bank directly. + +## Connections + +### Power + +| From (port) | Cable | To | Carries | +| --------------------------- | ------------------------------------- | ------------------------ | ------- | +| Bank **Out1** (100 W USB-C) | USB-C → DC 5.5×2.1 mm barrel, **5 V** | Servo board DC input | 5 V | +| Bank **Out2** (45 W USB-C) | USB-C ↔ USB-C, 0.3 m | Pi 5 USB-C power in | 5 V | +| Servo board | 3-pin servo lead | Left STS3215 (**ID 7**) | 5 V | +| Servo board | 3-pin servo lead | Right STS3215 (**ID 9**) | 5 V | + +### Data + +| From | Cable | To | Device node | Notes | +| ------------------------ | ------------------------------ | -------- | ------------------ | ----------------------------- | +| Servo board (USB-C data) | USB-A ↔ USB-C, 0.3 m | Pi USB-A | `/dev/mote_servos` | CH343 USB-serial, 1 Mbaud | +| RPLIDAR C1 | USB (cable supplied with unit) | Pi USB-A | `/dev/mote_lidar` | 460800 baud; powered over USB | +| USB webcam | USB-A (captive) | Pi USB-A | `/dev/mote_camera` | UVC; powered over USB | + +The Pi 5 has 4 USB ports (2× USB-3, 2× USB-2). Servo board, lidar and camera +take three of them. + +## Power notes (the fiddly bit) + +Three things make the 5 V budget non-obvious: + +1. **Servos run at 5 V** The STS3215's + [datasheet](https://www.feetechrc.com/Data/feetechrc/upload/file/20260622/6391772523943436695270694.pdf) + operating range is **4 V - 7.4V**, with the expected value of 6V or 7.4V. + Mote feeds the servo board **5 V** and this seems to work well. Just don't + expect the datasheet torque numbers, since those are quoted at the higher + voltage. + +2. **A "100 W" USB-C port is not 100 W at 5 V.** USB-C PD allows devices to + negotiate different voltage/current depending on need. Focusing on 5V, the + spec allows requesting up to 3A, however it is common for supplies to allow + up to 5A. The Pi explicitly requests 5V/5A = 25W. The servos only need 500mA. + +### Rough 5 V budget + +| Load | Rail | Typical | Peak | Fed from | +| -------------------- | -------------- | --------------------- | -------------- | -------- | +| Raspberry Pi 5 | 5 V | 5–10 W | 25 W (5 V/5 A) | Out2 | +| 2× STS3215 (driving) | 5 V via board | 1-2 W (130mA no load) | 10W (2A stall) | Out1 | +| RPLIDAR C1 | 5 V via Pi USB | 1.15 W (230 mA) | — | Pi | +| USB webcam | 5 V via Pi USB | ~0.5–1 W | — | Pi | diff --git a/pixi.lock b/pixi.lock index 4a96cb4..ae7b0aa 100644 --- a/pixi.lock +++ b/pixi.lock @@ -1908,6 +1908,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-9.5.2-py312h244374b_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-base-9.5.2-py312h6fba518_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/vtk-io-ffmpeg-9.5.2-py312hcdbd8b1_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/watchexec-2.5.1-hb17b654_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.25.0-hd6090a7_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/wrapt-2.2.1-py312h4c3975b_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-64/x264-1!164.3095-h166bdaf_2.tar.bz2 @@ -2952,6 +2953,7 @@ environments: - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/vtk-9.5.2-py312h4954c87_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/vtk-base-9.5.2-py312h90a26f6_7.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/vtk-io-ffmpeg-9.5.2-py312haba1314_7.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/watchexec-2.5.1-h069e38c_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/wayland-1.25.0-h4f8a99f_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/wrapt-2.2.1-py312hcd1a082_0.conda - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/x264-1!164.3095-h4e544f5_2.tar.bz2 @@ -3544,6 +3546,95 @@ environments: - conda: https://conda.anaconda.org/robostack-jazzy/linux-aarch64/ros-jazzy-zstd-vendor-0.26.9-np2py312h61f2ce4_16.conda - conda: https://conda.anaconda.org/robostack-jazzy/linux-aarch64/ros2-distro-mutex-0.14.0-jazzy_16.conda - conda: https://prefix.dev/mote/linux-aarch64/scservo-linux-1.0.0-he8cfe8b_0.conda + lint: + channels: + - url: https://prefix.dev/mote/ + - url: https://conda.anaconda.org/robostack-jazzy/ + - url: https://conda.anaconda.org/conda-forge/ + packages: + linux-64: + - conda: https://conda.anaconda.org/conda-forge/linux-64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/bzip2-1.0.8-hda65f42_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ld_impl_linux-64-2.45.1-default_hbd61a6d_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libexpat-2.8.1-hecca717_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libffi-3.5.2-h3435931_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgcc-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libgomp-15.2.0-he0feb66_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/liblzma-5.8.3-hb03c661_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libsqlite-3.53.2-h0c1763c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libstdcxx-15.2.0-h934c35e_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libuuid-2.42.1-h5347b49_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/libzlib-1.3.2-h25fd6f3_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ncurses-6.6-hdb14827_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/openssl-3.6.3-h35e630c_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.6-habeac84_100_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/readline-8.3-h853b02a_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/tk-8.6.13-noxft_h366c992_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py314h9891dd4_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/yaml-0.2.5-h280c20c_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-64/zstd-1.5.7-hb78ec9c_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.10.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.6.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-3.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.4.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.4.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda + linux-aarch64: + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/_openmp_mutex-4.5-20_gnu.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/bzip2-1.0.8-h4777abc_9.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py314h0bd77cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/icu-78.3-hcab7f73_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ld_impl_linux-aarch64-2.45.1-default_h1979696_102.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libexpat-2.8.1-hfae3067_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libffi-3.5.2-h376a255_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgcc-15.2.0-h8acb6b2_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libgomp-15.2.0-h8acb6b2_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/liblzma-5.8.3-he30d5cf_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libsqlite-3.53.2-h10b116e_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libstdcxx-15.2.0-hef695bb_19.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libuuid-2.42.1-h1022ec0_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libzlib-1.3.2-hdc9db2a_2.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ncurses-6.6-hf8d1292_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/openssl-3.6.3-h546c87b_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.6-hc679e19_100_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/readline-8.3-hb682ff5_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/tk-8.6.13-noxft_h0dc03b3_103.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py314hd7d8586_0.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/yaml-0.2.5-h80f16a2_3.conda + - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/zstd-1.5.7-h85ac4a6_6.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/ca-certificates-2026.5.20-hbd8a1cb_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/filelock-3.29.3-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/importlib-metadata-9.0.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.10.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.6.0-pyha770c72_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/pycparser-3.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.4.2-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/typing_extensions-4.15.0-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/tzdata-2025c-hc9c84f9_1.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.4.3-pyhcf101f3_0.conda + - conda: https://conda.anaconda.org/conda-forge/noarch/zipp-4.1.0-pyhcf101f3_0.conda sim: channels: - url: https://prefix.dev/mote/ @@ -5926,6 +6017,20 @@ packages: license_family: MIT size: 295716 timestamp: 1761202958833 +- conda: https://conda.anaconda.org/conda-forge/linux-64/cffi-2.0.0-py314h4a8dc5f_1.conda + sha256: c6339858a0aaf5d939e00d345c98b99e4558f285942b27232ac098ad17ac7f8e + md5: cf45f4278afd6f4e6d03eda0f435d527 + depends: + - __glibc >=2.17,<3.0.a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - pycparser + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + size: 300271 + timestamp: 1761203085220 - conda: https://conda.anaconda.org/conda-forge/linux-64/cfitsio-4.6.3-ha0b56bc_0.conda sha256: 31beae4b063f5e39ade020d3ee1ade0fdc8d5556fafac4d004ebe74ffbad44dd md5: 0fb449e4da07934a40db021c84773ed0 @@ -9422,6 +9527,16 @@ packages: license_family: LGPL size: 287897 timestamp: 1779091106723 +- conda: https://conda.anaconda.org/conda-forge/linux-64/libmpdec-4.0.0-hb03c661_1.conda + sha256: fe171ed5cf5959993d43ff72de7596e8ac2853e9021dec0344e583734f1e0843 + md5: 2c21e66f50753a083cbe6b80f38268fa + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + license: BSD-2-Clause + license_family: BSD + size: 92400 + timestamp: 1769482286018 - conda: https://conda.anaconda.org/conda-forge/linux-64/libnetcdf-4.9.3-nompi_hbf2fc22_104.conda sha256: cae2f8fe5258fc1a1d2b61cbc9190ed2c0a1b7cdf5d4aac98da071ade6dac152 md5: a2956b63b1851e9d5eb9f882d02fa3a9 @@ -11598,6 +11713,33 @@ packages: license: Python-2.0 size: 31608571 timestamp: 1772730708989 +- conda: https://conda.anaconda.org/conda-forge/linux-64/python-3.14.6-habeac84_100_cp314.conda + build_number: 100 + sha256: 6d28ac2b061179deb434d3d57afa98ffd20ec3c5d44ab8048a1ca33424b22d38 + md5: 0b9b2f83b5b600e1ac38becde8d0dd44 + depends: + - __glibc >=2.17,<3.0.a0 + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-64 >=2.36.1 + - libexpat >=2.8.1,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - liblzma >=5.8.3,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.53.2,<4.0a0 + - libuuid >=2.42.1,<3.0a0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.6,<7.0a0 + - openssl >=3.5.7,<4.0a0 + - python_abi 3.14.* *_cp314 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + size: 36717183 + timestamp: 1781255094700 + python_site_packages_path: lib/python3.14/site-packages - conda: https://conda.anaconda.org/conda-forge/linux-64/python-orocos-kdl-1.5.3-py312h1289d80_2.conda sha256: 481d724d6f7bbfa931f6f33a7940d3637b7289139526a5952d2289c114c5f5b6 md5: 30d805f6312812a6abef0933e56deefa @@ -11627,6 +11769,19 @@ packages: license_family: MIT size: 198293 timestamp: 1770223620706 +- conda: https://conda.anaconda.org/conda-forge/linux-64/pyyaml-6.0.3-py314h67df5f8_1.conda + sha256: b318fb070c7a1f89980ef124b80a0b5ccf3928143708a85e0053cde0169c699d + md5: 2035f68f96be30dc60a5dfd7452c7941 + depends: + - __glibc >=2.17,<3.0.a0 + - libgcc >=14 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + size: 202391 + timestamp: 1770223462836 - conda: https://conda.anaconda.org/conda-forge/linux-64/qhull-2020.2-h434a139_5.conda sha256: 776363493bad83308ba30bcb88c2552632581b143e8ee25b1982c8c743e73abc md5: 353823361b1d27eb3960efb076dfcaf6 @@ -12218,6 +12373,20 @@ packages: license_family: BSD size: 71525 timestamp: 1776960300375 +- conda: https://conda.anaconda.org/conda-forge/linux-64/ukkonen-1.1.0-py314h9891dd4_0.conda + sha256: c84034056dc938c853e4f61e72e5bd37e2ec91927a661fb9762f678cbea52d43 + md5: 5d3c008e54c7f49592fca9c32896a76f + depends: + - __glibc >=2.17,<3.0.a0 + - cffi + - libgcc >=14 + - libstdcxx >=14 + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + size: 15004 + timestamp: 1769438727085 - conda: https://conda.anaconda.org/conda-forge/linux-64/uncrustify-0.83.0-h54a6638_0.conda sha256: 556ea427c375c2b9eb3122b19a1ce0891d535ad51a196f25c73786bb1d7c5156 md5: 29f7fdf10a9604e18924eebbde71ce62 @@ -12395,6 +12564,18 @@ packages: license_family: BSD size: 108379 timestamp: 1768718074243 +- conda: https://conda.anaconda.org/conda-forge/linux-64/watchexec-2.5.1-hb17b654_0.conda + sha256: 5f2140f7b6a18138cad7a305b4185bea8499a4e044afb91e3fad72a130255d3b + md5: e5b552a8e3cc6084bce363770ae18c46 + depends: + - libgcc >=14 + - __glibc >=2.17,<3.0.a0 + constrains: + - __glibc >=2.17 + license: Apache-2.0 + license_family: APACHE + size: 3311519 + timestamp: 1774855010015 - conda: https://conda.anaconda.org/conda-forge/linux-64/wayland-1.25.0-hd6090a7_0.conda sha256: ea374d57a8fcda281a0a89af0ee49a2c2e99cc4ac97cf2e2db7064e74e764bdb md5: 996583ea9c796e5b915f7d7580b51ea6 @@ -13622,6 +13803,19 @@ packages: license_family: MIT size: 315113 timestamp: 1761203960926 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cffi-2.0.0-py314h0bd77cf_1.conda + sha256: 728e55b32bf538e792010308fbe55d26d02903ddc295fbe101167903a123dd6f + md5: f333c475896dbc8b15efd8f7c61154c7 + depends: + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - pycparser + - python >=3.14,<3.15.0a0 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + size: 318357 + timestamp: 1761203973223 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/cfitsio-4.6.3-hf475483_0.conda sha256: dca79e594c6326751291e1c0b47a92ef0bd2c0ad067105b0971fec2c73d3cf72 md5: fcc37a4d1fde95e2106059dd7ad3ec13 @@ -16979,6 +17173,15 @@ packages: license_family: LGPL size: 296558 timestamp: 1779091126550 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libmpdec-4.0.0-he30d5cf_1.conda + sha256: 57c0dd12d506e84541c4e877898bd2a59cca141df493d34036f18b2751e0a453 + md5: 7b9813e885482e3ccb1fa212b86d7fd0 + depends: + - libgcc >=14 + license: BSD-2-Clause + license_family: BSD + size: 114056 + timestamp: 1769482343003 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/libnetcdf-4.9.3-nompi_h06de00c_104.conda sha256: bf4d494f37744f27c474cfcaafe65e8680c117137ed45fc4866dfe82ad9aa4dc md5: 76ed52bab2a733e0eb5f08b8ec3da215 @@ -18990,6 +19193,32 @@ packages: license: Python-2.0 size: 13757191 timestamp: 1772728951853 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-3.14.6-hc679e19_100_cp314.conda + build_number: 100 + sha256: dd56fd95db3cb49a69fbe41df80afc8bd5214daa829bcd3930de80f0408ba5eb + md5: 416c74941d13d9f2b9e68b1a900f7f50 + depends: + - bzip2 >=1.0.8,<2.0a0 + - ld_impl_linux-aarch64 >=2.36.1 + - libexpat >=2.8.1,<3.0a0 + - libffi >=3.5.2,<3.6.0a0 + - libgcc >=14 + - liblzma >=5.8.3,<6.0a0 + - libmpdec >=4.0.0,<5.0a0 + - libsqlite >=3.53.2,<4.0a0 + - libuuid >=2.42.1,<3.0a0 + - libzlib >=1.3.2,<2.0a0 + - ncurses >=6.6,<7.0a0 + - openssl >=3.5.7,<4.0a0 + - python_abi 3.14.* *_cp314 + - readline >=8.3,<9.0a0 + - tk >=8.6.13,<8.7.0a0 + - tzdata + - zstd >=1.5.7,<1.6.0a0 + license: Python-2.0 + size: 34900936 + timestamp: 1781254861576 + python_site_packages_path: lib/python3.14/site-packages - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/python-orocos-kdl-1.5.3-py312h1ab2c47_2.conda sha256: 6a5a07185a4509ab13dcef98594d041081dd70d26b23651f4c86cc289f6217f6 md5: 574358b8f203748e7c46ff70a908ee76 @@ -19019,6 +19248,19 @@ packages: license_family: MIT size: 192182 timestamp: 1770223431156 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/pyyaml-6.0.3-py314h807365f_1.conda + sha256: 496b5e65dfdd0aaaaa5de0dcaaf3bceea00fcb4398acf152f89e567c82ec1046 + md5: 9ae2c92975118058bd720e9ba2bb7c58 + depends: + - libgcc >=14 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + - yaml >=0.2.5,<0.3.0a0 + license: MIT + license_family: MIT + size: 195678 + timestamp: 1770223441816 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/qhull-2020.2-h70be974_5.conda sha256: 49f777bdf3c5e030a8c7b24c58cdfe9486b51d6ae0001841079a3228bdf9fb51 md5: bb138086d938e2b64f5f364945793ebf @@ -19559,6 +19801,20 @@ packages: license_family: BSD size: 73779 timestamp: 1776960577002 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/ukkonen-1.1.0-py314hd7d8586_0.conda + sha256: 0a7efe469d7e2a34a1d017bc51cf6fb9a51436730256983694c5ad74a33bd4e0 + md5: f3a967efabf9cf450b7741487318ea6e + depends: + - cffi + - libgcc >=14 + - libstdcxx >=14 + - python >=3.14,<3.15.0a0 + - python >=3.14,<3.15.0a0 *_cp314 + - python_abi 3.14.* *_cp314 + license: MIT + license_family: MIT + size: 15756 + timestamp: 1769438772414 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/uncrustify-0.83.0-h7ac5ae9_0.conda sha256: e2b3719965204cc8c0fecaa685c96b527da168f97eb13a7e36fc7d8a6876c2b0 md5: 6a3d6acb5c7d4c203a33b14b8925c6c7 @@ -19731,6 +19987,17 @@ packages: license_family: BSD size: 106747 timestamp: 1768718080474 +- conda: https://conda.anaconda.org/conda-forge/linux-aarch64/watchexec-2.5.1-h069e38c_0.conda + sha256: 597470409a6cb80d85a2c433d30b91fbc542ccb8096a3aadcf084955e5a883ac + md5: 7e089d2d3ac6cc22b9ee91563116a028 + depends: + - libgcc >=14 + constrains: + - __glibc >=2.17 + license: Apache-2.0 + license_family: APACHE + size: 3164356 + timestamp: 1774855038268 - conda: https://conda.anaconda.org/conda-forge/linux-aarch64/wayland-1.25.0-h4f8a99f_0.conda sha256: 3cc479df517b0ce110835a1256f91ca568581cb6dfe1c53a0786f0a226039a45 md5: 0a7a9548726f98d5869fd4c43e110f0f @@ -20342,6 +20609,15 @@ packages: license_family: BSD size: 54106 timestamp: 1757558592553 +- conda: https://conda.anaconda.org/conda-forge/noarch/cfgv-3.5.0-pyhd8ed1ab_0.conda + sha256: aa589352e61bb221351a79e5946d56916e3c595783994884accdb3b97fe9d449 + md5: 381bd45fb7aa032691f3063aff47e3a1 + depends: + - python >=3.10 + license: MIT + license_family: MIT + size: 13589 + timestamp: 1763607964133 - conda: https://conda.anaconda.org/conda-forge/noarch/colcon-argcomplete-0.3.3-pyhd8ed1ab_1.conda sha256: 05ccb85cad9ca58be9dcb74225f6180a68907a6ab0c990e3940f4decc5bb2280 md5: bde6042a1b40a2d4021e1becbe8dd84f @@ -20641,6 +20917,16 @@ packages: license_family: APACHE size: 303675 timestamp: 1780988738861 +- conda: https://conda.anaconda.org/conda-forge/noarch/distlib-0.4.3-pyhcf101f3_0.conda + sha256: e2753997b8bd34205f42be01b8bab8037423dc30c02a1ec12de23e5b4c0b0a2e + md5: 58638f77697c4f6726753eb8be34818b + depends: + - python >=3.10 + - python + license: Apache-2.0 + license_family: APACHE + size: 303705 + timestamp: 1781320269259 - conda: https://conda.anaconda.org/conda-forge/noarch/distro-1.9.0-pyhd8ed1ab_1.conda sha256: 5603c7d0321963bb9b4030eadabc3fd7ca6103a38475b4e0ed13ed6d97c86f4e md5: 0a2014fd9860f8b1eaa0b1f3d3771a08 @@ -20838,6 +21124,16 @@ packages: license_family: MIT size: 73563 timestamp: 1733928021866 +- conda: https://conda.anaconda.org/conda-forge/noarch/identify-2.6.19-pyhd8ed1ab_0.conda + sha256: 381cedccf0866babfc135d65ee40b778bd20e927d2a5ec810f750c5860a7c5b8 + md5: 84a3233b709a289a4ddd7a2fd27dd988 + depends: + - python >=3.10 + - ukkonen + license: MIT + license_family: MIT + size: 79757 + timestamp: 1776455344188 - conda: https://conda.anaconda.org/conda-forge/noarch/idna-3.15-pyhcf101f3_0.conda sha256: 3d25f9f6f7ab3e1ce6429fc8c8aae0335cf446692e715068488536d220cc43de md5: 1b9083b7f00609605d1483dbc6071a81 @@ -21002,6 +21298,16 @@ packages: license_family: Apache size: 15851 timestamp: 1749895533014 +- conda: https://conda.anaconda.org/conda-forge/noarch/nodeenv-1.10.0-pyhd8ed1ab_0.conda + sha256: 4fa40e3e13fc6ea0a93f67dfc76c96190afd7ea4ffc1bac2612d954b42cdc3ee + md5: eb52d14a901e23c39e9e7b4a1a5c015f + depends: + - python >=3.10 + - setuptools + license: BSD-3-Clause + license_family: BSD + size: 40866 + timestamp: 1766261270149 - conda: https://conda.anaconda.org/conda-forge/noarch/packaging-26.2-pyhc364b38_0.conda sha256: 3906abfb6511a3bb309e39b9b1b7bc38f50a723971de2395489fd1f379255890 md5: 4c06a92e74452cfa53623a81592e8934 @@ -21022,6 +21328,16 @@ packages: license_family: MIT size: 19044 timestamp: 1667916747996 +- conda: https://conda.anaconda.org/conda-forge/noarch/platformdirs-4.10.0-pyhcf101f3_0.conda + sha256: 9e5e1fd3506ccfc4d444fc4d2d39b0ed097d5d0e3bd3d4bdf6bcc81aaf66860d + md5: 2c5ef45db85d34799771629bd5860fd7 + depends: + - python >=3.10 + - python + license: MIT + license_family: MIT + size: 26308 + timestamp: 1779972894916 - conda: https://conda.anaconda.org/conda-forge/noarch/pluggy-1.6.0-pyhf9edf01_1.conda sha256: e14aafa63efa0528ca99ba568eaf506eb55a0371d12e6250aaaa61718d2eb62e md5: d7585b6550ad04c8c5e21097ada2888e @@ -21048,6 +21364,20 @@ packages: license_family: OTHER size: 2348171 timestamp: 1675353652214 +- conda: https://conda.anaconda.org/conda-forge/noarch/pre-commit-4.6.0-pyha770c72_0.conda + sha256: 716960bf0a9eb334458a26b3bdcb17b8d0786062138a4f48c7f335c8418c5d0b + md5: 7859736b4f8ebe6c8481bf48d91c9a1e + depends: + - cfgv >=2.0.0 + - identify >=1.0.0 + - nodeenv >=0.11.1 + - python >=3.10 + - pyyaml >=5.1 + - virtualenv >=20.10.0 + license: MIT + license_family: MIT + size: 201606 + timestamp: 1776858157327 - conda: https://conda.anaconda.org/conda-forge/noarch/pybind11-3.0.3-pyhfe8187e_0.conda sha256: 71a9524f44d6ac6304feae71e2bbe8d8ce0816f0be7a0271c15681ad1040965d md5: e0f4549ccb507d4af8ed5c5345210673 @@ -21238,6 +21568,18 @@ packages: license_family: APACHE size: 233310 timestamp: 1751104122689 +- conda: https://conda.anaconda.org/conda-forge/noarch/python-discovery-1.4.2-pyhcf101f3_0.conda + sha256: 6914da740f6e3ec44ffb2f687dbc9c33abf084e42f34e3a8bb8235e475850619 + md5: 7a9095c9300d1b50b1785ca9bc4cadae + depends: + - python >=3.10 + - filelock >=3.15.4 + - platformdirs <5,>=4.3.6 + - python + license: MIT + license_family: MIT + size: 35514 + timestamp: 1781257630962 - conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.12-8_cp312.conda build_number: 8 sha256: 80677180dd3c22deb7426ca89d6203f1c7f1f256f2d5a94dc210f6e758229809 @@ -21248,6 +21590,16 @@ packages: license_family: BSD size: 6958 timestamp: 1752805918820 +- conda: https://conda.anaconda.org/conda-forge/noarch/python_abi-3.14-8_cp314.conda + build_number: 8 + sha256: ad6d2e9ac39751cc0529dd1566a26751a0bf2542adb0c232533d32e176e21db5 + md5: 0539938c55b6b1a59b560e843ad864a4 + constrains: + - python 3.14.* *_cp314 + license: BSD-3-Clause + license_family: BSD + size: 6989 + timestamp: 1752805904792 - conda: https://conda.anaconda.org/conda-forge/noarch/rosdistro-1.0.1-pyhd8ed1ab_0.conda sha256: bff3b2fe7afe35125669ffcb7d6153db78070a753e1e4ac3b3d8d198eb6d6982 md5: b7ed380a9088b543e06a4f73985ed03a @@ -21282,6 +21634,15 @@ packages: license_family: MIT size: 787541 timestamp: 1745484086827 +- conda: https://conda.anaconda.org/conda-forge/noarch/setuptools-82.0.1-pyh332efcf_0.conda + sha256: 82088a6e4daa33329a30bc26dc19a98c7c1d3f05c0f73ce9845d4eab4924e9e1 + md5: 8e194e7b992f99a5015edbd4ebd38efd + depends: + - python >=3.10 + license: MIT + license_family: MIT + size: 639697 + timestamp: 1773074868565 - conda: https://conda.anaconda.org/conda-forge/noarch/six-1.17.0-pyhe01879c_1.conda sha256: 458227f759d5e3fcec5d9b7acce54e10c9e1f4f4b7ec978f3bfd54ce4ee9853d md5: 3339e3b65d58accf4ca4fb8748ab16b3 @@ -21381,6 +21742,22 @@ packages: license: LicenseRef-Public-Domain size: 119135 timestamp: 1767016325805 +- conda: https://conda.anaconda.org/conda-forge/noarch/virtualenv-21.4.3-pyhcf101f3_0.conda + sha256: 72ac3da92b6417ad9667009b881ee75e0ca06ef5850f8781df54b27bd6f8be3d + md5: 84270b1d45569be1f9d2c8fe674993a4 + depends: + - python >=3.10 + - distlib >=0.3.7,<1 + - filelock <4,>=3.24.2 + - importlib-metadata >=6.6 + - platformdirs >=3.9.1,<5 + - python-discovery >=1.4.2 + - typing_extensions >=4.13.2 + - python + license: MIT + license_family: MIT + size: 5176090 + timestamp: 1781267575706 - conda: https://conda.anaconda.org/conda-forge/noarch/wayland-protocols-1.47-hd8ed1ab_0.conda sha256: 9ab2c12053ea8984228dd573114ffc6d63df42c501d59fda3bf3aeb1eaa1d23e md5: 7da1571f560d4ba3343f7f4c48a79c76 diff --git a/pixi.toml b/pixi.toml index 3c1b184..19c994f 100644 --- a/pixi.toml +++ b/pixi.toml @@ -73,9 +73,14 @@ ros-jazzy-ament-cmake-gtest = ">=2.5" [feature.dev.dependencies] ros-jazzy-desktop = ">=0.11.0" ros-jazzy-nav2-bringup = ">=1.3.11,<2" +watchexec = ">=2.5,<3" [feature.dev.tasks] rviz = "ros2 launch mote_bringup rviz_launch.py" +# Continuously rsync to the Pi on save (watchexec honours .gitignore, so +# build/install/log/.pixi are skipped). Edits to launch/config/Python go live +# without a rebuild thanks to colcon --symlink-install; only C++ needs `build`. +sync-watch = "watchexec --debounce 1s -- pixi run sync" [feature.sim.tasks] sim = "ros2 launch mote_bringup sim_launch.py"