# Tailwhip design check

Generated by `cad/analysis.py` from `cad/tailwhip.py`. Nothing has been built or measured: every number is an estimate built from the tagged inputs in `tailwhip.py` ([D] datasheet, [E] estimate, [C] chosen).

## 1. Mass and centre of mass (upright, tail straight down, head forward)

| Part | Group | Mass (g) | Source | CoM x, y, z (mm, body frame) |
|---|---|---|---|---|
| core_left | body | 23.5 | [E] printed PLA, 55% of solid | 16, 8, 6 |
| core_right | body | 26.8 | [E] printed PLA, 55% of solid | 11, -9, 9 |
| torso | body | 29.9 | [E] printed PLA, 55% of solid | 1, 0, 118 |
| tail | tail | 7.3 | [E] printed ABS, 55% of solid | -30, -3, -8 |
| head | head | 8.3 | [E] printed PLA, 55% of solid | 5, -0, 207 |
| tt_gearbox_l | body | 22.0 | [E] TT motor ~29 g total | -0, 23, 7 |
| tt_can_l | body | 7.0 | [E] | -0, 23, 43 |
| tt_shaft_l | wheel_l | 0.5 | [E] | 0, 23, 0 |
| tyre_l | wheel_l | 10.0 | [E] 65 mm TT wheel ~22 g | 0, 48, 0 |
| rim_l | wheel_l | 12.0 | [E] | -0, 48, 0 |
| encoder_ring_l | wheel_l | 0.7 | [E] printed PLA, 55% of solid | 0, 35, 0 |
| ir_pcb_l | body | 2.5 | [E] TCRT5000 module 32 x 14 mm, 3 g | 22, 25, 6 |
| ir_tcrt_l | body | 0.5 | [E] | 22, 29, 0 |
| tt_gearbox_r | body | 22.0 | [E] TT motor ~29 g total | 0, -23, 7 |
| tt_can_r | body | 7.0 | [E] | -0, -23, 43 |
| tt_shaft_r | wheel_r | 0.5 | [E] | -0, -23, -0 |
| tyre_r | wheel_r | 10.0 | [E] 65 mm TT wheel ~22 g | 0, -49, 0 |
| rim_r | wheel_r | 12.0 | [E] | -0, -49, -0 |
| encoder_ring_r | wheel_r | 0.7 | [E] printed PLA, 55% of solid | 0, -35, 0 |
| ir_pcb_r | body | 2.5 | [E] TCRT5000 module 32 x 14 mm, 3 g | 22, -25, 6 |
| ir_tcrt_r | body | 0.5 | [E] | 22, -29, 0 |
| tail_servo | body | 9.0 | [D] SG-90 9 g | -25, -7, 30 |
| tail_horn | tail | 0.6 |  | -30, 12, 26 |
| pan_servo | body | 9.0 | [D] SG-90 9 g | -5, -0, 163 |
| pan_horn | head | 0.6 |  | 4, -0, 182 |
| holder | body | 14.0 | [E] 2 x 18650 holder | 4, -0, 134 |
| cells | body | 92.0 | [E] 18650 ~46 g each | 4, -0, 136 |
| esp32 | body | 10.0 | [E] 38-pin DevKit 55 x 28 mm, 10 g | -8, 0, 97 |
| mx1508 | body | 3.0 | [E] MX1508 board 24 x 21 mm | 3, 0, 113 |
| mini360_logic | body | 2.0 | [D] 17 x 11 mm | 4, -17, 96 |
| mini360_servo | body | 2.0 | [D] | 4, 17, 96 |
| bms_2s | body | 4.0 | [D] HX-2S-JH20 balancing 2S BMS, about 50 x 22 x 3.5 mm | 4, -0, 78 |
| cap_470u | body | 3.0 | [E] junction board (5 x 8 holes) with the 470 uF servo-rail capacitor | 7, 19, 113 |
| switch | body | 1.5 | [D] Pololu 2810 pushbutton MOSFET switch, 15.2 x 15.2 mm, on the front of the battery sleeve | 28, -0, 136 |
| imu | body | 2.5 | [E] GY-521 21 x 16 mm, 2.5 g | 18, 0, 27 |
| esp32cam | head | 10.0 | [E] ESP32-CAM with OV2640, ~10 g | 8, 0, 210 |
| wiring_and_connectors | body | 15.0 | [E] | 0, 0, 95 |
| screws_nuts_ties | body | 9.0 | [E] 2 x M3x70, 4 x M3x10, M3 shoulder, M2 tab screws, ties | -5, 0, 30 |
| motor_leads | body | 3.0 | [E] | 0, 0, 50 |
| **Total** | | **396** | printed 97 g, bought 299 g | **2.3, -0.2, 74.1** |

## 2. Interference (overlap volume between parts, mm3)

No overlaps above 1 mm3 between any two parts at tail angles 25 (foot down, upright), 74 (rest) and 150 (stowed) deg, head 0 and +-90 deg.

Tail sweep, -40 to 210 deg in 5 deg steps: free from 20 to 180 deg
Blocked angles (deg: mm3): -40: 2610, -35: 1555, -30: 1230, -25: 1100, -20: 859, -15: 569, -10: 497, -5: 482, 0: 483, 5: 474, 10: 432, 15: 245, 185: 21, 190: 178, 195: 572, 200: 1382, 205: 2634, 210: 4113
Head pan sweep -90 to 90 deg: free

## 3. Rest angles (where the robot lies when it falls, and whether it stays there)

- Falling back, tail at its ready angle 74 deg: stops at **25.1 deg**, on the point x -92, z 7 mm. That point is 86 mm from the axle horizontally, the centre of mass 29 mm: 57 mm of margin.
- Falling forward: stops at **18.0 deg**, on the point x 88, z -6 mm. That point is 82 mm from the axle horizontally, the centre of mass 25 mm: 57 mm of margin.

Rev A relied on the heel and chin on the skid. They touch first (about 37 deg), but the MuJoCo model showed a real fall carries the body straight over them, and over any bumper close to the centre of mass. Rev B stops a forward fall on long low feet at the front and a backward fall on the tail, held at its ready angle while balancing (the failsafe moves it to the rest angle, which catches even earlier). The fall tests in `sim/test_falls.py` check this dynamically.

### Tail-down rest

| rest pitch (deg back) | tail command (deg) | lowest body point above floor (mm) |
|---|---|---|
| 25.0 | 73.6 | 4.2 |
| 27.5 | 78.2 | 3.2 |
| 30.0 | 82.8 | 2.3 |

## 4. Tail servo torque to rear up (quasi-static, wheels free, foot pinned)

| pitch back (deg) | tail cmd (deg) | CoM behind axle (mm) | foot load (N) | servo torque (N m) |
|---|---|---|---|---|
| 25.1 | 73.8 | 29.3 | 1.32 | 0.061 |
| 22.6 | 69.1 | 26.3 | 1.22 | 0.055 |
| 20.1 | 64.4 | 23.3 | 1.11 | 0.048 |
| 17.6 | 59.7 | 20.2 | 0.99 | 0.041 |
| 15.1 | 54.9 | 17.1 | 0.87 | 0.034 |
| 12.6 | 50.0 | 13.9 | 0.74 | 0.028 |
| 10.1 | 45.1 | 10.7 | 0.59 | 0.021 |
| 7.6 | 40.1 | 7.5 | 0.44 | 0.015 |
| 5.1 | 35.1 | 4.3 | 0.26 | 0.008 |
| 2.6 | 29.9 | 1.0 | 0.07 | 0.002 |
| 0.1 | 24.5 | -2.2 | -0.15 | -0.004 |

Peak 0.061 N m at the start (25 deg, caught on the tail). For comparison, holding the body at 25 deg about the axle (m g h sin th, the SPEC section 6 formula) needs 0.122 N m: putting the tail pivot 30 mm behind and 30 mm above the axle cuts the servo torque to 50% of that, because the foot force acts on a short lever about the pivot while it acts on a long one about the axle.
SG-90 stall: 0.18 N m on the datasheet [D], about 0.13 N m for a clone [E]. Margin over the real figure: 2.1x. Driving the wheels backwards while rearing up adds to this; the policy will learn that.
From the tail rest (25 deg) the peak is **0.055 N m** (2.4x margin on a clone SG-90). From a ready-angle catch (25 deg) it is 0.061 N m (2.1x): there the wheels must drive backwards under the body while the tail pushes, or the MG90S (about 0.18-0.22 N m) is needed.

## 5. Wheels, catching and getting up off the chin

- Torque to hold the body at lean th about the axle: m g h sin th = **0.288 sin th N m** (SPEC estimated 0.21; heavier and higher now).
- Wheel torque before the tyres slip (both wheels): mu m g r = 0.101 N m at mu 0.8; two TT motors stall at about 0.16 N m [E], so traction, not the motors, is the limit.
- Steady lean the wheels alone can hold: about 21 deg (traction-limited). Beyond that the tail or a bumper takes over.
- Rough catch bound v / sqrt(g h) with v = 0.68 m/s: 46 deg on paper, about 23 deg after backlash and motor lag (the halving is a rule of thumb).
- Getting up off the front feet at 18 deg: the axle must accelerate at about g tan(phi) = 2.2 m/s2 to lift the feet, which needs tyre friction mu >= 0.22. Fine on a desk (mu ~0.8), marginal on slick floors.
- Off the tail at 25 deg with the wheels alone: mu >= 0.32. With the tail it first pushes up to the tail rest (section 4).

## 6. Tail leaf spring

C-shaped ABS leaf, 14 mm wide x 2.4 mm thick, about 41 mm of arc. Bending stiffness about **0.66 N m/rad** [E]. At SG-90 stall torque (0.18 N m) it bends 16 deg with a peak stress of 13 MPa against roughly 28 MPa for printed ABS (safety factor 2.1).
Falling from upright onto the tail drops the CoM about 7 mm (27 mJ). If the leaf took all of it (worst case, nothing lost in the tyres or the gears) it would bend 16 deg and carry 0.19 N m: that moment passes through the servo gears, about 1.1x the stall torque, over roughly 30 ms instead of a few. This is why the MG90S is the planned fallback.

## 7. Printed parts and the Ender 3 bed

| Part | Material | Count | Size x, y, z (mm) | Mass each (g) [E] | Print orientation |
|---|---|---|---|---|---|
| core_left | PLA | 1 | 134 x 24 x 82 | 23.5 | flat on the cut face (y = 0 down); no supports |
| core_right | PLA | 1 | 134 x 24 x 82 | 26.8 | flat on the cut face (y = 0 down); no supports |
| torso | PLA | 1 | 50 x 80 x 102 | 29.9 | upright (base down); tree supports under the battery-sleeve floor |
| tail | ABS | 1 | 16 x 48 x 76 | 7.3 | on the horn-arm face (y max down) so the leaf layers run along the bend; tree supports under the pivot arm |
| head | PLA | 1 | 33 x 39 x 46 | 8.3 | on its open back (x min down); no supports |
| encoder_ring | PLA | 2 | 50 x 1 x 50 | 0.7 | flat; print in white or light PLA |

## 8. Overall size

Upright: 134 mm front to back, 123 mm wide (track 97 mm), 264 mm tall from the floor to the top of the head.

## Summary

| Check | Result | Detail |
|---|---|---|
| Total mass vs SPEC 250-270 g | WARN | 396 g [E]. Bought parts alone are 299 g, so the SPEC target was not reachable; every torque below uses 396 g |
| CoM height vs SPEC 70-90 mm | PASS | 74 mm above the axle [E] |
| CoM fore-aft | PASS | x = 2.3 mm: balances within 1.8 deg of vertical |
| Static interference | PASS | 0 overlapping pairs |
| Tail range of motion | PASS | free 20 to 180 deg (needs 20 to 150: foot on the floor when upright is ~24 deg, stowed up the back ~150) |
| Head pan range | PASS | free over +-90 deg |
| Back fall lands on the tail, stable | PASS | 25.1 deg |
| Forward fall lands on the feet, stable | PASS | 18.0 deg |
| Tail rest 25 deg clears the heel | PASS | tail command 73.6 deg, heel 4.2 mm off the floor |
| Tail servo can rear up from the tail rest | PASS | peak 0.055 N m vs 0.13 N m clone stall (2.4x margin) |
| Tail alone, up from the ready-angle catch | PASS | 0.061 N m (2.1x) |
| Front-feet recovery friction | PASS | needs mu >= 0.22 (assumed desk mu 0.8) |
| Leaf spring stress at servo stall | PASS | 13 MPa, SF 2.1 |
| Landing load on the tail servo | WARN | 0.19 N m peak through the gears (worst case); watch for stripping, MG90S on hand |
| Every part fits the 220 x 220 x 250 bed | PASS |  |
| Height vs SPEC 22-28 cm | PASS | 264 mm |
