Stawamus column bench · Order 1

Bench wiring and tests

One column on the TMC5240 dev kit. A NUCLEO-G474RE drives a TMC5240-BOB. The BOB drives one lead-screw column on a wooden jig (or the fully printed stand, step E2). A TBMA732 encoder sits on the motor's rear shaft. Use it for software bring-up, weight tests (including 1.4 vs 2.0 A run current), failure tests and encoder health. Parts and prices: parts list. 3D: jig model.

Read first. Change wiring only with both supply channels off and USB unplugged. Check + and − twice: a reversed rail destroys the capacitors and the BOB. Never connect or disconnect the motor while the BOB is powered. There is no E-stop: the supply's OUTPUT button is the stop, so keep it within reach.

What you have

PartQtyNote
Board
NUCLEO-G474RE1STLINK-V3E on board, USB Micro-B (CN1)
TMC5240-BOB21 + 1 spare. 4.5–36 V, max 2.12 A RMS, SPI only, no bulk capacitor fitted
Watterott 201835 heatsink + Orion OD4010-24HB 24 V fan2 + 2On the BOB above 1.4 A
StarTech USB2CUB1M, USB-C to Micro-B1Nucleo to Mac
SparkFun 12794 M-F jumpers (20 × 150 mm), Sullins jumper shunts1 + 2Logic: 8, female end cut off and soldered into the BOB. Encoder: 6 (step L). The shunts stay unused: the BOB has no pins, L7–L8 get a wire bridge
Adafruit CAN Pal 57082Later (CAN FD), not wired
Power and protection
Lab dual supply (lab's own)1CH2 = motor line, 24–30 V, limit 3 A. CH1 = fan, 24 V / 0.1 A. OUTPUT button = the stop
Fuse 3 A / 58 V MINI (0997003.WXN) + Keystone 3568 holder3 + 1In from the first power
Nichicon UHW1J222MHD, 2200 µF / 63 V2On the rail
Pololu #3777 shunt, 33 V1On the rail, on standoffs
Panasonic EEU-FR1H101, 100 µF / 50 V2At the BOB's R1/R2 + 1 spare
WAGO 221-415 (5-way) / 221-412 (2-way)2 / 4RAIL+ and RAIL− junctions / motor leads
Wire 1.5 mm² red + black, 0.5 mm² red + black, 4 mm banana plugs, 1.5 mm² ferrules, heat-shrink, cable ties—1.5 mm² = supply to rail; 0.5 mm² = soldered to the BOB
Column
17HS16-2004D motor21 + 1 spare. Black + green = coil A, red + blue = coil B
Tr8x12 lead screw, 200 mm, + brass nut21 + 1 spare. 12 mm per turn
Adafruit 1176 coupler 5→8 mm, Olimex KFL08 bearing2 + 21 + 1 spare each
Pololu #2266 bracket + 2 mm shim (local)2 + 1Shim behind the leg
DeoxIT L260 grease1For the brass nut
Printed: shelf_stop, nut_block, tower, platform, peg—docs/print/. Print now
Local: two planks, wood screws, M3 × 25 / M3 × 30 / M4 × 20 + nuts, glue, clamp—Jig stand and tower
No wood: printed stand_base, stand_tube, stand_carrier, stand_post1 eachInstead of the planks, shelf, nut block and tower (step E2). Same column parts; M3 × 6 (Pololu bag), M3 × 25 and M4 × 20 + nuts
Encoder
MPS TBMA732-Q-LT-00A41 + 3 spares. MA732, 3.3 V only, A/B/Z 1,024 ppr out of reset. CN1 / CN2 come fitted: two red 8-way SMD receptacles, wires soldered on their legs (step L)
Radial 9049 magnet, 6 × 2.5 mm N35SH5Diametric, 150 °C max
Printed: encoder_magnet_holder, encoder_mount, encoder_tray1 eachHolder: print now. Mount and tray: after measuring the rear shaft (REAR_SHAFT_MM) and the board thickness (pcb_t), step L
M2.5 × 5 nylon, × 8, × 6; 0.5 mm nylon washers; 28 AWG rainbow ribbon—4 screws each, 10 washers. Encoder leads: 4 ribbon wires + 2 cut M-F jumpers (step L)
Tools and weights
Biltema dial gauge 19-1443 + magnetic stand1On a steel plate ≥ 80 × 80 × 5 mm (local)
Weight discs 2.5 kg / 1.25 kg, kitchen scale 5 kg1 / 2, 1Biltema
From the lab—Meter, scope, soldering iron, crimper, thermocouple or IR thermometer, foam pad, pin or M4 bolt

Wiring

How each wire end is joined:S solder to the pin or padD Dupont: plug onto a pin or into a socket, no solderW WAGO: push in, close the lever (ferrule on 1.5 mm²)B banana plug: soldered on the wire, plugs into the supplyT clamped under the supply's terminalU USB cable· the part's own lead
LAB SUPPLY independent mode CH1 24.0 V · 0.1 A fan only CH2 · motor line 24.0 V / 0.5 A first, then 30.0 V / 3.0 A OVP 35.0 V OUTPUT = the stop + − − + 24 V fan Orion OD4010-24HB aimed at the BOB heatsink 3 A / 58 V fuse, Keystone 3568 RAIL− WAGO 221-415 RAIL+ WAGO 221-415 C1 C2 33 V 33 V shunt C1 C2 2200 µF ← 100 µF / 50 V at the pins NUCLEO-G474RE STLINK-V3E on board CN6-4 3V3 CN6-6 GND D10 PB6 D13 PA5 D11 PA7 D12 PA6 D8 PA9 D7 PA8 A0 / PA0 open: --no-estop DIAG0 PA10, DIAG1 PB5 open CN1 USB (ST-LINK) cut M-F jumpers 3.3 VGNDCSSCK MOSIMISODRV_ENnSLEEPn bridge TMC5240-BOB L1 VCC_IOL2 GNDL3 CSNL4 SCK L5 MOSIL6 MISOL7 GNDL8 CLK L9 DRV_ENnL10 SLEEPn L11 REFLL12 REFR R1 +VMR2 GNDR3 A2R4 A1 R5 B2R6 B1 R10 ENCAR11 ENCBR12 ENCN R7 GNDR8 AINR9 OV TMC5240 heatsink underneath 4 × WAGO 221-412 green Ablack Ablue Bred B 17HS16-2004D A / B / Z, spare GND → R7 TBMA732 CN2.5 ACN2.4 BCN2.6 Z CN1.1 VDDCN1.2 GND CN1.8 TEST ↔ CN1.2 CN7-8 GND CN7-16 3V3 encoder VDD, GND → Nucleo CN7-16, CN7-8 USB-C ↔ Micro-B (CN1) Mac bench CLI · 921,600 baud
CH2 / CH1 + − and GND 3.3 V SPI and enables encoder A/B/Z L7–L8 wire bridge ● joined · gap in a line = crossing, not joined
Everything on the bench in one picture. The 30 V path runs left to right along the top, logic from the Nucleo enters the BOB's left header, and motor and encoder leave its right header. BOB headers: L = left J201, R = right J202, pin 1 at the top. Exact wires and notes for each line: the table below. Where the boards sit around the jig, in 3D: jig model, tab "Wiring".

Build the 30 V rail

RAIL+ and RAIL− are two 5-way WAGO 221-415 lever connectors, not lengths of wire. Nothing is cut or chained: each part sits across the two WAGOs, so everything is in parallel. Only the 3 A fuse is in series, in the CH2 + lead.

RAIL+ · WAGO 221-415 RAIL− · WAGO 221-415 12345 12345 3 A fuse (series) from CH2 + from CH2 − C1C2 ++ −− 33 V +− 0.5 mm² red 0.5 mm² black R1 +VM R2 GND BOB 100 µF soldered on R1 / R2
Openings 1–5 of each WAGO: everything that enters a WAGO is W; soldered joints are S. C1, C2 = 2200 µF / 63 V, striped leg = minus. Opening 5 feeds the BOB; the 100 µF sits on the BOB's own pins.
OpeningRAIL+RAIL−
1Lead from the 3 A fuse (CH2 +)CH2 − lead
2C1 +C1 − (striped leg)
3C2 +C2 − (striped leg)
4Shunt + (VIN)Shunt − (GND)
50.5 mm² red to BOB R1 +VM0.5 mm² black to BOB R2 GND
PartHow
2200 µF capsLegs straight into the WAGOs, not shorter than ≈ 10 mm. Stripe = minus. Reversed, a cap can burst.
33 V shuntOnly + and −. It sits across the rail and clamps above 33 V.
WAGOs10–20 cm from the BOB.
100 µFSoldered directly on the BOB's R1 (+VM) and R2 (GND), stripe to R2, shortest legs, together with the two rail wires.
MotorShort 0.5 mm² wires soldered to R3–R6. Each motor lead joins its wire in a WAGO 221-412: black R4 A1, green R3 A2, red R6 B1, blue R5 B2. Wrong direction: params --set invert_dir_mask=1 (column disabled).
RulesNever plug or unplug the motor with power on. First power at 24 V with the CH2 limit at 0.5 A, then 30 V. Never above 30 V.

Every connection

How each wire end is joined:S solder to the pin or padD Dupont: plug onto a pin or into a socket, no solderW WAGO: push in, close the lever (ferrule on 1.5 mm²)B banana plug: soldered on the wire, plugs into the supplyT clamped under the supply's terminalU USB cable· the part's own lead

The BOB has bare holes: every wire at the BOB is soldered S. Logic leads: an M-F jumper with its female end cut off, D at the Nucleo. Encoder VDD / GND: female end D on the Nucleo's morpho pin.

#FromToHowWireNote
Motor line (CH2)
P1CH2 +Fuse holderB→S1.5 mm² red, red banana plug3 A / 58 V MINI in a Keystone 3568: solder, heat-shrink both pins, tie down. Not a 32 V car fuse.
P2Fuse holder, other pinRAIL+ (WAGO 221-415)S→W1.5 mm² red, ferrule
P3CH2 −RAIL− (WAGO 221-415)B→W1.5 mm² black, black banana plug, ferruleDon't link CH1 − and CH2 − at the supply.
P4C1 +, C2 + / C1 −, C2 −RAIL+ / RAIL−·→WCap legs straight in, ≥ 10 mm2 × 2200 µF / 63 V. Stripe = minus, to RAIL−.
P5Shunt VIN / GNDRAIL+ / RAIL−S→W1.5 mm², shortPololu #3777 on standoffs, away from caps and wood.
P6RAIL+BOB R1 +VMW→S0.5 mm² red, soldered at the BOBNever above 30 V (BOB max 36 V).
P7RAIL−BOB R2 GNDW→S0.5 mm² black, solderedStar point at the BOB. The only other ground is the Nucleo's, through L2.
P8100 µF / 50 VR1 (+) and R2 (−), at the pins·→SSoldered on the pins, shortest legsStripe to R2, together with P6 and P7. The BOB has no bulk cap (C209 not fitted).
Motor (BOB right header)
M1R4 A1Motor blackS→W0.5 mm² soldered at the BOB, WAGO 221-412 to the motor leadCoil A
M2R3 A2Motor greenS→W
M3R6 B1Motor redS→WCoil B. Wrong direction: params --set invert_dir_mask=1, column disabled.
M4R5 B2Motor blueS→W
Logic (Nucleo → BOB left header)
S1CN6-4 3V3L1 VCC_IOD→SM-F jumper, female end cut off: soldered into the BOB hole, male end into the Nucleo
S2CN6-6 GNDL2 GNDD→SLogic ground
S3CN5-3 D10, PB6L3 CSND→SIdle high
S4CN5-6 D13, PA5 (SPI1)L4 SCKD→SAlso drives LED LD2: don't use LD2
S5CN5-4 D11, PA7 (SPI1)L5 MOSID→S
S6CN5-5 D12, PA6 (SPI1)L6 MISOD→S
S7L8 CLKL7 GNDS→SBridge wire (a cut capacitor leg), bottom sideCLK to GND = internal clock. Must not float.
S8CN5-1 D8, PA9L9 DRV_ENnD→SM-F jumper, female end cut off, solderedBOB pull-up: driver off until the MCU drives it low
S9CN9-8 D7, PA8L10 SLEEPnD→SM-F jumper, female end cut off, solderedOptional (BOB pull-up). Low resets every register.
—A0 / PA0, DIAG0 PA10, DIAG1 PB5open——PA0 open reads 'pressed', hence --no-estop. DIAG: the firmware reads the flags over SPI.
—L11 REFL, L12 REFR, R7 GND, R8 AIN, R9 OVopen——Keep free on the Nucleo: PC4/PC5, PB3, PA13/PA14 (SWD), PA11/PA12 (FDCAN1 later).
Encoder (TBMA732 → BOB), fitted in step L
E1CN1.1 VDD (leg)Nucleo CN7-16 3V3S→DM-F jumper (red, black), male end cut off: soldered on the leg, female end on the Nucleo's morpho pinNever 5 V: MA732 abs max 4.6 V. CN7-18, right beside CN7-16, is 5 V. Same net as L1: nothing is cut or soldered at the Nucleo or the BOB.
E2CN1.2 GND (leg)Nucleo CN7-8 GNDS→DSame net as L2
E3CN1.8 TEST (leg)CN1.2 GND (leg)S→S2 cm of white ribbon wire, insulatedMA732 datasheet: connect TEST to ground; the board leaves it open (user guide Fig. 9). Outside legs 4 and 6
E4CN2.5 A (leg)BOB R10 ENCAS→S28 AWG ribbon wire (yellow, green, blue, brown), soldered on the leg and in the BOB hole. The four are twisted together, away from the motor leads1,024 ppr = 4,096 counts/rev out of reset
E5CN2.4 B (leg)BOB R11 ENCBS→S
E6CN2.6 Z (leg)BOB R12 ENCNS→SIndex, once per rev
E7CN1.8 leg (GND through E3)BOB R7 GNDS→SReturn path along A / B / Z. On leg 8 so that no leg takes more than two wires
—CN1.3–1.7 (–, CS, SCLK, MISO, MOSI); CN2.1–2.3 (SSCK, SSD, PWM); CN2.7 MGL, CN2.8 MGHopen——MGL / MGH: meter only, at gap setup (both low at the set gap). Beep check of every used leg: step L
Fan (CH1) and USB
F1CH1 + (24.0 V, limit 0.1 A)Fan redT→·Fan leadOnly for runs above 1.4 A. Never on the 30 V rail (fan max 26.4 V).
F2CH1 −Fan blackT→·Fan lead
U1Nucleo CN1 (Micro-B)MacU→UStarTech USB-C to Micro-BPowers the Nucleo, flashing, serial at 921,600 baud

The stop and the protection

PartSetting or behaviour
StopThe supply's OUTPUT button, within reach of where you stand at the jig. It must switch CH2; if the supply has one button for all outputs, use that.
Over-currentCH2 limit 3.0 A is the first fuse. The 3 A / 58 V fuse protects the wiring if the limit is set wrong.
Over-voltage2 × 2200 µF + 33 V shunt on the rail, 100 µF at the BOB. Supply OVP 35.0 V: above the shunt's 32.0–34.0 V, below the driver's 36 V.
Firmware--no-estop on every command (PA0 not wired). STREAM mode: 200 ms without a frame sends the column to rest height. MANUAL mode (all bench tests): a running move finishes (≤ 120 mm, ≤ 0.6 m/s), then holds. There the button is the only stop.
After a stopThe caps hold R1 up ≈ 0.1 s (estimate). The 10 ms health poll then sees undervoltage, disables the column and drops its reference. To continue: CH2 on, then init, enable, home.
Power orderOn: USB, then CH2. Off: disable, CH2 off, CH1 off, USB last.
Facts the firmware uses
Pin map and limits, from firmware/board/board_g474.h
MCU            STM32G474RE, 24 MHz HSE
SPI1 TMC5240   mode 3, 40-bit, 170 MHz / 32 = 5.3 MHz (/64 if errors)
               SCK PA5, MISO PA6, MOSI PA7, CS PB6
DRV_ENn        PA9, push-pull (BOB pull-up: off until low)
SLEEPn         PA8, held high (low wipes every register)
DIAG0 / DIAG1  PA10 / PB5, internal pull-ups, active low (not used yet)
E-stop         PA0, internal pull-up, high = stop; bench: not wired, --no-estop
Motion         chip ramp in velocity mode follows the 1 ms planner;
               positioning mode at rest; homing with SW_MODE.sg_stop
Microsteps     MRES 64 + intpol = 12,800 per rev (AMAX limit at 256)
Encoder        TBMA732 (MA732) A/B/Z, 1,024 ppr, no SPI or setup
               boots at enc_counts_rev 4096: binary, ENC_CONST 0x00032000
               (3.125); reversed: encoder_invert_mask=1 (0xFFFCE000)
Encoder lag    MA732 8-10 us = about 2 counts at 50 rev/s; ABZ
               hysteresis 0.52 deg = 6 counts (limit below: 41 counts)
Lost steps     ENC_DEVIATION (0x3D) = 128 (2 full steps), ENC_STATUS read
               every 1 ms -> event ENC_DEVIATION
               GCONF.stop_enable = 0 (else ENCA high stops the motor)
Limits         accel <= 7,857 mm/s^2, speed <= 600 mm/s
Current        RREF 12k: max 2.12 A RMS; cap 1.4 A after every boot; watch otpw
Link to Mac    LPUART1 PA2 / PA3 via ST-LINK VCP, 921,600 8N1, 0483:374E
Flash          ST-LINK, app at 0x08000000, no bootloader
Keep free      PA11 / PA12 (FDCAN1), PA13 / PA14 (SWD)

Steps, in order

Firmware: firmware/dist/firmware_nucleo_g474re_cube.bin (STM32Cube build; ping shows a build id ending in -cube). It has run on a bench: boot, the ST-LINK link, SPI-OK, init read-back and 120 mm strokes at 0.8 A. Every command carries --board nucleo-g474re --no-estop: it finds the ST-LINK port at 921,600 baud, and no E-stop is wired. bench = .venv/bin/bench from the repository root (or run source .venv/bin/activate once: then the blocks below paste as they are; it is python -m link, the code in software/link). Details: firmware/README.txt section 12. Ticks stay in this browser.

A

Prepare, everything unpowered

You will: solder S the BOB wires, the 100 µF, the fuse holder, the banana plugs and the shunt leads; crimp ferrules and push into WAGOs W; plug the jumpers' male ends into the Nucleo D. Every wire at the BOB is soldered. Soldering first, plugging last. Beep-check in B before any power.

  1. Motor current never goes through a Dupont. If a logic wire must come off again, cut it and re-solder.
  2. The motor leads are thin: fold the stripped end double, then tug-test.
  3. Series mode shorts a channel. CH2 never above 30 V: the shunt starts at 32.0 V and a voltage held above it destroys it.
B

Meter checks, unpowered

no solderingYou will: beep and measure with the meter. Everything still unpowered.

C

First power at 24 V: flash, ping, registers

no solderingYou will: plug USB U, switch CH2 on, run commands.

D

First spin, motor on the table

no solderingYou will: run commands, motor on the table.

Commands (C and D)
bench --board nucleo-g474re --no-estop ping
bench --board nucleo-g474re --no-estop regs
bench --board nucleo-g474re --no-estop vsupply
bench --board nucleo-g474re --no-estop current 0.8
bench --board nucleo-g474re --no-estop enable
bench --board nucleo-g474re --no-estop spin --revs 1 --rps 1
bench --board nucleo-g474re --no-estop disable
E

Build the column jig

no solderingYou will: screw and glue the jig. To fit the motor, open its four WAGOs W and close them again after.

3D: jig model, tab "Column jig". Print files: docs/print/ (PETG or PLA, 4 walls, 40–60 % infill, no supports). Power off and the motor WAGOs open while you mount it.
No wood? Build the printed stand (E2) instead of E1–E7, then carry on with F.
No weights before the tower and the 30 V checks (H). Travel ≤ 115 mm above home.
E2

Printed stand (no wood)

no solderingYou will: print four parts and bolt the column into them, instead of E1–E7. The heights match the wooden jig, so the coupler, the bearing and step L's encoder parts sit exactly as there.

Print files: docs/print/stand_*.stl, made by make_parts.py, which checks every fit: the motor bolts, the coupler, the screw, the full stroke and the encoder under the motor. PLA or PETG, 0.4 mm nozzle, 0.2–0.28 mm layers, 3 walls, 20–30 % infill, no supports. Every part fits 180 × 180 × 180 mm (Prusa Mini).
PartHow to printMassHours, Mini / MK4
stand_baseUpright, feet on the bed. The motor plate and the top plate print as 43 mm bridges≈ 47 g≈ 4.3 / 2.1
stand_tubeUpright, foot plate on the bed (177 mm tall)≈ 50 g≈ 4.6 / 2.3
stand_carrierFlat, nut traps down, 40 % infill≈ 11 g≈ 1.0 / 0.5
stand_postUpside down, platform on the bed≈ 50 g≈ 4.6 / 2.3
TotalEstimates; the slicer's figure counts≈ 160 g≈ 14.5 / 7

Hardware: the motor, coupler, KFL08, screw and brass nut from E; 4 × M3 × 6 from the Pololu bag (motor); 2 × M4 × 20 + nuts (the KFL08 bolts also clamp the tube to the base); 4 × M3 × 25 low-head + nuts (brass nut to the carrier). No wood, no glue.

How it works: the motor hangs under the base's motor plate, shaft up. The tube stands on the base. The KFL08 sits on the tube's foot plate, under the tube's floor, between two side walls. The square carrier holds the brass nut and slides in the square tube, so it can't turn. At home it sits on the tube's floor, which is the stall stop. The post is a square sleeve with the 100 × 100 mm platform on top. It rests loose on the carrier and goes up and down with it. Boxes go on the platform. The free space under the motor (37 mm, open underneath, the front side open) takes the encoder stack of step L for any rear shaft up to ≈ 20 mm.

  1. Tight: sand the carrier's sides, or reprint it with the slicer's XY compensation at −0.1 mm.
  2. The slots take a bolt spacing of 35.8–38.2 mm.
Travel ≤ 100 mm above home on this stand (G's 115 becomes 100). F's first moves are unchanged. Home is the carrier on the tube's floor. Boxes up to 5 kg, centred on the platform, only after H. On this stand they replace the tower, the peg and the discs of step I (I1, I4).
F

First moves on the jig (24 V, no weights)

no solderingYou will: run commands.

G

Homing

no solderingYou will: run commands.

  1. Runs to the end without stopping ('no_stall') or stops early: sgtune, then params --set sgt_home=… (lower = more sensitive).
Commands (F and G)
bench --board nucleo-g474re --no-estop enable
bench --board nucleo-g474re --no-estop setpos 60
bench --board nucleo-g474re --no-estop move 80 --speed 10
bench --board nucleo-g474re --no-estop move 40 --speed 10
bench --board nucleo-g474re --no-estop params --set tcool_speed_mm_s=15
bench --board nucleo-g474re --no-estop home
bench --board nucleo-g474re --no-estop move 115 --speed 50    # raise slowly
bench --board nucleo-g474re --no-estop move 0 --speed 10
bench --board nucleo-g474re --no-estop disable
H

30 V and the stop, no weights

no solderingYou will: change the supply, measure, press OUTPUT.

Commands (H)
bench --board nucleo-g474re --no-estop init          # CH2 was off: driver re-initialised
bench --board nucleo-g474re --no-estop vsupply
bench --board nucleo-g474re --no-estop enable
bench --board nucleo-g474re --no-estop home
bench --board nucleo-g474re --no-estop move 115 --speed 100
bench --board nucleo-g474re --no-estop move 5 --speed 400     # press OUTPUT mid-move
# after the stop: CH2 on, then
bench --board nucleo-g474re --no-estop init
bench --board nucleo-g474re --no-estop enable
bench --board nucleo-g474re --no-estop home
I

Weight tower, dial gauge, weights

no solderingYou will: assemble the tower, set up the dial gauge, weigh.

3D: jig model, tab "Weights". Load path: weights → tower → nut → screw → KFL08.
LoadTotal moving massRoughly
2.5 N0.32 kgbolts or a water bottle
10 N1.08 kgtower + light load
25 N2.61 kg2 × 1.25 kg discs + tower
40 N4.14 kg2.5 + 1.25 kg discs + tower
J

Weight tests

no solderingYou will: stick on the heatsink; clamp the fan leads under CH1's terminals T; run tests.

Predictions from reports/BENCH_V1/PREDICTIONS.md (archived study: studies/ARCHIVE.md, tag pre-cleanup), made for the TMC2240; the TMC5240 has the same power stage. Cruise ≤ 0.6 m/s, ramp 4 m/s².

TestHowPredictionWrong if
Light loads2.5 N and 10 N: 20 × (lift 0→120, drop, step 60→70) at 0.4 m/sNo lost stepsAny stall flag, or gauge > 0.5 mm off
Timing10 N: full lift and 10 mm step; firmware times + 240 fps video of the rulerLift ≈ 0.4 s, step ≈ 0.1 sLift > 0.5 s or step > 150 ms
Speed vs load25 N and 40 N, cruise 0.1 → 0.6 m/s, 20 clean cycles per speed. Once at 1.4 A, once at 2.0 A (below).2.0 A: 25 N clean to ≈ 0.4 m/s, 40 N to ≈ 0.3 m/s. About half the 40 N lost steps of 1.4 A.2.0 A no better than 1.4 A at 40 N
Motor heat10 min of cycles at 40 N at each current; motor case temperature at the endCopper loss ≈ 4.3 W at 1.4 A, ≈ 8.8 W at 2.0 ACase > 80 °C at 2.0 A
Stall detection20 provoked stalls at 0.4 m/s, then 20 clean cycles at 10 N≤ 2 of 20 missed, no false flagsMore missed, or any false flag (re-tune first)
Return accuracyDial gauge after each block of 20 cyclesWithin 0.5 mm> 0.5 mm (lost steps or slipping coupler)
Friction (optional)Slide test, cardboard box on the woven PTFE fabric, ≈ 5 kg and ≈ 10 kgAs measured at 0–575 g: static 0.23, kinetic 0.16Friction clearly rises with load
Commands (J, at 1.4 A)
bench --board nucleo-g474re --no-estop a1 light     --mass-kg 0.32 --cycles 20   # 2.5 N
bench --board nucleo-g474re --no-estop a1 light     --mass-kg 1.08 --cycles 20   # 10 N
bench --board nucleo-g474re --no-estop a1 timing    --mass-kg 1.08
bench --board nucleo-g474re --no-estop a1 speedload --mass-kg 2.61               # 25 N, 0.1 -> 0.6 m/s
bench --board nucleo-g474re --no-estop a1 speedload --mass-kg 4.14               # 40 N
bench --board nucleo-g474re --no-estop a1 stall     --mass-kg 1.08 --speed 400
bench --board nucleo-g474re --no-estop a1 return    --mass-kg 1.08 --blocks 3

Log moving mass, speed, stall flags, gauge and the scope's rail peak (the tool asks). Keep falls short: a fast-falling load drives the motor as a generator into the shunt. A move runs to its target: OUTPUT is the only stop.

Run current: 1.4 A vs 2.0 A

Decides the production preset: 2.0 A only if it clearly loses fewer steps at 40 N and the case stays ≤ 80 °C. The firmware caps the current at 1.4 A after every boot.

Commands (run current)
# 1.4 A
bench --board nucleo-g474re --no-estop current 1.4 --hold 0.8
bench --board nucleo-g474re --no-estop a1 speedload --mass-kg 2.61 --notes "1.4 A"
bench --board nucleo-g474re --no-estop a1 speedload --mass-kg 4.14 --notes "1.4 A"
bench --board nucleo-g474re --no-estop a1 light --mass-kg 4.14 --speed V --cycles N --yes --notes "1.4 A heat"
bench --board nucleo-g474re --no-estop vsupply
#   V = top clean 40 N speed at 1.4 A (100 if none); N = cycles for 10 min (time 20 first)

# 2.0 A (heatsink and fan on)
bench --board nucleo-g474re --no-estop params --set current_cap_ma=2000
bench --board nucleo-g474re --no-estop current 2.0 --hold 0.8
bench --board nucleo-g474re --no-estop a1 speedload --mass-kg 2.61 --notes "2.0 A"
bench --board nucleo-g474re --no-estop a1 speedload --mass-kg 4.14 --notes "2.0 A"
bench --board nucleo-g474re --no-estop a1 light --mass-kg 4.14 --speed V --cycles N --yes --notes "2.0 A heat"
bench --board nucleo-g474re --no-estop status

# back to the default (current first: the cap can't go below it)
bench --board nucleo-g474re --no-estop current 1.4 --hold 0.8
bench --board nucleo-g474re --no-estop params --set current_cap_ma=1400
K

Failure tests: does a loaded column hold when the motor stops?

no solderingYou will: open and close the four motor WAGOs W; run tests.

Commands (K)
bench --board nucleo-g474re --no-estop move 60 --speed 50
bench --board nucleo-g474re --no-estop disable          # A and B
# C: CH2 off instead; afterwards CH2 on, then
bench --board nucleo-g474re --no-estop init
bench --board nucleo-g474re --no-estop enable
bench --board nucleo-g474re --no-estop home
L

Encoder: lost steps and column health

You will: solder S six wires and the TEST bridge onto the legs of the TBMA732's two red connectors, before the board goes into its tray, then beep every used leg against the MA732 before any power. VDD and GND: M-F jumpers, female end D onto the Nucleo's CN7-16 and CN7-8. A, B, Z and the spare GND: 28 AWG ribbon wires, soldered S into the BOB holes R10, R11, R12 and R7.

The TBMA732 on the rear shaft feeds the BOB's encoder inputs (rows E1–E7). The chip compares it with its own position every 1 ms and raises ENC_DEVIATION at 2 full steps. 3D, step by step: jig model, tab "Encoder". The model still shows bare pads and the old leads; the legs sit on those same pads.

CN1 and CN2 come fitted. Each is a red 8-way SMD receptacle: two staggered rows of contacts at 1.27 mm, 4 gull-wing legs on each side. The user guide lists Würth 690367280876 or TE 7-2178711-8 for this footprint. Red with a pick-up cap points to the Würth part, since the TE part is black. Each leg is soldered on its own pad, so leg n = pin n of the guide's Fig. 12: odd legs on one side, even legs on the other, and pin 1 is the odd leg at the stem end. The loose red pieces were the pick-up caps.

Wires on the legs

  • Ribbon (Assmann AWG28-10/F/300): peel off yellow, green, blue and brown, long enough to reach the BOB with slack (30–60 cm). Also cut 2 cm of white for the bridge. Strip 1.5 mm and tin.
  • Jumpers: 2 M-F, a red and a black if the pack has them. Cut them near the male end so ≈ 14 cm of wire stays on the female end.
  • Solder each wire on top of its leg's foot, where it lies on the pad (figure). Use a fine tip and flux, about 1 s per joint, because the housing is plastic. Each leg takes one wire, except legs 2 and 8 of CN1, which also take the bridge.
  • Inner legs (CN1.1, CN2.4, CN2.6): run the wire up and over the connector, not across the Ø3 hole, because its screw goes in later.
  • Bridge: the white piece from CN1 leg 2 to leg 8, outside the feet of 4 (CS) and 6 (MISO). Twist yellow, green, blue and brown together.

Mount (printed)

  • Print now: encoder_magnet_holder (it doesn't depend on the shaft length).
  • Print after measuring: encoder_mount and encoder_tray (34 × 84.6 × 6 mm, flat, pocket up). Measure the rear shaft (REAR_SHAFT_MM) and the board thickness (pcb_t, 1.6 mm assumed). Set both in print/make_parts.py and run it; it checks the clearances.
  • Magnet into the holder with a drop of superglue, holder on the rear shaft.
  • Mount: 2 × M2.5 × 5 nylon into the 19.05 mm pair. Tray: 2 × M2.5 × 8 from below. Board chip up in the pocket: 2 × M2.5 × 6.
  • Air gap 1.5 mm, magnet to chip (≈ 85 mT, estimate). Each 0.5 mm washer between tray and walls adds 0.5 mm. The connectors stand ≈ 5.3 mm above the board, 38 mm outside the motor, so nothing on the jig comes near them (make_parts.py checks this). Keep 34 mm clear in front of the motor for the connector end and its wires.

S soldered: on the legs, the TEST bridge, and in the BOB holes R7, R10–R12 · D female end onto the Nucleo's CN7-16 / CN7-8, no solder

stem: MA732 at its tip, 57 mm up slot Ø3 1 2 3 4 5 6 7 8 CN1 1 2 3 4 5 6 7 8 CN2 VDD GND – CS SCLK MISO MOSI TEST IO6 IO1 IO5 B A Z MGL MGH VDD → Nucleo CN7-16 3V3 (E1) never CN7-18 beside it: 5 V GND → Nucleo CN7-8 (E2) red / black M-F jumper, female end kept TEST (8) ↔ GND (2): bridge (E3) white, insulated, outside legs 4 and 6 brown leaves from leg 8 (GND via E3) Z → BOB R12 ENCN (E6) B → BOB R11 ENCB (E5) A → BOB R10 ENCA (E4) MGL (7): meter only MGH (8): meter only both low at the set gap spare GND → BOB R7 (E7) yellow, green, blue, brown: twisted gold leg: solder a wire · light ring: meter test point · grey leg: leave free · pin 1 = odd row, stem end Beep targets: MA732 at the stem tip same view, pin-1 dot toward CN2 (check yours) 2 A ← CN2.5 3 Z ← CN2.6 CN1.8 → 10 TEST CN2.7 → 11 MGL 8 GND ← CN1.2 6 B ← CN2.4 13 VDD ← CN1.1 16 MGH ← CN2.8 C1 (0402) under the chip: VDD one end, GND the other
TBMA732 board end from the chip side, stem up, at 20 px per mm. Board and pin positions come from the TBMA user guide Rev 1.2 (Fig. 11, 12, Table 5); the connector comes from the Würth 690367280876 drawing (body 5.2 × 12.16 mm, legs 7.0 mm across). The leg colours show which legs to use. The wire colours are a suggestion; any distinct colours will do if you note them. CN2.1–2.3 are the MA732's SSCK, SSD and PWM, unused here. The inset shows the MA732 pins for the beep check, from the MA732 datasheet's top view (pin 1 at the dot, then anticlockwise).

Beep check, before any power

Use the meter on continuity, with nothing plugged in. Touch each used leg, then the MA732 pin it must reach. The QFN pins are 0.5 mm apart at the chip's edge, so touch the solder fillet at the side with a sharp probe, or a needle held against it. For VDD and GND, the two ends of C1 are easier. The check is meter-only and can't harm the board. If any leg beeps to a different pin than listed, stop and don't power it: the legs are numbered differently from the user guide.

LegWireMust beep toMust stay silent to
CN1.1 VDDred jumper (E1)MA732 pin 13, one end of C1CN1.2: a short chirp is C1 charging, a steady beep is a short
CN1.2 GNDblack jumper (E2), bridgeMA732 pin 8, the other end of C1CN1.1
CN1.8 TESTbridge (E3), brown (E7)MA732 pin 10; CN1.2 once bridgedCN1.1
CN1.4 CS, CN1.6 MISOnone—CN1.2 and CN1.8 (the bridge stays clear of them)
CN2.5 Ayellow (E4)MA732 pin 2CN1.1, CN1.2
CN2.4 Bgreen (E5)MA732 pin 6CN1.1, CN1.2
CN2.6 Zblue (E6)MA732 pin 3CN1.1, CN1.2
CN2.7 MGL, CN2.8 MGHnone (meter points)MA732 pins 11 and 16 (optional)—
Each wire's far endits own legits neighbours in the twist
Option to buy: a plug instead of soldering on the legs

Würth's datasheet for the WR-MM male IDC 690157000872 (8-way, 28 AWG ribbon at 1.27 mm) lists 690367280876 as a mate. Digi-Key 732-1990-5-ND costs $0.90, with a 15-week lead time when checked on 2026-10-17. Digi-Key offers TE 215083-8 (Micro-MaTch male IDC, 28 AWG) as its substitute, with 813 shown in stock the same day. It uses the same Micro-MaTch interface, but no maker's table pairs it with this socket, so dry-fit it unpowered first. One plug per connector, pressed in a vise onto 8 conductors of the same ribbon, conductor 1 on pin 1. TEST to GND then joins conductors 8 and 2 within a few cm of the CN1 plug. Run the same beep check through the plug.

Commands (L)
bench --board nucleo-g474re --no-estop regs
bench --board nucleo-g474re --no-estop disable
bench --board nucleo-g474re --no-estop params --set encoder_mask=1
bench --board nucleo-g474re --no-estop enable
bench --board nucleo-g474re --no-estop home
#   encoder error grows with travel: disable, params --set encoder_invert_mask=1, enable, home
bench --board nucleo-g474re --no-estop testmove stroke --speed 50 --reps 2
bench --board nucleo-g474re --no-estop health-run --db jig.sqlite --encoder
deck-health report --db jig.sqlite

CAN FD bench test

Before Order 2, with what is on the bench: one NUCLEO-G474RE, both CAN Pals from Order 1, no PC adapter. FDCAN1 talks to FDCAN2 over a short real bus, in both directions, with the normal bench image. The BOB stays wired and nothing moves. Command and output: firmware/README.txt.

PartQtyStatus
Adafruit CAN Pal 5708 (TJA1051T/3, 2 × 60 Ω terminator with a switch)2have (Order 1)
120 Ω terminators—not needed: on the CAN Pals (switch ON)
Twisted pair + a ground wire, ≈ 30 cm1have: twist 24 AWG solid wire (Order 2) by hand
Jumpers: 2 M-F, 6 F-F8have (Order 1 M-F, Order 2 F-F)
How each end is joined:D Dupont jumper end on a pin or in a socketT CAN Pal screw terminalU USB cableS only the CAN Pals' headers (step 1)
NUCLEO-G474REbench image, BOB stays wired CN6-2 IOREF 3V3 CN6-7 GND CN10-12 PA12 TX1 CN10-14 PA11 RX1 CN7-12 IOREF 3V3 CN10-20 GND CN10-30 PB13 TX2 CN10-16 PB12 RX2 FDCAN1FDCAN2 CAN Pal A Vcc GND TX RX TJA1051T/3 · SLNT open ONTERM L GND H CAN Pal B Vcc GND TX RX TJA1051T/3 · SLNT open ONTERM H GND L M-FF-F F-F twisted pair + GND, ≈ 30 cm120 Ω at each end: TERM ON on both CAN_L · GND · CAN_H Mac (serial)
CAN_H CAN_L GND 3.3 V TX / RX
Each CAN Pal runs on 3.3 V (it makes its own 5 V for the bus), so its TX / RX are 3.3 V like the Nucleo's. Power comes from the two IOREF pins: on this Nucleo IOREF is 3V3 (solder bridge SB39, on by default), because CN6-4 and CN7-16 already feed the BOB and the encoder.
#FromToHowWireNote
CAN Pal A on FDCAN1
C1Nucleo CN6-2 IOREF (3.3 V)A VccD→DM-F jumper, male in the Nucleo socketIOREF = 3V3 (SB39 on)
C2Nucleo CN6-7 GNDA GNDD→D
C3Nucleo CN10-12 PA12 (FDCAN1 TX)A TXD→DF-F jumperMCU TX → transceiver TXD
C4Nucleo CN10-14 PA11 (FDCAN1 RX)A RXD→DTransceiver RXD → MCU RX
CAN Pal B on FDCAN2
C5Nucleo CN7-12 IOREF (3.3 V)B VccD→DF-F jumper
C6Nucleo CN10-20 GNDB GNDD→D
C7Nucleo CN10-30 PB13 (FDCAN2 TX)B TXD→DFree on the bench
C8Nucleo CN10-16 PB12 (FDCAN2 RX)B RXD→DFree on the bench
The bus
C9A terminal HB terminal HT→TTwisted pair
C10A terminal LB terminal LT→T
C11A terminal GND (middle)B terminal GNDT→TWire along the pairCommon ground
—Both SLNTopen——High = silent. Both TERM switches ON
CAN

Steps

You will: solder the two CAN Pal headers S, plug jumpers D, clamp the bus T, run two commands. No image swap, nothing unplugged at the BOB.

  1. ≈ 120 Ω: one TERM switch is OFF. Open: a broken wire.
  2. On a failure a second line starts likely cause:; the table below says what to check. -v adds the counts per direction.
The test saysCheck
likely cause: no ACKTermination (both switches ON, 60 Ω), 3.3 V on each Vcc, SLNT open
likely cause: bus-offCAN_H / CAN_L swapped at one CAN Pal, or TX / RX swapped (PA12 / PB13 → TX, PA11 / PB12 ← RX)
errors in the data phase onlyTiming or the cable at 4 Mbit/s: a clean --classic pass confirms the wiring
errors in the arbitration phaseWiring: CAN_H / CAN_L, a loose contact, ground, termination
Anything else3.3 V at each Vcc; GND C2, C6, C11; 60 Ω; SLNT not pulled high.
Commands (CAN)
bench --board nucleo-g474re ping                     # the new build
bench --board nucleo-g474re canbus-test              # 1000/1000 ok both ways
bench --board nucleo-g474re canbus-test --classic    # 500k classic only, if FD fails
#   --frames N: a longer or shorter run
# no --no-estop and no disable here: the motor supply can stay off, and --no-estop would
# refuse ("driver not initialised") because it re-arms the driver, which needs motor power

PC-side CAN (talking to the Mac) needs a USB CAN FD adapter: PEAK PCAN-USB FD, or a cheaper candleLight / slcan adapter (being evaluated). Not needed for the single-board pilot, which uses the debug serial port.

HIL test: a whole Tile-20's work on the bench

After the CAN FD test passed, with the same wiring (the BOB, the encoder, both CAN Pals C1–C11). A separate image runs 20 columns: the real motor is column 0, the other 19 are simulated inside the Nucleo, but their SPI traffic really goes out on the buses. The Mac's heights travel over the real CAN bus (FDCAN2 → FDCAN1) among a whole row's traffic, as on the deck. A recorded simulator run drives it. Nothing to wire. Details: firmware/README.txt section 17.

Hand on the supply. The motor follows a busy deck column at up to 400 mm/s over the full 0–120 mm. Free shaft only (nothing on the nut block). Not on the jig until a free-shaft run has passed; then --scale 0.9. Motor supply 29 V, run current 0.8 A first. Keep a hand on the supply's OUTPUT button for every run.
HIL

Steps

You will: flash the HIL image, run 2 minutes, then 30 minutes, then flash the bench image back. Each run ends with HIL PASS or HIL FAIL.

  1. No hardware. It also proves the recording is there (else: hil_replay.py record, about 75 s).
  2. It sets the limits (400 mm/s, 4 m/s²) and 0.8 A, checks 2 s idle (it refuses on any SPI timeout and prints which bus), enables all 20 columns, streams, then prints the report. If the real column strays more than 0.12 mm from its command, the firmware switches its driver off within 20 ms and the run stops.
PASS needsLimit
Planner tick (without the simulated chips' own work)no deadline miss, p99 ≤ 600 µs, max < 1 ms
CAN targets0 lost, 0 duplicates, no bus-off
Real column vs. the firmware's command≤ 0.12 mm (2 full steps), encoder the same
Watchdogs, SPIno trip, no timeout
Commands (HIL)
.venv/bin/python sim/tools/hil_replay.py run --virtual --duration 120        # dry run, no hardware
cp -X firmware/dist/firmware_nucleo_g474re_hil_cube.bin /Volumes/NOD_G474RE/
bench --board nucleo-g474re-hil --no-estop ping                              # -cube-hil, columns 20/20
bench --board nucleo-g474re-hil --no-estop regs --col 0                      # SPI-OK
.venv/bin/python sim/tools/hil_replay.py run --no-estop --current 0.8 --duration 120 --json runs/hil/bench_120s.json
.venv/bin/python sim/tools/hil_replay.py run --no-estop --current 0.8 --duration 1800 --json runs/hil/bench_1800s.json
bench --board nucleo-g474re-hil --no-estop hil                               # the report again, any time
cp -X firmware/dist/firmware_nucleo_g474re_cube.bin /Volumes/NOD_G474RE/    # the bench image back
#   encoder fitted and wired on the BOB: add --real-encoder;  the jig (only after a free-shaft PASS): --scale 0.9

If it fails, the report says where: the tick figures, the CAN counters (check as in the CAN table above), or the real column's error. Keep the --json file and bench ... events.

Order 2 · a separate rig

Joerg's 3x3

NUCLEO-G474RE + 9 × TMC5240-BOB + 9 × 17HS16-2004D + 9 × TBMA732, 48 mm pitch. One SPI bus per row of three, as on the Tile-20. Its own fuses, capacitors, shunt and a wired E-stop. Parts: parts list, Order 2.

Firmware: firmware/dist/firmware_nucleo_g474re_3x3_cube.bin (STM32Cube build). Tested in simulation only (its 1-column twin has run on a bench). Use --board nucleo-g474re-3x3, without --no-estop. Columns 0–8 = A1 A2 A3 B1 B2 B3 C1 C2 C3. It boots with every DRV_ENn high. Every pin below is checked against firmware/board/board_g474.h and UM2505 Table 16.

Wiring

30 V SUPPLY borrowed, ≥ 10 A 30.0 V · limit 8 A OVP 35.0 V first: 24 V / 0.5 A + − F0 10 A P1 coil 1 + · 0 − 2 – 4 6 – 8 K1 · G7L-2A XP STAR+ 2 × WAGO 221-415 STAR− 2 × WAGO 221-415 P2 1 2 33 V 2 × 2200 µF + 33 V shunt P4, P5 P3 link P6 P8 30 V 5 A keep clear signal 3 × ENC 3V3 / GND pins IDC row ±WAGO P7 A1 TMC5240-BOB L R1 R2 8 leads A2 TMC5240-BOB L R1 R2 A3 TMC5240-BOB L R1 R2 ROW A · SPI1 · ribbon A 30 V 5 A keep clear signal 3 × ENC 3V3 / GND pins IDC row ±WAGO P7 B1 TMC5240-BOB L R1 R2 8 leads B2 TMC5240-BOB L R1 R2 B3 TMC5240-BOB L R1 R2 ROW B · SPI2 · ribbon B 30 V 5 A keep clear signal 3 × ENC 3V3 / GND pins IDC row ±WAGO P7 C1 TMC5240-BOB L R1 R2 8 leads C2 TMC5240-BOB L R1 R2 C3 TMC5240-BOB L R1 R2 ROW C · SPI3 · ribbon C P9, P10 NUCLEO-G474RE CN7 / CN10 under the carrier CN1 USB (ST-LINK) CARRIER perfboard on CN7 / CN10 · 10k PA0 → 3V3 build: see Build the perfboards IDC A IDC B IDC C X4 16-way ribbons S1–S16 U1 USB-C ↔ Micro-B Mac bench CLI · 921,600 baud 24 V ADAPTER ≥ 0.75 A, plug-in 24 V− 24 V+ X0 3 × 24 V fan one per row F1 F2 E-STOP NC1 NC2 X1 X2 NC1 → coil + X3 coil − → 24 V− XD X4 NC2 → carrier: PA0 / GND (twisted pair) EVERY COLUMN · the same for A1 … C3 row board leads soldered at both ends TMC5240-BOB L1 VCC_IO R1 +VM L2 GND R2 GND L3 CSN R3 A2 L4 SCK R4 A1 L5 MOSI R5 B2 L6 MISO R6 B1 L7 GND R7 GND L8 CLK R8 AIN L9 DRV_ENn R9 OV L10 SLEEPn R10 ENCA L11 REFL R11 ENCB L12 REFR R12 ENCN D1 D2 D3 D4 D5 D6 D7 D8 bridge D9 DIAG0 → J203-1 (optional) ← row + WAGO (P9) ← row − WAGO (P10) 100 µF (P11) green A black A blue B red B 17HS16-2004D M1–M4, soldered at the BOB TBMA732 CN1.8 GND (E3) E7 CN2.5 A E4 CN2.4 B E5 CN2.6 Z E6 CN1.8 TEST ↔ CN1.2 (E3) CN1.1 VDD CN1.2 GND ENC 3V3 GND E1 VDD, E2 GND → row board ENC pins
30 V / 24 V + − and GND 3.3 V logic encoder A/B/Z 16-way ribbon ● joined · gap in a line = crossing, not joined
The whole rig. 30 V runs from the supply through F0 and K1 to the star point, then one fused branch per row. Each row board takes a ribbon from the carrier and feeds its three BOBs. The dashed box shows one column; all nine are wired the same way. IDs match the tables below. BOB headers: L = left J201, R = right J202, pin 1 at the top.

Build the star point

STAR+ and STAR− are two linked WAGO 221-415 each. The caps and the shunt sit across them in parallel. Only F0, K1 and the row fuses are in series.

STAR+ a STAR+ b STAR− a STAR− b 1122334455 1122334455 from K1 terminal 8 (XP) from supply − (P2) 1 + − 2 + − 2200 µF 33 V VIN GND link (P3) link (P3) row A fuse row A − row B fuse row B − row C fuse row C − P6, 1.5 mm² P8, 1.5 mm² 5: spare
Openings 1–5 of each WAGO. 2200 µF / 63 V: the striped leg is minus. Short 1.5 mm² links join a5 to b1.
OpeningSTAR+ aSTAR+ bSTAR− aSTAR− b
1From K1 terminal 8 (XP)Link from a5Supply − (P2)Link from a5
2Cap 1 +Row A fuse (P6)Cap 1 − (stripe)Row A − WAGO (P8)
3Cap 2 +Row B fuse (P6)Cap 2 − (stripe)Row B − WAGO (P8)
4Shunt VINRow C fuse (P6)Shunt GNDRow C − WAGO (P8)
5Link to b1spareLink to b1spare

Each row has two more WAGO 221-415: row + takes the fuse lead (1) and R1 of BOB 1–3 (2–4); row − takes the STAR− lead (1) and R2 of BOB 1–3 (2–4). Opening 5 is spare. The 24 V side has two more: 24 V+ and 24 V−.

Every connection

How each wire end is joined:S solder to the pin or padD Dupont: plug onto a pin or into a socket, no solderW WAGO: push in, close the lever (ferrule on 1.5 mm²)B banana plug: soldered on the wire, plugs into the supplyT clamped in a screw terminalU USB cableR 6.3 mm receptacle, crimped, pushed on the relay tab· the part's own lead
#FromToHowWireNote
30 V power
P1Supply +F0 holderB→S1.5 mm² red, banana plug10 A / 58 V MINI in a Keystone 3568, soldered and heat-shrunk, tied down
XPF0 outK1 2; K1 4 → K1 6 (link); K1 8 → STAR+ a1S→R1.5 mm², 6.3 mm blue receptaclesBoth relay contacts in series
P2Supply −STAR− a1B→W1.5 mm² black, banana plug, ferrule
P3STAR± a5STAR± b1W→W1.5 mm², shortLinks the two WAGOs of each star
P4Cap 1, cap 2 (2200 µF)STAR+ / STAR− a2, a3·→WLegs straight in, ≥ 10 mmStripe to STAR−
P5Shunt VIN / GNDSTAR+ / STAR− a4S→W1.5 mm², shortPololu #3777 on standoffs, away from the caps
P6STAR+ b2, b3, b4Row A, B, C fuse INW→S1.5 mm² red, soldered to the holder pins5 A MINI, on the row board's 30 V zone
P7Row fuse OUTRow + WAGO 1S→W1.5 mm² red, soldered to the holder pinsNever through perfboard copper
P8STAR− b2, b3, b4Row − WAGO 1W→W1.5 mm² black, ferrule
P9Row + WAGO 2–4R1 +VM of BOB 1–3W→S0.5 mm² red, soldered at the BOB9 wires in all
P10Row − WAGO 2–4R2 GND of BOB 1–3W→S0.5 mm² black, soldered9 wires in all
P11100 µF / 50 VR1 (+) and R2 (−) of each BOB·→SOn the pins, shortest legsStripe to R2, with P9 and P10
E-stop, 24 V, fans
X024 V adapter + / −24 V+ / 24 V− WAGOT→W0.5 mm², barrel-jack terminal
X124 V+ WAGOE-stop NC1W→TE-stop cable, core 14 × 22 AWG cable to the E-stop box
X2E-stop NC1, other sideK1 coil + (terminal 1)T→RE-stop cable, core 2; red 6.3 mm receptacleThe coil has no polarity: call terminal 1 the + side
X3K1 coil − (terminal 0)24 V− WAGOR→W0.5 mm², red 6.3 mm receptacle
XD1N4007 band on coil + (1)anode on coil − (0)R→RLeads crimped in with the coil wiresCoil + is always +24 V
X4E-stop NC2Carrier X4: PA0 (CN7-28) and GNDT→TE-stop cable, cores 3 + 4Dry contact. 10k PA0 to 3V3 is on the carrier
F124 V+ WAGOFan red, × 3W→·Fan leadOne Orion OD4010-24HB per row, only above 1.4 A
F224 V− WAGOFan black, × 3W→·Fan leadNever on the 30 V line (fan max 26.4 V)
U1Nucleo CN1 (Micro-B)MacU→UUSB-C to Micro-BPowers the Nucleo and all 3.3 V logic

Logic: ribbon S1–S16

Ribbon conductor n = IDC pin n at both ends (red stripe = pin 1). On the carrier each Row column is one wire: morpho pin to IDC pin. All buses at 170 MHz / 32 = 5.31 MHz.

#SignalRow A · SPI1Row B · SPI2Row C · SPI3Row board → BOB
S1SCKPA5 · CN10-11PB13 · CN10-30PC10 · CN7-1L4 of all three
S3MISOPA6 · CN10-13PB14 · CN10-28PC11 · CN7-2L6 of all three
S5MOSIPA7 · CN10-15PB15 · CN10-26PC12 · CN7-3L5 of all three
S7CS1PB6 · CN10-17PB12 · CN10-16PD2 · CN7-4BOB 1 L3
S8CS2PB10 · CN10-25PB11 · CN10-18PA15 · CN7-17BOB 2 L3
S9CS3PB4 · CN10-27PB2 · CN10-22PB1 · CN10-24BOB 3 L3
S10EN1 (DRV_ENn)PA9 · CN10-21PB0 · CN7-34PC7 · CN10-19BOB 1 L9
S11EN2PC2 · CN7-35PB7 · CN7-21PC8 · CN10-2BOB 2 L9
S12EN3PC3 · CN7-37PC6 · CN10-4PC9 · CN10-1BOB 3 L9
S13SLEEPnPA8 · CN10-23, to all three headersL10 of all three
S14DIAG0PA10 · CN10-33, to all three headers (optional)J203-1 of all three (optional)
S153V3CN7-16, to all three headersL1 + ENC 3V3 of all three
S2 S4 S6 S16GNDCN7-8 to IDC C, CN10-9 to IDC A, CN10-20 to IDC B (all common on the Nucleo); pins 2-4-6 bridged, 16 wired, on every headerL2 + ENC GND of all three
—E-stopPA0 · CN7-28 to X4, 10k to 3V3; X4 second pole to GND (CN7-20)—

A1 keeps the bench's pins. Keep free: PA2/PA3 (VCP), PA11/PA12 (FDCAN), PA13/PA14 (SWD), PB3, PB8, PC4/PC5, PC13.

#FromToHowWireNote
Row board → each BOB's left-header holes (× 9), soldered at both ends
D1Lead L1 (3V3)L1 VCC_IOS→SF-F jumper half, housing cut off: soldered in the row board and in the BOB hole
D2Lead L2 (GND)L2 GNDS→S
D3Lead L3 (CS1/2/3)L3 CSNS→SIdle high
D4Lead L4 (SCK)L4 SCKS→S
D5Lead L5 (MOSI)L5 MOSIS→S
D6Lead L6 (MISO)L6 MISOS→S
D7Lead L9 (EN1/2/3)L9 DRV_ENnS→SBOB pull-up: off until driven low
D8Lead L10 (SLEEPn)L10 SLEEPnS→SHeld high
D9Lead DG (DIAG0)J203-1 DIAG0S→SOptional; open drain, wire-OR
—L8 CLKL7 GNDS→SBridge wire (a cut capacitor leg), bottom sideInternal clock, on every BOB
Motor (× 9)
M1R4 A1Motor blackS→·Motor lead shortened, soldered into the BOB hole, heat-shrinkCoil A
M2R3 A2Motor greenS→·
M3R6 B1Motor redS→·Coil B. Wrong direction: invert_dir_mask
M4R5 B2Motor blueS→·
Encoder, TBMA732 (× 9): wires on the connector legs, beep check as in step L
E1CN1.1 VDD (leg)Row board ENC 3V3 of its BOBS→DF-F jumper half (300 mm): cut end on the leg, female end on the row board's ENC pinNever 5 V (MA732 max 4.6 V)
E2CN1.2 GND (leg)Row board ENC GNDS→DSame nets as L1 / L2
E3CN1.8 TEST (leg)CN1.2 GND (leg)S→SShort insulated bridgeOutside legs 4 and 6 (CS, MISO)
E4CN2.5 A (leg)BOB R10 ENCAS→SF-F jumper half, housing cut off: soldered on the leg and in the BOB hole; the four twisted together, away from the motor leads4,096 counts/rev out of reset
E5CN2.4 B (leg)BOB R11 ENCBS→S
E6CN2.6 Z (leg)BOB R12 ENCNS→SIndex
E7CN1.8 leg (GND through E3)BOB R7 GNDS→SReturn along A / B / Z
Power, E-stop and why
Supply30 V / ≥ 10 A lab supply (borrow): limit ≈ 8 A, OVP 35.0 V. ≈ 1.8 A at rest at 1.4 A run current, up to ≈ 7 A with all nine moving (estimate).
E-stopNC1 feeds the relay coil: pressed or a broken wire drops K1 and cuts 30 V to all nine BOBs. NC2 pulls PA0 to GND: the firmware latches and drives every DRV_ENn high. Releasing restarts nothing.
Why wired9 pinch points at 48 mm pitch, up to ≈ 77 N per column at 1.4 A (estimate); a borrowed supply's button may be out of reach.
LogicNucleo 3V3 over USB, ≈ 210 mA for 9 encoders, 9 × VCC_IO and the MCU (estimate).
CoolingWatterott heatsink on each BOB, as in step R1. Fans only above 1.4 A.
RibbonThe pre-made 16-way cables in hand are 457 mm. Fold the extra length flat. SCK, MISO and MOSI each run next to a ground.
RelayOmron lists only AC ratings for the G7L (25 A at 220 V AC). Both contacts in series share the 30 V DC break.
EncodersThe boards are 76 mm long: the 8 outer ones point outward, the centre one ≈ 27° off a row axis (≈ 4 mm clearance, estimate; arm_deg 27 for its tray). Joerg checks it on the frame.

Build the perfboards

Two designs: the carrier on the Nucleo, and the row board, built three times. Chip Quik plated boards, true 2.54 mm grid. Holes are named by row letter and column number, e.g. F12. On the carrier the two female headers hang underneath, so their pins are soldered on top; every other joint on both boards is underneath. Wire: 24 AWG solid, insulated. Leads to the BOBs: the 300 mm F-F jumpers cut in half, housing cut off, soldered at both ends (the BOB has bare holes). No crimping.

One board fits CN7 and CN10. UM2505 Fig. 6 puts the outer pin columns of CN7 and CN10 63.50 mm apart (= 25 × 2.54 mm) with the rows level. Step PB3 still dry-fits it before any solder.

Each drawing opens on group 1. Wire it, beep it, then Next. "Top side" shows what you see from above; "Underside" is the board turned over.

filled pad = a pin or wire end is soldered here empty ring = unused hole orange ring = hop hole big dot = wires join here

TOP SIDE · parts and the short hop wires Nucleo edge (below) C EN3: CN10-1, PC9 → hop F27 A MISO: CN10-13, PA6 → hop L27 GND: CN7-8, GND → hop I6 C EN2: CN10-2, PC8 → hop F30 A EN3: CN7-37, PC3 → hop X3 C EN1: CN10-19, PC7 → hop O27 GND: CN7-20, GND → hop O6 GND: CN10-20, GND → hop O30 A CS2: CN10-25, PB10 → hop R27 B MOSI: CN10-26, PB15 → hop R30 C MOSI: CN7-3, PC12 → hop G3 B EN3: CN10-4, PC6 → hop G30 C CS1: CN7-4, PD2 → hop G6 GND: CN10-9, GND → hop J27 B EN2: CN7-21, PB7 → hop P3 3V3: CN7-16, 3V3 → hop M6 A MOSI: CN10-15, PA7 → hop M27 A CS3: CN10-27, PB4 → hop S27 B EN1: CN7-34, PB0 → hop V6 B CS1: CN10-16, PB12 → hop M30 B MISO: CN10-28, PB14 → hop S30 A EN1: CN10-21, PA9 → hop P27 PA0: CN7-28, PA0 → hop S6 B CS3: CN10-22, PB2 → hop P30 DIAG0: CN10-33, PA10 → hop V27 A CS1: CN10-17, PB6 → hop N27 C CS2: CN7-17, PA15 → hop N3 A SCK: CN10-11, PA5 → hop K27 B CS2: CN10-18, PB11 → hop N30 SLEEPn: CN10-23, PA8 → hop Q27 A EN2: CN7-35, PC2 → hop W3 C CS3: CN10-24, PB1 → hop Q30 B SCK: CN10-30, PB13 → hop T30 C SCK: CN7-1, PC10 → hop F3 C MISO: CN7-2, PC11 → hop F6 CN7 CN10 10k X4 IDC A IDC B CN7 socket: plugs onto the Nucleo's left pins (underneath) CN10 socket: plugs onto the Nucleo's right pins (underneath) IDC C: ribbon plug notch ▲ pin 1 IDC A: ribbon plug notch ▲ pin 1 IDC B: ribbon plug notch ▲ pin 1 X4: E-stop hop hole: wire goes through here hop hole: wire goes through here hop hole: wire goes through here hop hole: wire goes through here hop hole: wire goes through here

Work side: underside (the view switches there). On top: only the short hop wires, morpho pin → hop hole.

  1. bare bridge underneath: T34–S34–R34 (IDC B pins 2-4-6)
  2. bare bridge underneath: K23–L23–M23 (IDC A pins 2-4-6)
  3. bare bridge underneath: B10–B11–B12 (IDC C pins 2-4-6)
  4. I5 (CN7-8, GND) → hop I6 → underside → B10 (IDC C pin 2)
  5. underside: B12 (IDC C pin 6) → B17 (IDC C pin 16)
  6. J28 (CN10-9, GND) → hop J27 → underside → K23 (IDC A pin 2)
  7. underside: M23 (IDC A pin 6) → R23 (IDC A pin 16)
  8. O29 (CN10-20, GND) → hop O30 → underside → M34 (IDC B pin 16)
  9. underside: from R35 (joint on the GND wire) → R34 (IDC B pin 6)
  10. O5 (CN7-20, GND) → hop O6 → underside → AA14 (X4 GND)
  11. M5 (CN7-16, 3V3) → hop M6 → underside → C17 (IDC C pin 15)
  12. underside: from I17 (joint on the 3V3 wire) → R24 (IDC A pin 15)
  13. underside: C17 (IDC C pin 15) → M33 (IDC B pin 15)
  14. M5 (CN7-16, 3V3) → hop M6 → underside → AA10 (10k)
  15. S5 (CN7-28, PA0) → hop S6 → underside → AA6 (10k)
  16. underside: from AA7 (joint on the PA0 wire) → AA12 (X4 PA0)

Work side: underside (the view switches there). On top: only the short hop wires, morpho pin → hop hole.

  1. K28 (CN10-11, PA5) → hop K27 → underside → K24 (IDC A pin 1)
  2. L28 (CN10-13, PA6) → hop L27 → underside → L24 (IDC A pin 3)
  3. M28 (CN10-15, PA7) → hop M27 → underside → M24 (IDC A pin 5)
  4. N28 (CN10-17, PB6) → hop N27 → underside → N24 (IDC A pin 7)
  5. R28 (CN10-25, PB10) → hop R27 → underside → N23 (IDC A pin 8)
  6. S28 (CN10-27, PB4) → hop S27 → underside → O24 (IDC A pin 9)
  7. P28 (CN10-21, PA9) → hop P27 → underside → O23 (IDC A pin 10)
  8. W4 (CN7-35, PC2) → hop W3 → underside → P24 (IDC A pin 11)
  9. X4 (CN7-37, PC3) → hop X3 → underside → P23 (IDC A pin 12)

Work side: underside (the view switches there). On top: only the short hop wires, morpho pin → hop hole.

  1. T29 (CN10-30, PB13) → hop T30 → underside → T33 (IDC B pin 1)
  2. S29 (CN10-28, PB14) → hop S30 → underside → S33 (IDC B pin 3)
  3. R29 (CN10-26, PB15) → hop R30 → underside → R33 (IDC B pin 5)
  4. M29 (CN10-16, PB12) → hop M30 → underside → Q33 (IDC B pin 7)
  5. N29 (CN10-18, PB11) → hop N30 → underside → Q34 (IDC B pin 8)
  6. P29 (CN10-22, PB2) → hop P30 → underside → P33 (IDC B pin 9)
  7. V5 (CN7-34, PB0) → hop V6 → underside → P34 (IDC B pin 10)
  8. P4 (CN7-21, PB7) → hop P3 → underside → O33 (IDC B pin 11)
  9. G29 (CN10-4, PC6) → hop G30 → underside → O34 (IDC B pin 12)

Work side: underside (the view switches there). On top: only the short hop wires, morpho pin → hop hole.

  1. F4 (CN7-1, PC10) → hop F3 → underside → C10 (IDC C pin 1)
  2. F5 (CN7-2, PC11) → hop F6 → underside → C11 (IDC C pin 3)
  3. G4 (CN7-3, PC12) → hop G3 → underside → C12 (IDC C pin 5)
  4. G5 (CN7-4, PD2) → hop G6 → underside → C13 (IDC C pin 7)
  5. N4 (CN7-17, PA15) → hop N3 → underside → B13 (IDC C pin 8)
  6. Q29 (CN10-24, PB1) → hop Q30 → underside → C14 (IDC C pin 9)
  7. O28 (CN10-19, PC7) → hop O27 → underside → B14 (IDC C pin 10)
  8. F29 (CN10-2, PC8) → hop F30 → underside → C15 (IDC C pin 11)
  9. F28 (CN10-1, PC9) → hop F27 → underside → B15 (IDC C pin 12)

Work side: underside (the view switches there). On top: only the short hop wires, morpho pin → hop hole.

  1. Q28 (CN10-23, PA8) → hop Q27 → underside → C16 (IDC C pin 13)
  2. Q28 (CN10-23, PA8) → hop Q27 → underside → Q24 (IDC A pin 13)
  3. Q28 (CN10-23, PA8) → hop Q27 → underside → N33 (IDC B pin 13)
  4. V28 (CN10-33, PA10) → hop V27 → underside → B16 (IDC C pin 14)
  5. V28 (CN10-33, PA10) → hop V27 → underside → Q23 (IDC A pin 14)
  6. underside: from Z27 (joint on the DIAG0 wire) → N34 (IDC B pin 14)

All 46 underside wires and 35 hops at once. Use Back to go group by group.

row Arow Brow C3V3GNDSLEEPn, DIAG0PA0
Carrier, 36 × 28 holes: columns 1–36, rows A–AB. Each wire group opens on the side where its wires are. The 2 × 19 female headers hang under the board, so their 38 + 38 pins are soldered on top. The box headers, 10k and X4 sit on top and are soldered underneath. So every morpho signal hops: a short wire on top from the morpho pin to the hole beside it (orange ring), through that hole, then underneath to the IDC pin. Wires between IDC pins stay underneath. The underside view is mirrored, as you see it with the board turned over. Notch on the box headers: the ▲ on the part decides, the notch may sit on either side.

filled pad = a pin or wire end is soldered here empty ring = unused hole big dot = wires join here

TOP SIDE · parts, and the leads coming in fuse holder (30 V zone) 5 A IN, P6 OUT, P7 L1 L2 L3 L4 L5 L6 L9 L10 DG ↓ leads to BOB 1 (A1 / B1 / C1), soldered into its holes ENC: encoder 3V3 · GND L1 L2 L3 L4 L5 L6 L9 L10 DG ↓ leads to BOB 2 (A2 / B2 / C2), soldered into its holes ENC: encoder 3V3 · GND L1 L2 L3 L4 L5 L6 L9 L10 DG ↓ leads to BOB 3 (A3 / B3 / C3), soldered into its holes ENC: encoder 3V3 · GND IDC: ribbon from the carrier plugs in here notch ▲ pin 1

Work side: underside (the view switches there). Every joint on this board is underneath.

  1. bare bridge underneath: B19–B20–B21 (IDC pins 2-4-6, GND). Pin 16 stays free.
  2. 3V3: C26 (IDC pin 15) → lane along row N → Q1 (ENC 1) and S1 (BOB 1 L1), Q11 (ENC 2) and S11 (BOB 2 L1), Q21 (ENC 3) and S21 (BOB 3 L1)
  3. GND: B19 (IDC pin 2, bridged to 4 and 6) over the top edge → lane along row J → Q2 (ENC 1) and S2 (BOB 1 L2), Q12 (ENC 2) and S12 (BOB 2 L2), Q22 (ENC 3) and S22 (BOB 3 L2)

Work side: underside (the view switches there). Every joint on this board is underneath.

  1. SCK: C19 (IDC pin 1) → lane along row L → S4 (BOB 1 L4), S14 (BOB 2 L4), S24 (BOB 3 L4)
  2. MISO: C20 (IDC pin 3) → lane along row P → S6 (BOB 1 L6), S16 (BOB 2 L6), S26 (BOB 3 L6)
  3. MOSI: C21 (IDC pin 5) → lane along row M → S5 (BOB 1 L5), S15 (BOB 2 L5), S25 (BOB 3 L5)

Work side: underside (the view switches there). Every joint on this board is underneath.

  1. CS1: C22 (IDC pin 7) → row I → S3 (BOB 1 L3)
  2. CS3: C23 (IDC pin 9) → straight down → S23 (BOB 3 L3)
  3. EN2: C24 (IDC pin 11) → between rows K and L → S17 (BOB 2 L9)
  4. CS2: B22 (IDC pin 8) over the top edge → between rows J and K → S13 (BOB 2 L3)
  5. EN1: B23 (IDC pin 10) over the top edge → between rows I and J → S7 (BOB 1 L9)
  6. EN3: B24 (IDC pin 12) over the top edge → straight down → S27 (BOB 3 L9)

Work side: underside (the view switches there). Every joint on this board is underneath.

  1. SLEEPn: C25 (IDC pin 13) → lane along row K → S8 (BOB 1 L10), S18 (BOB 2 L10), S28 (BOB 3 L10)
  2. DIAG0: B25 (IDC pin 14) over the top edge → lane along row O → S9 (BOB 1 DG), S19 (BOB 2 DG), S29 (BOB 3 DG)

Work side: underside.

  1. IN: 1.5 mm² from STAR+ (P6), soldered underneath to both pins of the top clip.
  2. OUT: 1.5 mm² to the row + WAGO (P7), soldered to both pins of the bottom clip.
  3. Drill the 4 pin holes 1.6 mm, marked from the holder. Heat-shrink, cable-tie both wires. Nothing else in the 30 V zone.

All 51 wire pieces at once. Use Back to go group by group.

SCK, MISO, MOSICS, EN3V3GNDSLEEPn, DIAG01.5 mm², fuse
Row board, 30 × 20 holes: columns 1–30, rows A–T. Built three times (A, B, C). Each group opens on the underside. Every joint is underneath: the box header, the three ENC headers and the fuse holder sit on top, and the leads come in from the top into row S; their other end is soldered into the BOB. Underneath, each signal runs on its own lane. The 1.5 mm² fuse wires solder to the holder pins, so 5 A never runs through board copper. Pin 16 of the IDC is a spare ground here; 2-4-6 carry it.
PB

Build steps

  1. If the pins don't line up, stop: cut the carrier into two strips, one per header.
  2. Plugged on, the carrier must rest on the morpho headers, not on the Nucleo's Arduino sockets.
3x3

First steps

Commands (3x3)
bench --board nucleo-g474re-3x3 --virtual ping   # dry run, no hardware
bench --board nucleo-g474re-3x3 ping             # columns 9/9
bench --board nucleo-g474re-3x3 regs --col 0     # ... to --col 8
bench --board nucleo-g474re-3x3 params --set encoder_mask=511   # all nine
bench --board nucleo-g474re-3x3 current 0.8
bench --board nucleo-g474re-3x3 enable --col 0   # no --col = all nine
bench --board nucleo-g474re-3x3 home --col 0
bench --board nucleo-g474re-3x3 move 40 --col 0 --speed 100
bench --board nucleo-g474re-3x3 health-run --col 8 --encoder --db rig.sqlite
#   9 columns: keep sample_period_us >= 10000

Next, stage 3: a 10 × 16 validation strip on 8 Tile-20 rev A pilot boards. See the electronics plan, path to production ↗

Check these on your parts