Skip to main content

A unified, dynamic Firmata control library supporting GPIO, I2C, SPI, UART, and CAN-bus on STM32 microcontrollers

Project description

roboreactor-firmata

A unified, dynamic Firmata client library for configuring and controlling GPIO, I2C, SPI, UART, and CAN-bus peripherals on STM32 microcontrollers.

Instead of being limited to hardcoded hardware pins, roboreactor-firmata allows you to dynamically assign peripheral pins at runtime from Python using a custom extended SysEx protocol.


Installation

pip install roboreactor-firmata

Firmware Flashing

Before running the Python client, flash the matching custom .ino sketch located inside the firmware/ directory to your microcontroller:

  • STM32: Flash StandardFirmataCustom_STM32.ino (Requires STM32duino core and optional STM32_CAN library).

Features & Quick Start Examples

1. Analog Input Read (Background Reporting)

Read analog inputs using physical named pins. Register callbacks to receive updates asynchronously.

import time
from roboreactor_firmata import STM32Board

board = STM32Board('/dev/ttyUSB0')

# Configure A0 analog channel on PA0
analog_in = board.get_gpio('PA0', mode='a')

# Callback receives value between 0.0 and 1.0
def analog_callback(value):
    print(f"Analog Read PA0: {value:.3f} | Voltage: {value * 3.3:.2f}V")

analog_in.register_callback(analog_callback)
analog_in.enable_reporting()

# Start messaging loop
board.samplingOn(50)

time.sleep(3)
board.exit()

See examples/analog_read_example.py for the complete runnable script.

2. Servo Motor Control

Configure a physical pin as a servo output to control angular position (0-180 degrees).

import time
from roboreactor_firmata import STM32Board

board = STM32Board('/dev/ttyUSB0')

# Configure PA9 as Servo
servo_out = board.get_gpio('PA9', mode='s')

# Set angles
print("Setting servo to 0 deg")
servo_out.write(0)
time.sleep(1)

print("Setting servo to 90 deg")
servo_out.write(90)
time.sleep(1)

print("Setting servo to 180 deg")
servo_out.write(180)
time.sleep(1)

board.exit()

See examples/servo_control_example.py for the complete runnable script.

3. PWM Output Control

Configure pins for PWM output to write duty cycles between 0.0 (0%) and 1.0 (100%).

import time
from roboreactor_firmata import STM32Board

board = STM32Board('/dev/ttyUSB0')

# Configure PA1 as PWM
pwm_out = board.get_gpio('PA1', mode='p')

# Set PWM duty cycle to 50%
pwm_out.write(0.5)
time.sleep(2)

# Turn off PWM
pwm_out.write(0.0)
board.exit()

See examples/pwm_output_example.py for the complete runnable script.

4. Dynamic I2C Read

Route dynamic SDA/SCL pins and request read bytes from an I2C sensor via a response callback.

import time
from roboreactor_firmata import STM32Board

board = STM32Board('/dev/ttyUSB0')
board.samplingOn(50)

# Configure dynamic SDA/SCL pins
board.configure_custom_i2c(sda_pin="PB9", scl_pin="PB8")
board.i2c_config()

# Define read response callback
def on_i2c_reply(data):
    if len(data) >= 6:
        accel_x = (data[0] << 8) | data[1]
        print(f"MPU6050 Accel X: {accel_x}")

# Read 6 bytes starting from register 0x3B on MPU6050 (0x68)
board.i2c_read(0x68, register=0x3B, num_bytes=6, callback=on_i2c_reply)

time.sleep(2)
board.exit()

See examples/i2c_read_example.py for the complete runnable script.

5. Dynamic I2C Write

Configure dynamic I2C pins and write command configuration bytes to configure an external device or driver register.

import time
from roboreactor_firmata import STM32Board

board = STM32Board('/dev/ttyUSB0')

# Configure dynamic SDA/SCL pins
board.configure_custom_i2c(sda_pin="PB9", scl_pin="PB8")
board.i2c_config()

# Wake up MPU6050 (0x68) by writing 0x00 to Power Management register (0x6B)
board.i2c_write(0x68, register=0x6B, data_bytes=[0x00])

time.sleep(0.5)
board.exit()

See examples/i2c_write_example.py for the complete runnable script.

6. Dynamic SPI Read

Configure dynamic SPI clock, data, and CS pins to perform a read transaction using a response callback.

import time
from roboreactor_firmata import STM32Board

board = STM32Board('/dev/ttyUSB0')
board.samplingOn(50)

# Configure dynamic SPI lines
board.configure_custom_spi(mosi="PA7", miso="PA6", sclk="PA5", cs="PA4")

# Define SPI reply callback
def spi_callback(data):
    print(f"SPI Read Bytes: {list(data)}")

# Transfer JEDEC ID command to read response
board.spi_transfer("PA4", [0x9F, 0x00, 0x00, 0x00], callback=spi_callback)

time.sleep(2)
board.exit()

See examples/spi_read_example.py for the complete runnable script.

7. Dynamic SPI Write

Configure SPI lines and write command or configuration payloads to a device without registering a callback.

import time
from roboreactor_firmata import STM32Board

board = STM32Board('/dev/ttyUSB0')

# Configure dynamic SPI lines
board.configure_custom_spi(mosi="PA7", miso="PA6", sclk="PA5", cs="PA4")

# Write Write Enable (WREN) command (0x06) to SPI flash chip
board.spi_transfer("PA4", [0x06])

time.sleep(0.5)
board.exit()

See examples/spi_write_example.py for the complete runnable script.

8. Dynamic UART Read

Configure dynamic RX/TX pins at a set baudrate, and receive serial streams asynchronously.

import time
from roboreactor_firmata import STM32Board

board = STM32Board('/dev/ttyUSB0')
board.samplingOn(50)

def uart_callback(data):
    print(f"UART Rx: {data}")

# Route RX=PA3, TX=PA2 at 9600 baud
board.configure_custom_uart(rx_pin="PA3", tx_pin="PA2", baudrate=9600, callback=uart_callback)

time.sleep(3)
board.exit()

See examples/uart_read_example.py for the complete runnable script.

9. Dynamic UART Write

Configure dynamic UART pins and write raw serial command packages/data to external devices.

import time
from roboreactor_firmata import STM32Board

board = STM32Board('/dev/ttyUSB0')

# Route RX=PA3, TX=PA2 at 9600 baud
board.configure_custom_uart(rx_pin="PA3", tx_pin="PA2", baudrate=9600)

# Write command string
board.uart_write(b"CMD_SET_SPEED:100\r\n")

board.exit()

See examples/uart_write_example.py for the complete runnable script.

10. Dynamic CAN-Bus Read

Configure dynamic CAN RX/TX pins and handle incoming standard or extended frames via a callback.

import time
from roboreactor_firmata import STM32Board

board = STM32Board('/dev/ttyUSB0')
board.samplingOn(50)

def can_callback(msg_id, payload, is_extended):
    print(f"CAN frame - ID: {hex(msg_id)} | Payload: {payload.hex()}")

# Configure CAN at 500kbps on PB12/PB13
board.configure_custom_can(rx_pin="PB12", tx_pin="PB13", baudrate=500000, callback=can_callback)

time.sleep(3)
board.exit()

See examples/can_read_example.py for the complete runnable script.

11. Dynamic CAN-Bus Write

Configure dynamic CAN pins and transmit standard (11-bit ID) or extended (29-bit ID) frames.

import time
from roboreactor_firmata import STM32Board

board = STM32Board('/dev/ttyUSB0')

# Configure CAN at 500kbps on PB12/PB13
board.configure_custom_can(rx_pin="PB12", tx_pin="PB13", baudrate=500000)

# Send standard CAN frame
board.can_write(msg_id=0x123, data_bytes=[0x01, 0x02, 0x03], is_extended=0)

# Send extended CAN frame
board.can_write(msg_id=0x1F0000, data_bytes=[0xAA, 0xBB, 0xCC], is_extended=1)

board.exit()

See examples/can_write_example.py for the complete runnable script.

12. Custom MCU Pin Mapping

For custom boards not natively supported in pin mappings, you can register and inject a custom virtual pin mapping at initialization.

See examples/custom_mcu_example.py for a complete example showing custom pin maps and simple LED/Servo/Analog callback integration.


---

## License

This project is licensed under the MIT License - see the `LICENSE` file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

roboreactor_firmata-0.1.4.tar.gz (10.5 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

roboreactor_firmata-0.1.4-py3-none-any.whl (9.2 kB view details)

Uploaded Python 3

File details

Details for the file roboreactor_firmata-0.1.4.tar.gz.

File metadata

  • Download URL: roboreactor_firmata-0.1.4.tar.gz
  • Upload date:
  • Size: 10.5 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.10.12

File hashes

Hashes for roboreactor_firmata-0.1.4.tar.gz
Algorithm Hash digest
SHA256 f2d180261445819814d1a1aeb920e203273b07ced42b13952c27763f4fc36eff
MD5 4ed7f04c0793abca7f156d18020a8fd2
BLAKE2b-256 aad7550ca7f8246e9d7b397a4ecfb4465c71b8c8a841b22031b434c21c3c5618

See more details on using hashes here.

File details

Details for the file roboreactor_firmata-0.1.4-py3-none-any.whl.

File metadata

File hashes

Hashes for roboreactor_firmata-0.1.4-py3-none-any.whl
Algorithm Hash digest
SHA256 828f59f4d76f911b67913b2f28a507b4e24d6cee092515ca281c6b0e72865f16
MD5 30352281afef82546f61fb38e0d3c57b
BLAKE2b-256 b72496bfa2b26d41bff6af817e71017c39fbaf5a270a0bb65110e502168dfda1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page