Skip to content

About

MicroPython and MicroBlocks API for the line sensor

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

93 Commits

Folders and files

Repository files navigation

lms line sensor logo

LMS Line Sensor

Drivers, firmware, and tools for the LMS Line Sensor — an 8-channel reflectance board for LEGO SPIKE, Robot Inventor, Technic, and EV3 with Pybricks, MicroPython, or MicroBlocks.

1. Flash the sensor (firmware 5.6)

Current UF2: firmware/firmware_ch32_line_i2c_ur_v5.6.uf2

  1. Connect the line sensor to your PC with USB.
  2. Press RESET twice quickly until a CH32V UF2 drive appears.
  3. Drag the UF2 onto that drive and wait for it to disappear.
  4. If the NeoPixels do not scan, unplug and replug USB.

Full hardware notes: firmware/README.md.

2. Pick a connection path

Goal Path Start here
Configure / calibrate / watch values on a PC USB → web dashboard linesensor.antonsmindstorms.com or web/
Script the sensor from a PC USB → desktop Python usb/
Hub wired straight to the sensor UART uRemote → Pybricks examples/spike-direct/
Sensor on Qwiic, hub talks to LMS-ESP32 Hub → LineSensorUR → LMS-ESP32 LineSensorURServer → I2C examples/lms-esp32-ur-server/
MicroPython on LMS-ESP32 only (no hub RPC) I2C → LineSensorI2C micropython/
Blocks programming MicroBlocks library microblocks/

Approximate read timing (8 sensor values)

Measured cycle times for reading eight channels (indicative; wiring and hub load vary):

Setup ~cycle
LMS-ESP32 I2C @ 400 kHz 1.3 ms
USB → PC (uRemote) 1.5 ms
LMS-ESP32 I2C @ 100 kHz 2.3 ms
EV3 UART (direct) 4 ms (sensors() ~5.2 ms; that call reads 13 bytes)
SPIKE Prime UART (direct) 8.2 ms
EV3 I2C 10 ms
Prime ← LMS-ESP32 LineSensorURServer (uRemote) ← I2C 14 ms

PUPRemote note: Prime ← PUPRemote ← LMS-ESP32 I2C can look like ~2.5 ms per hub poll, while the ESP32 side takes ~5 ms to push a new sample. The hub therefore often re-reads the same values before they update.

Most of the I2C vs uRemote gap is framing overhead: uRemote sends about 33 bytes on the wire for 13 payload bytes; plain I2C and a PUPRemote 8B channel do not add that framing.

Installation

Web dashboard

Open linesensor.antonsmindstorms.com in Chrome or Edge (Web Serial). Close any other app using the USB serial port first. See web/README.md.

USB desktop Python

cd usb
python -m pip install -r requirements.txt
python read_line_sensor.py

Pybricks (direct UART or via LMS-ESP32)

Upload micropython/line_sensor_pybricks.py into your Pybricks project.

MicroPython on LMS-ESP32

On current LMS-ESP32 firmware the line sensor driver is often pre-installed. Otherwise install with ViperIDE:

  1. Open ViperIDE → package manager → custom package.
  2. Paste https://github.com/antonsmindstorms/lms-line-sensor.git and install.

For hub ↔ ESP32 ↔ I2C sensor, also copy micropython/line_sensor_ur_server.py (uremote is frozen on current LMS-ESP32 firmware).

MicroBlocks

Open the MicroBlocks editor and drag microblocks/LMS Line Sensor.ubl into the window.

Quick start

MicroPython via I2C (LMS-ESP32)

from time import sleep
from line_sensor import LineSensorI2C

sensor = LineSensorI2C(scl_pin=4, sda_pin=5, device_addr=51)

sensor.ir_power(True)
sensor.load_calibration()
sensor.mode_calibrated()

while True:
    print(sensor.position(), sensor.derivative(), sensor.shape())
    sleep(0.1)

Pybricks via uRemote (direct UART or LineSensorURServer)

from pybricks.parameters import Port
from line_sensor_pybricks import LineSensorUR

sensor = LineSensorUR(Port.B)

sensor.ir_power(True)
sensor.load_calibration()
sensor.mode_calibrated()

while True:
    print(sensor.position(), sensor.derivative(), sensor.shape())

MicroBlocks

Shape is an ASCII character:

SHAPE_NONE     = ' '
SHAPE_STRAIGHT = '|'
SHAPE_T        = 'T'
SHAPE_L_LEFT   = '<'
SHAPE_L_RIGHT  = '>'
SHAPE_Y        = 'Y'

Microblocks example

API overview

LineSensorI2C and LineSensorUR share one high-level API. Prefer these names in new code:

Method Meaning
position() Line position (−128…127, 0 = center)
derivative() Position derivative
shape() Shape as an ASCII character
sensors() Eight raw or calibrated values
position_derivative_shape() (position, derivative, shape)
data(*indices) Full packet or selected fields
mode_raw() / mode_calibrated() Acquisition mode
calibrate(duration=5) Calibrate and save to EEPROM
ir_power(True/False) IR emitter
leds(mode) Automatic NeoPixel mode
save_calibration() / load_calibration() EEPROM calibration

Compatibility aliases available on both classes: set_emitter (= ir_power) and get_cal_min / get_cal_max / set_cal_min / set_cal_max. LineSensorI2C also accepts rgb_mode / led_mode (= leds), set_neopixel (= neopixel) and get_min / get_max / set_min / set_max.

LineSensorI2C also has start_calibration() and fine-grained calibration helpers.

Line polarity: firmware 5.6 defaults to a black line. Use blackline(False) for a white line (then recalibrate); the setting is not stored in EEPROM. Both classes provide it, and LineSensorUR.blackline() without an argument reads the current value.

LineSensorURServer (LMS-ESP32) subclasses frozen uRemote and exposes the native uRemote command names over UART while talking to the sensor on I2C.

More examples

Documentation

sphinx-build -b html docs docs/_build/html

Development notes

  • Main MicroPython source: micropython/line_sensor.py
  • Pybricks bundle: tools/generate_line_sensor_pybricks.py → micropython/line_sensor_pybricks.py
  • LMS-ESP32 uRemote server: micropython/line_sensor_ur_server.py
  • Sphinx mocks the MicroPython machine module for desktop builds
  • Tests need no hardware: python -m pip install pytest && python -m pytest (see tests/README.md)
  • PyPI publish: bump version in micropython/line_sensor.py and package.json, then rm -rf ./dist && python -m build && twine upload dist/*

About

MicroPython and MicroBlocks API for the line sensor

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages