Rayforge Driver Development Guide¶
This guide provides a high-level overview of how to create a driver in Rayforge to add support for your laser cutter or engraver. By creating a driver, you integrate your machine's unique communication protocol and command language into the Rayforge ecosystem.
Driver Overview¶
A driver is the bridge between Rayforge's core logic and your physical hardware. It is responsible for three main tasks:
- Managing Connectivity: Handling the low-level communication protocol (Serial, WebSocket, HTTP, etc.).
- Translating and Executing Jobs: Converting Rayforge's internal representation of a job (
Ops
) into machine-specific commands (like G-code) and sending them to the device. - Reporting State: Emitting signals to update the UI with the laser's real-time position, status (
IDLE
,RUN
), and log messages.
To simplify this, Rayforge provides an architecture based on composable parts:
graph TD;
subgraph Your Driver Implementation
Driver-->Transport;
Driver-->OpsEncoder;
end
subgraph Rayforge Core
OpsProducer --> Ops;
end
Ops --> Driver;
Transport --> Device[Physical Laser];
OpsEncoder
: TranslatesOps
into a specific command language (e.g., G-code).Transport
: Manages the connection and data transfer.Driver
: Orchestrates the process, handles device state, and communicates with the UI.
All driver operations are asynchronous to ensure the user interface remains responsive.
The Ops
Language¶
Rayforge describes a laser job as a sequence of high-level operations, stored in an Ops
object. This is the universal language within Rayforge for describing machine movements, independent of any specific hardware.
Ops Method |
Signature | Description |
---|---|---|
move_to |
(x, y, z=0.0) |
Rapid movement (no cutting) |
line_to |
(x, y, z=0.0) |
Cutting/Engraving movement |
arc_to |
(x, y, i, j, cw=True, z=0.0) |
Cutting/Engraving arc movement |
set_power |
(power) |
Set laser power (0-100%) |
set_cut_speed |
(speed) |
Set speed for cutting moves (mm/min) |
set_travel_speed |
(speed) |
Set speed for rapid moves (mm/min) |
enable_air_assist |
() |
Turn on air assist |
disable_air_assist |
() |
Turn off air assist |
Your driver receives an Ops
object and must execute these operations on the device. Typically, this is done by passing the Ops
object to an OpsEncoder
.
# Example of how Rayforge builds an Ops object
ops = Ops()
ops.set_travel_speed(3000)
ops.set_cut_speed(800)
ops.set_power(80)
ops.move_to(10, 10) # Rapid move to start point
ops.enable_air_assist()
ops.line_to(50, 10) # Cut a line with air assist
ops.disable_air_assist()
ops.line_to(50, 50) # Cut a line without air assist
Driver Implementation¶
All drivers MUST inherit from rayforge.machine.drivers.Driver
.
from rayforge.machine.driver.driver import Driver
class YourDriver(Driver):
label = "Your Device" # Display name in the UI
subtitle = "Description for users"
supports_settings = False # Set True if the driver can read/write firmware settings
Required Properties¶
label
: A human-readable name shown in the UI.subtitle
: A brief description shown below the name.supports_settings
: A boolean indicating if the driver can read/write device settings (like GRBL's$$
).
Required Methods¶
Your driver class MUST implement the following methods. Note that most are asynchronous and must be defined with async def
.
Configuration and Lifecycle¶
get_setup_vars() -> VarSet
: (Class Method) Returns aVarSet
object defining the parameters needed for connection (e.g., IP address, serial port). Rayforge uses this to automatically generate the setup form in the UI.precheck(**kwargs)
: (Class Method) A non-blocking, static check of the configuration that can be run before driver instantiation. Should raiseDriverPrecheckError
on failure.setup(**kwargs)
: Called once with the values from the setup form. Use this to initialize your transports and internal state.async def connect()
: Establishes and maintains a persistent connection to the device. This method should contain auto-reconnection logic.async def cleanup()
: Called when disconnecting. Should close all connections and release resources.
Device Control¶
async def run(ops: Ops, machine: Machine, doc: Doc)
: The core method for executing a job. Here, you'll use anOpsEncoder
to convert theops
object into commands and send them to the device.async def home(axes: Optional[Axis] = None)
: Homes the machine. Can home specific axes or all axes.async def move_to(pos_x: float, pos_y: float)
: Manually moves the laser head to a specific XY coordinate.async def set_hold(hold: bool = True)
: Pauses or resumes the current job.async def cancel()
: Stops the current job.async def jog(axis: Axis, distance: float, speed: int)
: Jogs the machine along a specific axis.async def select_tool(tool_number: int)
: Selects a new tool/laser head by its number.async def clear_alarm()
: Clears any active alarm state.
Firmware Settings (if supports_settings
is True
)¶
get_setting_vars() -> List[VarSet]
: ReturnsVarSet
objects that define the structure of the device's settings page.async def read_settings()
: Reads all settings from the device and calls_on_settings_read()
with the result.async def write_setting(key: str, value: Any)
: Writes a single setting to the device.
Emitting Signals¶
To communicate with the UI, your driver must emit signals. To ensure proper logging and thread safety, you must not emit signals directly. Instead, call the protected helper methods from the base Driver
class.
self._log(message)
: Sends a log message to the console.self._on_state_changed()
: Call this whenever you updateself.state
to notify the UI of a status or position change.self._on_connection_status_changed(status, message)
: Informs the UI about the connection status (CONNECTING
,CONNECTED
,ERROR
, etc.).self._on_command_status_changed(status, message)
: Reports the status of a sent command.self._on_settings_read(settings)
: Sends the device settings you've read back to the UI.
Have Questions?¶
The best way to learn is to look at the existing drivers in rayforge/machine/driver/
, such as:
grbl.py
- GRBL-based machinesgrbl_serial.py
- Serial-based GRBL communicationsmoothie.py
- Smoothieboard-based machinesdummy.py
- A test driver for development
If you get stuck, please don't hesitate to open an issue on GitHub! We're happy to help.