# AK 2.0 and manual v1.0.18 This library targets the **AK-DRV-V2.1** driver and *AK Series Module Driver Manual* **v1.0.18** (2026-01-19). Most existing Python libraries were written against AK 1.0-era firmware and an older manual. ## What changed that matters **New motors.** v1.0.17 added AK45-36, AK45-10 and **AK40-10**; v1.0.18 corrected the AK45-10 parameters. Libraries predating these simply do not have the field ranges. **A new fault code.** Code 7 is motor stall. Code 6 is MOSFET over-temperature — older libraries label it "phase current unbalance", which is wrong. Indexing a 0–6 dict with a 7 raises `KeyError`, and in the reference library that happens inside the receive thread where it is swallowed. **Corrected position-velocity scaling.** v1.0.12 fixed the byte-order description and v1.0.14 corrected the origin-mode and position-velocity routines. The CAN `SET_POS_SPD` packet divides speed *and* acceleration by 10 before packing them as `int16`. **Permanent zero is dual-encoder only.** v1.0.15 spelled this out. Origin mode 1 writes flash; on a single-encoder model such as the AK40-10 it is meaningless. **Two fault tables, not one.** CAN feedback uses codes 0–7. The serial `GET_VALUES` reply uses `mc_fault_code`, where 1 is over-voltage and the range runs to 18. They are not interchangeable. ## Protocol facts worth having in one place MIT command — **standard** frame, arbitration id = motor id, DLC 8: ``` D0 = p>>8 D1 = p & 0xFF D2 = v>>4 D3 = (v & 0xF)<<4 | kp>>8 D4 = kp & 0xFF D5 = kd>>4 D6 = (kd & 0xF)<<4 | t>>8 D7 = t & 0xFF ``` MIT reply — standard frame, DLC 8: `D0` driver id, `D1..D2` position (16 bit), `D3`+`D4` high nibble velocity (12 bit), `D4` low nibble +`D5` torque (12 bit), `D6` temperature + 40, `D7` fault. Special MIT payloads: enter `FF×7,FC`, exit `FF×7,FD`, zero `FF×7,FE`. Servo — **extended** frame, `arbitration_id = (packet_id << 8) | motor_id`: | Packet | id | Payload | Scale | |---|---|---|---| | SET_DUTY | 0 | int32 | duty × 1e5 | | SET_CURRENT | 1 | int32 | A × 1000 | | SET_CURRENT_BRAKE | 2 | int32 | A × 1000, ≥ 0 | | SET_RPM | 3 | int32 | raw ERPM | | SET_POS | 4 | int32 | **deg × 1e4** | | SET_ORIGIN | 5 | uint8 | 0 temporary, 1 permanent | | SET_POS_SPD | 6 | int32 + int16 + int16 | deg × 1e4; **spd/10**; **acc/10** | | SET_MIT | 8 | undocumented | in the enum, no payload given — not implemented | Servo replies, by function id `(arb_id >> 8) & 0xFF`: | id | meaning | |---|---| | `0x29` | state | | `0x2C` | entered servo mode, payload `FA FB FC FD` | | `0x09` | jump to bootloader | Only `0x29` is state. Decoding `0x2C` as a position yields a plausible-looking −128.5°. ## The float↔uint asymmetry The manual's `float_to_uint` uses `(1<