Skip to main content

Grafito CANStepper

Grafito CANStepper

Closed-loop stepper motor control over CAN. Each board carries an ESP32-C3, a TMC2209 driver, an MT6701 14-bit magnetic encoder and a CAN transceiver; up to 31 boards daisy-chain on one 1 Mbps bus and are driven from Python through the USB port of any board on the chain.

├── canstepper/                              # Python package (grafito-canstepper)
├── firmware/GrafitoCANStepper_C3/           # node firmware (GCSP v1, fw 1.9)
├── firmware/GrafitoCANStepper_C3_CANopen/   # optional CiA 301/402 SKU (fw 2.0)
├── examples/                                # runnable examples + machine.toml
├── tests/                                   # pytest suite (runs on a software sim)
├── model_assets/                            # assembly render, PCB drawing, STEP CAD
└── docs/                                    # protocol, quickstart, CAD index

CAD and brochure files in this repo (model_assets/):

File Description
CANStepper.png Product photo (also at repo root)
CANStepper_pinout.png Connector / pinout diagram
CANStepper_multiaxis_can.png Multi-axis CAN bus demonstration
CANStepper_V1_assembly.mp4 V1 board assembly video (historical)
CANStepper_V1_assembly_preview.jpg Preview frame for the V1 video
CANStepper_test_station.png Board Test Station (after USB connect)
CANStepper_block_diagram.png System block diagram
CANStepper_V2_Assembly.webp V2 assembly render
Drawing_CANStepper_V2.pdf V2 PCB mechanical drawing
CANStepperV2_3D_PCB.step V2 PCB STEP
CASING_MOUNT.step Casing / mount STEP
Heat_Spreader.step Heat spreader STEP
TMC2209 UART Stepper Driver - Heat_Sink.step TMC2209 heatsink STEP
canstepper-brochure-v2.pdf Product brochure
CANStepper pinout CAN bus multi-axis demonstration

V1 board assembly (click the preview to play the video):

V1 board assembly

This clip is version 1 of the same board. V1 used three different connector types, which made cabling and crimping difficult. The current production board is V2, with JST 2.0 connectors throughout for easy crimping.

Important — encoder magnet: Fit a diametrical magnet on the motor shaft. The magnet polarity must be radial, not axial. An axial magnet will not produce a valid MT6701 angle and closed-loop control will fail.

After USB and Vin are connected, test the board in the CANStepper Test Station — set the node ID, enable the driver, jog, and check encoder / TMC / CAN telemetry.

CANStepper Test Station

Highlights

  • Layered Python API — raw frames → StepperNode → NodeGroup → Axis (mm units via rotation_distance) → DualMotorAxis / IndependentDualAxis / Cartesian / CoreXY / MotionGroup → declarative machine.toml.
  • Safety scopes — node.estop(), group.estop(), bus.estop_all() (single broadcast frame); e-stop is latched until re-enabled.
  • Homing — physical endstop on IO8, sensorless (StallGuard), or set-zero; configurable current, backoff and timeout.
  • Closed loop — firmware ≥1.2 plans a rest-to-rest trapezoidal trajectory with velocity feedforward and a light tracking PID on the MT6701 encoder (settle + stall watchdog). All motion limits are configurable defaults, never hard clamps.
  • On-bus leader/follower — dual-motor gantries stay coupled with no host in the loop (DualMotorAxis).
  • Encoder-gated dual screws — IndependentDualAxis commands both motors independently and blocks the next pass until both encoders are within mm tolerance of the target.
  • Simulator included — canstepper.sim.SimNetwork implements the whole protocol in software; the test suite and the examples run without hardware.

Install & first spin

pip install grafito-canstepper

# Development (from this directory):
# pip install -U pip setuptools && pip install -e ".[dev]"
from canstepper import CANStepperBus

with CANStepperBus.serial("/dev/ttyACM0") as bus:
    print(bus.discover())
    node = bus.node(1)
    node.set_run_current(40).enable()
    node.move_to(360.0, blocking=True)

Continue with:

G-code examples (from this directory):

PYTHONPATH=. python3 examples/gcode_cartesian.py /dev/ttyACM0 1 2
PYTHONPATH=. python3 examples/gcode_corexy.py /dev/ttyACM0 1 2
PYTHONPATH=. python3 examples/gcode_from_file.py examples/gcode/square.gcode

Homing examples (IO8 endstop, StallGuard sensorless, set-zero):

PYTHONPATH=. python3 examples/home_endstop.py /dev/ttyACM0 1 -1
PYTHONPATH=. python3 examples/home_sensorless.py /dev/ttyACM0 1 -1 60
PYTHONPATH=. python3 examples/home_set_zero.py /dev/ttyACM0 1

Belt axis (mm):

PYTHONPATH=. python3 examples/belt_move_mm.py /dev/ttyACM0 1 50 77.2 150

Development

python3 -m pytest

Current GCSP firmware is 1.9 (motors off at boot until enable()). Optional CANopen 2.0 (EDS/DCF for PLC) lives in firmware/GrafitoCANStepper_C3_CANopen/ — see https://docs.grafito.in/docs/canopen. Do not mix GCSP and CANopen on one bus.

Firmware builds with Arduino IDE or arduino-cli (ESP32C3 Dev Module, USB CDC On Boot = Enabled; libraries: FastAccelStepper, TMC2209 janelia-arduino). Apply Vin (5–24 V, typically 24 V) before upload — USB-C is data only and does not power the ESP32 for programming. CAN termination is on by default (0 Ω jumper); remove that 0 Ω on mid-chain daisy-chain nodes.

arduino-cli compile --fqbn esp32:esp32:esp32c3:CDCOnBoot=cdc \
  firmware/GrafitoCANStepper_C3
arduino-cli upload -p /dev/ttyACM0 --fqbn esp32:esp32:esp32c3:CDCOnBoot=cdc \
  firmware/GrafitoCANStepper_C3

Metadata

Release files for grafito-canstepper 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for grafito-canstepper 0.2.2
File Size Uploaded
grafito_canstepper-0.2.2.tar.gz 84.1 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for grafito-canstepper 0.2.2
File Interpreter ABI Platform
grafito_canstepper-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 160.9 kB

Release files / grafito_canstepper-0.2.2.tar.gz

Download URL grafito_canstepper-0.2.2.tar.gz
Size 84.1 kB
Tags Source
SHA-256 checksum
How to use checksums
0698ecccacc522c9cf8cc54f784532b8760c62f7c02e59295d2d5c320d97dad2
BLAKE2b-256 checksum
How to use checksums
3a60d169dd4c91a682061def6a1208d2e0cd59e2744a8d385b4a47c60dd5094b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release files / grafito_canstepper-0.2.2-py3-none-any.whl

Download URL grafito_canstepper-0.2.2-py3-none-any.whl
Size 76.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
7b1b4f5e5ba388dab8eb69e94a7c7ee525c67e9c4ee9d3719b128eee9348f7ee
BLAKE2b-256 checksum
How to use checksums
605c08b66908f8ea038d6799a25a669bdf2a60a38ceec3e7a745769f94044c24
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.10.12

Release history Release notifications | RSS feed

0.2.3

2 release files

This release

0.2.2 This release

2 release files

0.2.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page