Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down
79 changes: 79 additions & 0 deletions design/ASSEMBLY.md
Original file line number Diff line number Diff line change
@@ -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).
5 changes: 5 additions & 0 deletions design/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
80 changes: 80 additions & 0 deletions design/WIRING.md
Original file line number Diff line number Diff line change
@@ -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<br/>Servo Driver Board"]
BANK -->|"Out2 · USB-C to USB-C · 5V"| PI["Raspberry Pi 5"]

MCB ==>|"3-pin bus: 5V + serial"| SL["Left STS3215<br/>ID 7, inverted"]
MCB ==>|"3-pin bus: 5V + serial"| SR["Right STS3215<br/>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<br/>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 |
Loading
Loading