Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Python

The Python binding is built on the session facade and exposed as a single machbus.Session class. It wraps the sans-IO Session core, so the Python side drives the node explicitly: stamp inputs against a millisecond clock, advance timers with tick, feed received CAN frames, and drain the outbound frames and application events.

The Python bindings (pyo3, abi3 for Python 3.9+) are compiled into every hosted (std/default) build. Build an importable wheel with make bind-py (maturin build --features pyo3/extension-module).

Constructing a session

import machbus

s = machbus.Session(
    name=machbus.name(0x100, 0x80, True),
    preferred_address=0x80,
    enable_diagnostics=True,
)

Constructor signature:

Session(
    name=0,
    preferred_address=0x80,
    preset=None,                  # "tractor" | "implement" | "diagnostic_node"
    enable_diagnostics=False,
    diagnostics_interval_ms=1000,
    enable_gnss=False,
    enable_implement=False,
    enable_vt_client=False,
    enable_tc_client=False,
)

When preset is set it is plugged first, then the enable_* flags add any extra subsystems on top. Each subsystem type may only be plugged once.

Driving the node

MethodPurpose
start()Begin address claiming.
tick(dt_ms)Advance the clock by dt_ms and tick the session.
now_ms()Current monotonic time cursor, in milliseconds.
run_until_claimed(timeout_ms)Tick in 50 ms steps until claimed; returns the address.
feed(port, can_id, data)Feed one received CAN frame (raw 29-bit id + payload bytes) on port.

With no bus contention the claim completes purely by ticking:

s.start()
addr = s.run_until_claimed(2000)
print(addr, s.claim_state())

Outputs

MethodPurpose
poll_transmit()Next (port, can_id, data) to transmit, or None.
poll_transmit_all()Drain every queued outbound frame as (port, can_id, data) tuples.
poll_event()Next application event as a dict, or None when drained.
drain_events()Drain all queued events as dicts.

Each event dict carries a kind and a sub, plus kind-specific fields. Branch on those:

for (port, can_id, data) in s.poll_transmit_all():
    bus_write(port, can_id, data)

while ev := s.poll_event():
    if ev["kind"] == "diag" and ev["sub"] == "raised":
        print(ev["spn"], ev["fmi"])

Address claim

address(), claim_state() (a string such as "claimed"), and is_claimed().

Raw send

s.send_raw(pgn, data, dst=0xFF, priority=6)

dst is a destination address (0xFF for broadcast), priority is 0..=7.

Diagnostics — ISO 11783-12 (Diagnostics)

diag_raise(spn, fmi), diag_clear(), diag_active_count(), and diag_active() (a list of dicts). Require the diagnostics subsystem.

GNSS — NMEA 2000

gnss_broadcast_position(latitude, longitude, altitude_m=None, speed_mps=None, heading_rad=None), gnss_broadcast_cog_sog(cog_rad, sog_mps), and gnss_latest_position() (a dict or None). Require the GNSS subsystem.

Implement — ISO 11783-7 / ISO 11783-9 (Tractor-implement)

Require the implement subsystem. Hitch and PTO take "front"/"rear"; commands are strings such as "raise", "lower", "engage", "disengage".

MethodPurpose
imp_command_hitch(hitch, command)Front/rear hitch command.
imp_command_pto(pto, command)Front/rear PTO command.
imp_command_pto_speed(pto, rpm, ramp_rate)PTO target speed with a ramp rate.
imp_command_aux_valve(valve_index, command, flow_rate)Auxiliary valve command.

VT client — ISO 11783-6 (Virtual Terminal)

Require the VT client subsystem.

MethodPurpose
vt_connect_to(server)Connect to a VT server address.
vt_is_connected()Whether the client is connected.
vt_state()Connection state as a string.
vt_show(object_id) / vt_hide(object_id)Show/hide an object.
vt_set_value(object_id, value)Set a numeric value.
vt_set_string(object_id, value)Set a string value.
vt_change_active_mask(ws, mask)Change the active mask of a working set.

TC client — ISO 11783-10 (Task Controller)

Require the TC client subsystem: tc_connect(), tc_disconnect(), tc_is_connected(), tc_state() (a string), and tc_address().

Module functions

FunctionPurpose
machbus.name(identity_number, function_code, self_configurable=True)Build a J1939/ISOBUS NAME, returns the raw 64-bit value.
machbus.validate_can_bus_config(...)Returns a dict of per-field and overall checks.
machbus.enforce_iso_can_config(...)Raises if the config is not ISO-conformant.