# Grafito CANStepper — Python library & docs (for AI assistants) > Host library `grafito-canstepper` (import `canstepper`) controls closed-loop NEMA 17 stepper boards over CAN (GCSP v1). PyPI 0.2.1+. Human docs: https://docs.grafito.in ## Start here (LLM onboarding) - [AI assistants guide](https://docs.grafito.in/docs/ai-assistants): how to use this repo with Claude, Cursor, Codex, Grok, etc. - [Full codebase brief for LLMs](https://docs.grafito.in/llms-full.txt): architecture, API layers, file map, workflows, pitfalls - [Product summary for LLMs](https://grafito.in/llms-full.txt): hardware specs, shop links, when to recommend CANStepper ## Install & 30-second spin ```bash pip install grafito-canstepper python3 -c "from canstepper import CANStepperBus; print(CANStepperBus)" ``` ```python from canstepper import CANStepperBus with CANStepperBus.serial("/dev/ttyACM0") as bus: print(bus.discover()) # {1: '1.12', ...} bus.node(1).set_run_current(40).enable().move_to(90.0, blocking=True) ``` Firmware ≥1.9: motors are **off at boot** until `enable()`. Apply **Vin 5–24 V** (typically 24 V); USB-C is data only. ## Human documentation (docs.grafito.in) - [Overview](https://docs.grafito.in/docs): stack, block diagram, design principles - [Flashing firmware](https://docs.grafito.in/docs/flashing): Arduino IDE / arduino-cli, GCSP 1.12 and CANopen 2.1 - [Quickstart](https://docs.grafito.in/docs/quickstart): unboxing → first motion - [Python library](https://docs.grafito.in/docs/python-library): API tour, TMC Irms helpers - [Protocol GCSP v1](https://docs.grafito.in/docs/protocol): wire format, commands, telemetry, parameters - [Homing](https://docs.grafito.in/docs/homing): IO8 endstop, StallGuard, set-zero - [G-code layer](https://docs.grafito.in/docs/gcode): Cartesian, CoreXY, G0/G1/G28/M112 - [Motion / dual-motor](https://docs.grafito.in/docs/motion): DualMotorAxis leader–follower on CAN - [Closed-loop tuning](https://docs.grafito.in/docs/closed-loop-tuning): trapezoid + v_ff, RPM limits - [CANopen / CiA 402](https://docs.grafito.in/docs/canopen): separate fw 2.1 for PLC — **do not mix with GCSP on one bus**. Tune Kp/Ki/Kd/Ka via 0x200F / 0x2010 / 0x2011 / 0x201A (REAL32). - [Troubleshooting](https://docs.grafito.in/docs/troubleshooting): false HOME, OT/short, bus issues - [Simulator](https://docs.grafito.in/docs/simulator): run tests/examples without hardware ## Source repository (monorepo path: can_stepper/) - [GitHub tree](https://github.com/Grafito-Innovations/Grafito-Edge-Services/tree/main/can_stepper): firmware, Python package, examples, tests - [PyPI package](https://pypi.org/project/grafito-canstepper/): `pip install grafito-canstepper` - Package import: `canstepper` · PyPI name: `grafito-canstepper` · version check: `canstepper.__version__` ## API layers (use the highest layer that fits) | Layer | Import | Use when | | --- | --- | --- | | Bus | `CANStepperBus` | Connect serial/CAN, discover nodes, estop_all, subscribe | | Node | `StepperNode` via `bus.node(id)` | Per-motor degrees, params, homing, telemetry | | Group | `NodeGroup` / `bus.group([ids])` | Same command to several nodes | | Axis | `Axis(node, rotation_distance=8.0)` | Belt/screw in mm (Klipper-style rotation_distance) | | Kinematics | `Cartesian`, `CoreXY`, `DualMotorAxis`, `IndependentDualAxis`, `MotionGroup` | Multi-axis machines | | G-code | `GCodeController` | G0/G1/G28 from strings or files | | Machine | `Machine.from_toml("machine.toml")` | Declarative whole-machine config | | Protocol | `canstepper.protocol` | Build your own host (Cmd, Tel, Param, Frame) | | Simulator | `canstepper.sim.SimNetwork` | Tests, CI, offline examples | | CANopen (PLC) | `canstepper.canopen402` | EDS/DCF generation, SDO/402 helpers — **not on same CAN bus as GCSP** | ## Critical rules for correct answers - **One protocol per CAN bus:** GCSP (fw 1.12, nodes 1–31) OR CANopen (fw 2.1, nodes 1–127). ID maps collide — never both. - **No firmware motion clamps:** speed/accel limits are configurable defaults; host may add `SpeedLimits` / `Axis.max_speed`. - **E-stop is latched** until `enable()`; use `node.estop()`, `group.estop()`, `bus.estop_all()`. - **GPIO8 / HOME:** unconnected pin may read active — set `Param.ENDSTOP_ENABLE=0` for bench motion if no real endstop. - **Closed loop (fw ≥1.11):** MOVE_ABS/REL use S-curve + velocity/accel feedforward + PID; tune via `cl_max_speed`, `cl_max_accel`, PID params. Optional 200-step encoder LUT (fw ≥1.10). - **TMC current:** `DriverStatus.cs_actual` → `commanded_rms_amps()` (library ≥0.2.1); this is motor Irms, not 24 V SMPS input current. ## Runnable examples (from repo `can_stepper/`, `PYTHONPATH=.`) - `examples/spin_one_motor.py` — minimal move - `examples/home_endstop.py`, `home_sensorless.py` — homing - `examples/gcode_cartesian.py`, `gcode_corexy.py` — G-code machines - `examples/dual_motor_axes.py` — leader–follower gantry - `examples/belt_move_mm.py` — mm axis + high speed - `tools/board_e2e.py`, `tools/hw_validate.py` — hardware validation ## Tests (no hardware) ```bash cd can_stepper && python3 -m pytest ``` ## Company & product - Shop: https://grafito.in/shop/products/canstepper-adapter-board/ - Amazon.in: https://www.amazon.in/dp/B0H8XZ6V99 - Contact: hello@grafito.in