Ranger 2-Way (TOF2) × SPIKE × Pybricks

Interactive tutorialSPIKE

First time? Try the interactive tutorial in your browser first, then follow the steps below with your hub.

This page covers Pybricks (Python) only: how to set it up for the Ranger 2-Way (TOF2) on SPIKE Prime / Robot Inventor, how to read every value, the commands it supports and examples. Use the switcher above to change product, host or software.

Setup

What you need

  • Sensor: Ranger 2-Way (TOF2) (SPIKE edition).
  • Hub: SPIKE Prime or Robot Inventor.
  • Computer: Chrome. Open code.pybricks.com and start writing; nothing to install.
  • Hub firmware: must be switched to Pybricks firmware v4.1 first (the stable code.pybricks.com is v4.1.1; v4.1.0 from the MBC SPIKE Blocks website works too). Every example on this site is written for v4.1.
  • Library: MBC_laser2_obj_Lib.py (only needed for the "import the library" method). For a new program of your own, import just MBC_sensors.py: one file for every MBC sensor.

Note

The Pybricks 3.6.1 libraries and examples are no longer updated (the 2026 SPIKE Prime hubs cannot run 3.6.1 either). For hubs that have not been upgraded, the old files are under "Legacy (no longer updated)" on the Downloads page.

Install the software

  1. Open code.pybricks.com in Chrome.
  2. Switch the hub to Pybricks firmware. The easiest way is the MBC SPIKE Blocks website: top menu "SPIKE Hub → Install/Update Pybricks firmware", about 3 minutes.
  3. To go back to the official LEGO App later, switch back to the original LEGO firmware with the SPIKE App.

Make the software see the sensor

Pybricks can read the sensor two ways; pick one:

  1. Built-in commands (no library): read the sensor with Pybricks' own sensor commands. No extra file, quickest to start.
  2. Import the library: download MBC_laser2_obj_Lib.py to get more data, such as the high-resolution position and every channel.

To import the library:

  1. In code.pybricks.com, click "Import a file" in the file panel on the left.
  2. Import both the example file and MBC_laser2_obj_Lib.py, so they are in the same project list.
  3. Open the example and press ▶ to run.

Important

New projects: use MBC_sensors.py. Old projects: just replace the one file they already use. MBC_sensors.py is one file for every MBC sensor (the EXP6 and Servo6 expander libraries are separate downloads); write from MBC_sensors import MBC_LINE8, with the same class names as in the old files. The old file names (such as MBC_laser2_obj_Lib.py used by the examples on this page) are kept for existing programs: swap in the new file with the same name and the program needs no changes. But every old-name file is the whole shared library, so importing 3 or more of them in one program goes over the SPIKE program slot limit of about 51 KB; to mix several sensors, import only MBC_sensors.py.

Tip

The file name must match the name in the program's import exactly, or you will get an ImportError. The library files on this site have no version suffix, so you do not need to rename them.

Tip

Most libraries take a multitask argument when you create the object: False is normal mode, one line after another; True is multitask mode, where every call needs await in front so the robot can do several things at once.

Wiring

  1. Plug the sensor into hub port C with the cable (any of A~F works).
  2. Use the same port in the program: built-in commands use Port.APort.F; a library's port argument is usually 16 for A~F.
  3. Latch up, push the plug in gently.

Which side is left

Left and right are as seen from behind the sensor, looking the way it faces (left = J5, right = J3). Facing the sensor, they are the other way round, so when you test with your hand, stand behind the sensor and look the same way it does. "Left is closer" and "turn left" in the examples follow this direction.

Test results (Pybricks 4.1.2)

The SPIKE edition passed hardware testing on Pybricks 4.1.2 (2026-11-02): readings, the library and the beginner examples were all run on a hub.

  • When you read it directly with ColorSensor, sensor firmware from 2026-11 on gives a whole number from reflection() on Pybricks 4.x (for example 31); older firmware gives one decimal place (for example 30.8). Writing int(...) works with both, so just keep it.

Change the settings with commands (E0 ~ E4)

Tip

Tested with SPIKE Pybricks (2026-11-02): every command E0 ~ E4 was checked on the hub: valid parameters return "done", out-of-range ones return "failed" and leave the setting unchanged, long-range mode reads up to 200 cm, and after a power cut the settings are back to factory.

Use cmd() in the MBC library MBC_laser2_obj_Lib.py to send a command and wait_done() to wait until it is done (True = done, False = failed or no reply). The official SPIKE App and the Pybricks built-in ColorSensor blocks cannot send commands; the sensor firmware must be from 2026-11 or later.

from MBC_laser2_obj_Lib import MBC_LASER2

laser2 = MBC_LASER2(3)          # 3 = port C
laser2.cmd(0xE0, 1)             # switch to long-range mode (up to 200 cm)
if laser2.wait_done():          # True = done
    print('long range on')
Command Parameter (out of range = failed) What it does When to use it Example
E0 ranging mode 0 normal (factory, up to 120 cm) / 1 long range (up to 200 cm) / 2 accurate (every 100 ms) / 3 fast (every 20 ms) Changes the mode and resets the timing budget and max distance to that mode's defaults Long range to measure beyond 120 cm; accurate for steady numbers; fast for quick reactions 1
E1 filter 0 off / 1 median of the last 3 (factory) / 2 median of the last 5 Removes an odd reading now and then Numbers jumping around → 2; fastest reaction in a match → 0 2
E2 timing budget 20 ~ 200 ms (0 = mode default) How long each reading takes: shorter is faster, longer is steadier Fast obstacle avoiding → 20; far and steady → 200 3
E3 factory reset must be 0xA5 Mode 0, filter 1, 33 ms, limit 120 cm Send it at the start of a program to begin from a clean state 4
E4 max distance 10 ~ mode limit in cm (normal 120, long range 200; 0 = mode limit) Anything beyond the limit counts as nothing, and the reading is the limit React only to near things, not to people walking around far away 5
  • On SPIKE, out of range = failed, setting unchanged (wait_done() returns False); it is not clamped to the nearest value as on Arduino I2C.
  • Changing the mode (E0) resets the timing budget and the max distance: to use E2 / E4 as well, send E0 first.
  • Settings are kept only in the sensor's memory: unplugging the sensor or turning the hub off brings back the factory settings (normal mode, limit 120 cm), so send them again every time the program starts.
  • "Nothing" reads as the limit: 120 in normal mode, 200 in long-range mode, or the limit you set with E4.
  • The same command with the same parameters is not done again (even inside a loop it runs once); to run it again write cmd(..., again=True) (example 4).
  • Each wait_done() adds a few tens of milliseconds, so do not put it in a fast line-following or obstacle-avoiding loop; set things up at the start of the program. E0, E2 and E3 re-configure the laser chips, which takes about 0.1 ~ 0.5 s.
  • The EV3 and MATRIX editions have no commands (read only).

Command examples (5 programs)

For each one: sensor on port C; import the example and MBC_laser2_obj_Lib.py into Pybricks Code together, then run it. Change the setting with the hub's left / right buttons; the screen shows the current setting and the computer prints the readings. Download all (5 examples + library)

1. Ranging mode (E0)

Put a white wall or big whiteboard about 150 cm ahead. Normal mode reads 120 (beyond the limit = nothing); press the right button to switch to 1 long range and it reads about 150.

Download cmd01_long_range.py + library

# Ranger 2-Way command example 01 (Pybricks, SPIKE Prime / Robot Inventor hub): ranging mode: normal / long range / accurate / fast
# Switch between the 4 ranging modes (command E0) with the left / right buttons on the hub; the screen shows the mode and the console prints the distances:
#   0 normal (factory, up to 120 cm), 1 long range (up to 200 cm), 2 accurate (every 100 ms, steadiest), 3 fast (every 20 ms, fastest)
# Setup: a white wall or big whiteboard about 150 cm in front of both lasers. Normal mode reads 120 (beyond the limit = nothing); mode 1 reads about 150
# Wiring: Ranger 2-Way → port C; upload it together with MBC_laser2_obj_Lib.py (keep both files in Pybricks Code)
# Only the SPIKE edition takes commands (sensor firmware 2026-11 or later); settings stay in the sensor memory and go back to factory when unplugged
#   cmd(code, parameter): send a command; wait_done(): wait until it is done, True = done, False = failed (parameter out of range) or no reply
#   Commands: E0 ranging mode, E1 filter, E2 timing budget, E3 factory reset (parameter 0xA5), E4 max distance
from pybricks.hubs import PrimeHub
from pybricks.parameters import Button, Color
from pybricks.tools import wait, StopWatch
from MBC_laser2_obj_Lib import MBC_LASER2

hub = PrimeHub()
laser2 = MBC_LASER2(3)                   # 3 = port C (1=A, 2=B, 3=C, 4=D, 5=E, 6=F)

mode = 0
laser2.cmd(0xE3, 0xA5)              # Factory reset first (normal mode)
laser2.wait_done()
hub.display.number(mode)
t = StopWatch()

while True:
    pressed = hub.buttons.pressed()    # Check the buttons every 10 ms, so one press is enough
    if Button.RIGHT in pressed or Button.LEFT in pressed:
        mode = (mode + (1 if Button.RIGHT in pressed else 3)) % 4   # right button +1, left button -1
        laser2.cmd(0xE0, mode)        # Change the ranging mode (re-configures the laser chips, about 0.1~0.5 s)
        ok = laser2.wait_done()       # Wait until done: True = done
        hub.display.number(mode)
        print('mode', mode, ['normal', 'long range', 'accurate', 'fast'][mode], 'done' if ok else 'failed')
        while hub.buttons.pressed():   # Wait until the button is released
            wait(10)
    if t.time() >= 300:                # Print the distances every 0.3 s
        t.reset()
        print('left', laser2.left(), 'right', laser2.right(), 'cm | left', laser2.left_mm(), 'mm')
    wait(10)

2. Filter (E1)

Put a box or whiteboard about 50 cm ahead and keep it still. Every second it prints "max - min within 1 s" = how many mm it jumps; a bigger filter is steadier.

Download cmd02_filter.py + library

# Ranger 2-Way command example 02 (Pybricks, SPIKE Prime / Robot Inventor hub): filter: steadier numbers
# Switch the filter (command E1) with the left / right buttons: 0 off, 1 median of the last 3 (factory), 2 median of the last 5
# Setup: a box or whiteboard about 50 cm in front of both lasers, kept still. Every second it prints "max - min within 1 s" = how many mm the number jumps; a bigger filter is steadier
# Wiring: Ranger 2-Way → port C; upload it together with MBC_laser2_obj_Lib.py (keep both files in Pybricks Code)
# Only the SPIKE edition takes commands (sensor firmware 2026-11 or later); settings stay in the sensor memory and go back to factory when unplugged
#   cmd(code, parameter): send a command; wait_done(): wait until it is done, True = done, False = failed (parameter out of range) or no reply
#   Commands: E0 ranging mode, E1 filter, E2 timing budget, E3 factory reset (parameter 0xA5), E4 max distance
from pybricks.hubs import PrimeHub
from pybricks.parameters import Button, Color
from pybricks.tools import wait, StopWatch
from MBC_laser2_obj_Lib import MBC_LASER2

hub = PrimeHub()
laser2 = MBC_LASER2(3)                   # 3 = port C (1=A, 2=B, 3=C, 4=D, 5=E, 6=F)

filt = 1
laser2.cmd(0xE3, 0xA5)              # Factory reset first (filter 1)
laser2.wait_done()
wait(500)                        # Wait for fresh readings before counting
hub.display.number(filt)

while True:
    lo, hi = 99999, -1
    t = StopWatch()
    while t.time() < 1000:           # Keep reading for 1 s and remember the max and min
        mm = laser2.left_mm()
        lo = min(lo, mm)
        hi = max(hi, mm)
        pressed = hub.buttons.pressed()
        if Button.RIGHT in pressed or Button.LEFT in pressed:
            filt = (filt + (1 if Button.RIGHT in pressed else 2)) % 3
            laser2.cmd(0xE1, filt)      # Change the filter (takes effect at once)
            laser2.wait_done()
            hub.display.number(filt)
            print('filter', filt)
            while hub.buttons.pressed():
                wait(10)
            lo, hi = 99999, -1
            t.reset()
        wait(20)
    print('filter', filt, '| left mm', lo, '~', hi, '| jumps', hi - lo, 'mm')

3. Timing budget (E2)

Put a box or whiteboard about 50 cm ahead and keep it still. Every second it prints how many times the value changed (≈ updates) and how many mm it jumps: 20 ms is fastest, 200 ms steadiest.

Download cmd03_budget.py + library

# Ranger 2-Way command example 03 (Pybricks, SPIKE Prime / Robot Inventor hub): timing budget: faster or more accurate
# Switch the timing budget (command E2) with the left / right buttons: 20, 33 (factory), 100, 200 ms
# Setup: a box or whiteboard about 50 cm in front of both lasers, kept still. Every second it prints "how many times the value changed" (≈ updates) and "how many mm it jumps"
# Wiring: Ranger 2-Way → port C; upload it together with MBC_laser2_obj_Lib.py (keep both files in Pybricks Code)
# Only the SPIKE edition takes commands (sensor firmware 2026-11 or later); settings stay in the sensor memory and go back to factory when unplugged
#   cmd(code, parameter): send a command; wait_done(): wait until it is done, True = done, False = failed (parameter out of range) or no reply
#   Commands: E0 ranging mode, E1 filter, E2 timing budget, E3 factory reset (parameter 0xA5), E4 max distance
from pybricks.hubs import PrimeHub
from pybricks.parameters import Button, Color
from pybricks.tools import wait, StopWatch
from MBC_laser2_obj_Lib import MBC_LASER2

hub = PrimeHub()
laser2 = MBC_LASER2(3)                   # 3 = port C (1=A, 2=B, 3=C, 4=D, 5=E, 6=F)

CHOICES = [20, 33, 100, 200]
k = 1
laser2.cmd(0xE3, 0xA5)              # Factory reset first (33 ms)
laser2.wait_done()
laser2.cmd(0xE1, 0)                 # Filter off, so the difference is easier to see
laser2.wait_done()
wait(500)                        # Wait for fresh readings before counting
hub.display.number(CHOICES[k])

while True:
    last, changes, lo, hi = -1, 0, 99999, -1
    t = StopWatch()
    while t.time() < 1000:
        mm = laser2.left_mm()
        if mm != last:
            changes += 1
            last = mm
        lo = min(lo, mm)
        hi = max(hi, mm)
        pressed = hub.buttons.pressed()
        if Button.RIGHT in pressed or Button.LEFT in pressed:
            k = (k + (1 if Button.RIGHT in pressed else 3)) % 4
            laser2.cmd(0xE2, CHOICES[k])    # Change the timing budget (re-configures the laser chips)
            ok = laser2.wait_done()
            hub.display.number(CHOICES[k])
            print('timing budget', CHOICES[k], 'ms', 'done' if ok else 'failed')
            while hub.buttons.pressed():
                wait(10)
            last, changes, lo, hi = -1, 0, 99999, -1
            t.reset()
        wait(5)
    print(CHOICES[k], 'ms | changed', changes, 'times in 1 s | jumps', hi - lo, 'mm')

4. Factory reset (E3)

Put a whiteboard about 60 cm ahead. The limit is set to 30 cm first, so the reading is "capped" at 30; press the center button to send E3, the limit goes back to 120 and the board at 60 cm shows up again. To stop the program: hold the center button.

Download cmd04_factory_reset.py + library

# Ranger 2-Way command example 04 (Pybricks, SPIKE Prime / Robot Inventor hub): factory reset
# Factory reset (command E3, the parameter must be 0xA5): first set the max distance to 30 cm and see the reading "capped" at 30;
# press the center button to send E3 → the limit is back to 120 cm and far objects show up again
# Setup: a whiteboard about 60 cm in front of both lasers (farther than 30, nearer than 120)
# Wiring: Ranger 2-Way → port C; upload it together with MBC_laser2_obj_Lib.py (keep both files in Pybricks Code)
# Only the SPIKE edition takes commands (sensor firmware 2026-11 or later); settings stay in the sensor memory and go back to factory when unplugged
#   cmd(code, parameter): send a command; wait_done(): wait until it is done, True = done, False = failed (parameter out of range) or no reply
#   Commands: E0 ranging mode, E1 filter, E2 timing budget, E3 factory reset (parameter 0xA5), E4 max distance
from pybricks.hubs import PrimeHub
from pybricks.parameters import Button, Color
from pybricks.tools import wait, StopWatch
from MBC_laser2_obj_Lib import MBC_LASER2

hub = PrimeHub()
laser2 = MBC_LASER2(3)                   # 3 = port C (1=A, 2=B, 3=C, 4=D, 5=E, 6=F)

laser2.cmd(0xE4, 30)                # Set the max distance to 30 cm first (beyond 30 = nothing, reads 30)
laser2.wait_done()
hub.display.number(30)
print('Max distance 30 cm: press the center button to send E3 factory reset')
hub.system.set_stop_button(None)   # Use the center button in the program (to stop the program: hold the center button)

t = StopWatch()
while True:
    if Button.CENTER in hub.buttons.pressed():   # Check the buttons every 10 ms
        laser2.cmd(0xE3, 0xA5, again=True)   # Factory reset; again=True: run the same command again too
        ok = laser2.wait_done()
        hub.display.number(120)
        hub.speaker.beep()
        print('factory reset', 'done' if ok else 'failed', ': limit back to 120 cm')
        while hub.buttons.pressed():
            wait(10)
    if t.time() >= 300:                # Print the distances every 0.3 s
        t.reset()
        print('left', laser2.left(), 'right', laser2.right(), 'cm | left', laser2.left_mm(), 'mm')
    wait(10)

5. Max distance (E4)

The left / right buttons change the limit to 10, 20 ... 120 cm. Closer than the limit: red light + beep, otherwise green; people walking around far away do not trigger it.

Download cmd05_max_distance.py + library

# Ranger 2-Way command example 05 (Pybricks, SPIKE Prime / Robot Inventor hub): max distance: only near things count
# Max distance (command E4, cm): anything beyond the limit counts as "nothing" and reads as the limit → it only reacts to near things
# Left / right buttons change the limit to 10, 20, 30 ... 120 cm (shown on the screen); if the nearer distance is closer than the limit: red light + beep, otherwise green
# Wiring: Ranger 2-Way → port C; upload it together with MBC_laser2_obj_Lib.py (keep both files in Pybricks Code)
# Only the SPIKE edition takes commands (sensor firmware 2026-11 or later); settings stay in the sensor memory and go back to factory when unplugged
#   cmd(code, parameter): send a command; wait_done(): wait until it is done, True = done, False = failed (parameter out of range) or no reply
#   Commands: E0 ranging mode, E1 filter, E2 timing budget, E3 factory reset (parameter 0xA5), E4 max distance
from pybricks.hubs import PrimeHub
from pybricks.parameters import Button, Color
from pybricks.tools import wait, StopWatch
from MBC_laser2_obj_Lib import MBC_LASER2

hub = PrimeHub()
laser2 = MBC_LASER2(3)                   # 3 = port C (1=A, 2=B, 3=C, 4=D, 5=E, 6=F)

limit = 30
laser2.cmd(0xE3, 0xA5)              # Factory reset first
laser2.wait_done()
laser2.cmd(0xE4, limit)             # Max distance 30 cm
laser2.wait_done()
hub.display.number(limit)
t = StopWatch()

while True:
    pressed = hub.buttons.pressed()    # Check the buttons every 10 ms
    if Button.RIGHT in pressed or Button.LEFT in pressed:
        limit = limit + 10 if Button.RIGHT in pressed else limit - 10
        limit = max(10, min(120, limit))
        laser2.cmd(0xE4, limit)       # Change the limit (takes effect at once)
        laser2.wait_done()
        hub.display.number(limit)
        while hub.buttons.pressed():
            wait(10)
    if t.time() >= 200:                # Check the distance every 0.2 s
        t.reset()
        cm = min(laser2.left(), laser2.right())
        if cm < limit:               # Closer than the limit = something is really there
            hub.light.on(Color.RED)
            hub.speaker.beep(1000, 50)
        else:
            hub.light.on(Color.GREEN)
        print('limit', limit, 'cm |', 'left', laser2.left(), 'right', laser2.right(), 'cm | left', laser2.left_mm(), 'mm')
    wait(10)

First test

  1. Turn on the hub and connect it in code.pybricks.com.
  2. Import and open example 1 on this page, then press ▶.
  3. If the numbers printed in the console change with what is in front of the sensor, everything is connected.

FAQ

  • ImportError? The library was not imported into the same project, or its file name differs from the import name. Rename it to MBC_laser2_obj_Lib.py and import it again.
  • The example does not run, or a command is unknown? The hub firmware is too old: the examples on this site are written for Pybricks v4.1, so update the hub to v4.1 first. 3.6.1 is no longer updated; the old files are on the Downloads page.
  • What happens if the sensor cable comes out? The program keeps running: the library returns the last value it read and prints one notice in the console (in Chinese and English: MBC: Port C 讀不到感應器,先回傳上一次的值 / no sensor, using the last value); if the sensor was never connected it returns None. To check in your program, call the object's sensor_ok(): True if the last read worked, False if not (add await in multitask mode). Once you plug it back in the library keeps reading; if the sensor was missing from the start and you use multitask mode, run the program again.
  • An example marked "Pybricks only" shows strange numbers? It uses a new mode in sensor firmware from 2026-10 on; older firmware returns different numbers.
  • The official App cannot connect any more? The hub now runs Pybricks firmware: switch back to the original LEGO firmware with the SPIKE App.

Reading values

Code assumes the sensor is on port A. For the MBC library form, import the library .py into Pybricks too.

left distance (cm) leftCm

left distance (cm)
Range Meaning
0~120 cm distance from the left sensor, 0~120 cm (left = sensor 0 seen from behind the robot); 120 = nothing in range / sensor failed
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port

dev = PUPDevice(Port.A)   # sensor on port A

w = dev.read(9)[0]
leftCm = (w & 0xFF)   # left distance (cm)(lo byte)

MBC library

from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2

laser = MBC_LASER2(Port.A)
leftCm = laser.left()

mode 0 (edu) byte 0 🔒; mode 0 (toy) byte 0 🔒; mode 1 byte 0; mode 2 byte 0; mode 3 byte 0 🔒; mode 4 v[0] lo; mode 5 v[0] 🔒; mode 8 v[0] lo; mode 9 v[0] lo 🔒. Note: 16 B = [左, 右, 0, 左, 0, 右, 0, 平均, 0×8]:App 顏色 = 左、原始紅 = 256×左; 8 B 原樣(不壓縮); 韌體註解寫「最近」,實際送左(INO:261-263); 網站 read(3) 在用:[左, 右, 0]; Pybricks reflection() 編碼:L = 左 cm,a = L/25、b = 10×(L mod 25)+9,3 個 int16 = a×256+b → reflection() = L; 只送 4 B,v0 = 左 + 256×右

right distance (cm) rightCm

right distance (cm)
Range Meaning
0~120 cm distance from the right sensor, 0~120 cm (right = sensor 1); 120 = nothing in range / sensor failed
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port

dev = PUPDevice(Port.A)   # sensor on port A

w = dev.read(9)[0]
rightCm = ((w >> 8) & 0xFF)   # right distance (cm)(hi byte)

MBC library

from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2

laser = MBC_LASER2(Port.A)
rightCm = laser.right()

mode 0 (edu) byte 1 🔒; mode 0 (toy) byte 1 🔒; mode 3 byte 1 🔒; mode 4 v[0] hi; mode 7 v[2] 🔒; mode 8 v[0] hi; mode 9 v[0] hi 🔒. Note: App 反射光 = 右、原始綠 = 256×右; 網站 read(3) 在用; Pybricks ambient() = int16[2]/100 = 右 cm(INO:300-312)

left distance (mm) leftMm

left distance (mm)
Range Meaning
0~1200 mm left sensor distance 0~1200 mm; 1200 = nothing in range / sensor failed
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port

dev = PUPDevice(Port.A)   # sensor on port A

leftMm = dev.read(6)[0]   # left distance (mm)

MBC library

from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2

laser = MBC_LASER2(Port.A)
leftMm = laser.left_mm()

mode 6 v[0]. Note: #67 新:HSV 3×int16 = [左 mm, 右 mm, 平均 mm](原本是基底緩衝合併值)

right distance (mm) rightMm

right distance (mm)
Range Meaning
0~1200 mm right sensor distance 0~1200 mm; 1200 = nothing in range / sensor failed
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port

dev = PUPDevice(Port.A)   # sensor on port A

rightMm = dev.read(6)[1]   # right distance (mm)

MBC library

from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2

laser = MBC_LASER2(Port.A)
rightMm = laser.right_mm()

mode 6 v[1]. Note: #67 新

init bitmap initOk

init bitmap
Range Meaning
0~3 bit bit0 = left, bit1 = right; 1 = that sensor initialised at power-on (no retry); 3 = both OK
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port

dev = PUPDevice(Port.A)   # sensor on port A

w = dev.read(9)[1]
initOk = (w & 0xFF)   # init bitmap(lo byte)

MBC library

from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2

laser = MBC_LASER2(Port.A)
initOk = laser.is_ok(1)

mode 9 v[1] lo 🔒

fault bitmap fault

fault bitmap
Range Meaning
0~3 bit bit0 = left, bit1 = right; 1 = that sensor is currently failing (I2C error or no update for 200 ms); its distance reads 120 / 1200
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port

dev = PUPDevice(Port.A)   # sensor on port A

w = dev.read(9)[1]
fault = ((w >> 8) & 0xFF)   # fault bitmap(hi byte)

MBC library

from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2

laser = MBC_LASER2(Port.A)
fault = laser.is_ok(1)

mode 9 v[1] hi 🔒

average distance (mm) avgMm

average distance (mm)
Range Meaning
0~1200 mm (left mm + right mm) / 2, 0~1200; same number as EV3 mode 3 and the 3rd value of SPIKE mode 6
from pybricks.iodevices import PUPDevice
from pybricks.parameters import Port

dev = PUPDevice(Port.A)   # sensor on port A

avgMm = dev.read(0)[7]   # average distance (mm)

MBC library

from pybricks.parameters import Port
from MBC_laser2_obj_Lib import MBC_LASER2

laser = MBC_LASER2(Port.A)
avgMm = laser.average_mm()

mode 0 (edu) byte 7 🔒; mode 6 v[2]. Note: byte7 = (左 cm + 右 cm)>>1;App 原始藍 = 256×平均; #67 新:平均 mm

Not readable here:nearer distance (cm). Use Arduino / mBlock / micro:bit for these.

Examples

Example 1: See the distance

What this example does: the hub display keeps scrolling two numbers, "left distance right distance" (in cm), for example "40 80".

What you need

  • 1 SPIKE hub
  • 1 Ranger 2-Way
  • A book or a box to use as an "obstacle"

How to connect: plug the Ranger 2-Way into port C.

Download the program

Pybricks
ex01_show_distance.py + library
Pybricks code
# 測距者 2 路 範例 1:看見距離(螢幕捲動顯示「左距離 右距離」)
# 接線:測距者 2 路 → C 埠
from pybricks.hubs import PrimeHub
from pybricks.tools import wait
from MBC_laser2_obj_Lib import MBC_LASER2

hub = PrimeHub()
laser2 = MBC_LASER2(3)              # 3 = C 埠(1=A、2=B、3=C、4=D、5=E、6=F)

while True:
    left = laser2.left()            # 左邊雷射量到的距離(公分,0~120;120 = 前面沒東西)
    right = laser2.right()          # 右邊雷射量到的距離
    hub.display.text(str(left) + ' ' + str(right))   # 主機螢幕捲動顯示,例如「40 80」
    print('左', left, '  右', right)                  # 電腦畫面也印出來
    wait(200)                       # 等 0.2 秒再讀下一次

Step by step: what the program does

  1. Repeat forever: the blocks inside keep running until you press stop.
  2. Read the left and right distance: in the official App that is "raw red ÷ 256, rounded down" and "raw green ÷ 256, rounded down", stored in two "variables" (a variable is a box with a name that holds one number). The MBC Blocks website and Pybricks have "left laser distance" and "right laser distance" directly.
  3. Show it on the display: join "left distance", a space and "right distance" into one piece of text and scroll it on the hub display. The MBC Blocks website and Pybricks also print it on the computer screen.
  4. Wait 0.2 seconds, then read again.

What you should see when it runs

  • Nothing in front: it shows 120 120.
  • Put a book 30 cm in front: both numbers go to about 30.
  • Cover only the left laser with your hand: the first number drops, the second one stays the same.

Important

Use this example to confirm left and right first. With the sensor facing forward and the component side up, stand behind it looking the same way and cover only the left laser (J5): the first number should drop. If the second number drops instead, your sensor is mounted the opposite way from the examples (for example upside down), and you will need to swap "left" and "right" in the later examples too.

Common questions

  • It always shows 120 120? → There really is nothing in front, or the object is too far away, or it is black/transparent. Try a white book 20 cm in front. It also shows 120 for the first 1 to 2 seconds after power-on.
  • Only one side is stuck at 120? → That laser may be blocked, dirty or broken. You can check it with the "laser OK" block on the MBC Blocks website or laser2.is_ok(1) in Pybricks.
  • The numbers keep jumping? → That's normal. The lasers measure a dozen or more times per second and have an error of 1 to 2 cm.
  • The official App shows numbers in the thousands? → You forgot the "÷ 256, rounded down" step.

Example 2: Beep when too close

What this example does: if either side sees something closer than 20 cm, the hub light turns red and the hub beeps; otherwise it stays green.

What you need: same as Example 1.

How to connect: plug the Ranger 2-Way into port C.

Download the program

Pybricks
ex02_too_close_beep.py + library
Pybricks code
# 測距者 2 路 範例 2:太近就嗶(任何一邊小於 20 公分:紅燈+嗶聲;否則綠燈)
# 接線:測距者 2 路 → C 埠
from pybricks.hubs import PrimeHub
from pybricks.parameters import Color
from pybricks.tools import wait
from MBC_laser2_obj_Lib import MBC_LASER2

hub = PrimeHub()
laser2 = MBC_LASER2(3)                  # 3 = C 埠

while True:
    if laser2.min_distance() < 20:      # 左右兩邊比較近的那個距離,小於 20 公分
        hub.light.on(Color.RED)
        hub.speaker.beep(880, 100)      # 頻率 880 Hz,響 0.1 秒
    else:
        hub.light.on(Color.GREEN)
    wait(100)

Step by step: what the program does

  1. Read the distance: the official App reads the left and right distances; the MBC Blocks website and Pybricks read the "nearer distance" (the smaller of the two) directly.
  2. If too close then…: the official App writes it as "left < 20 or right < 20", which means the same as "nearer distance < 20" → red light and a beep.
  3. Else…: green light.
  4. Wait 0.1 seconds, then check again.

What you should see when it runs

  • Nothing in front: green light.
  • Move your hand in slowly; once it is within 20 cm: red light and constant beeping. Take your hand away and it goes back to green.

Common questions

  • It goes quiet when my hand touches the sensor? → When something is extremely close (within a few cm), the laser may not be able to measure it and reads 120. That is just how the laser works; leave a little gap.
  • Want it to beep at 30 cm instead? → Change "20" to "30" (in the official App there are two 20s, change both).

Example 3: Which side is closer

What this example does: the hub display uses an arrow to tell you where the object is: left side closer → ⬅, right side closer → ➡, about the same → ⬆, nothing there → ✕.

What you need: same as Example 1.

How to connect: plug the Ranger 2-Way into port C.

Download the program

Pybricks
ex03_which_closer.py + library
Pybricks code
# 測距者 2 路 範例 3:哪一邊比較近(主機螢幕顯示箭頭)
# 接線:測距者 2 路 → C 埠
from pybricks.hubs import PrimeHub
from pybricks.parameters import Icon
from pybricks.tools import wait
from MBC_laser2_obj_Lib import MBC_LASER2

hub = PrimeHub()
laser2 = MBC_LASER2(3)                      # 3 = C 埠

while True:
    diff = laser2.diff()                    # 左距離 減 右距離:負的 = 左邊比較近,正的 = 右邊比較近
    if laser2.min_distance() >= 120:        # 兩邊都是 120 → 前面什麼都沒有
        hub.display.icon(Icon.FALSE)        # 顯示 ✕
    elif diff < -5:                         # 左邊近了 5 公分以上
        hub.display.icon(Icon.ARROW_LEFT)
    elif diff > 5:                          # 右邊近了 5 公分以上
        hub.display.icon(Icon.ARROW_RIGHT)
    else:                                   # 兩邊差不多 → 東西在正前方
        hub.display.icon(Icon.ARROW_UP)
    wait(100)

Step by step: what the program does

  1. First work out left minus right = left distance minus right distance. When the left side is closer, the left distance is smaller, so the result is negative.
  2. If both sides are 120 → show ✕ (nothing in front; check this first). The official App writes it as "left > 119 and right > 119".
  3. Else, if left minus right < -5 → the left side is closer by more than 5 cm → left arrow.
  4. Else, if left minus right > 5 → the right side is closer by more than 5 cm → right arrow.
  5. Otherwise (less than 5 cm difference) → up arrow, meaning the object is straight ahead.

What you should see when it runs: move a book slowly from the left to the right (about 30 cm away). The arrow goes ⬅ → ⬆ → ➡; take the book away and it becomes ✕.

Common questions

  • Why does it have to differ by more than 5 cm? → The lasers themselves have an error of 1 to 2 cm. Leaving some room keeps the arrow from flickering back and forth.
  • The left and right arrows are swapped? → Left and right are as seen from behind the sensor, looking the way it faces (left = J5, right = J3); facing the sensor, they are the other way round. If they are still swapped seen from behind, go back to Example 1 and confirm left and right; the sensor may be mounted the other way round.
  • The arrow jumps around when the object is far away? → The two laser beams get wider with distance and overlap far away, so beyond 50 cm it is hard to tell left from right. Play with this example within 50 cm.

Example 4: Back up and turn when something is ahead

What this example does: the robot keeps driving forward. When something is in front (closer than 20 cm), it stops → beeps → backs up 10 cm → turns right 90 degrees, then keeps going.

What you need

  • Everything from Example 1, plus
  • A two-wheeled robot car (two motors as the wheels)
  • An open floor area with a few boxes as obstacles

How to connect

  • Plug the Ranger 2-Way into port C, mounted at the front of the car, pointing straight ahead, at least 5 cm off the floor (too low and it will measure the floor)
  • Left wheel motor on E, right wheel motor on F

Download the program

Pybricks
ex04_obstacle_back.py + library
Pybricks code
# 測距者 2 路 範例 4:一直往前走,前面有東西(小於 20 公分)就停車、嗶一聲、後退、右轉
# 接線:測距者 2 路 → C 埠(裝在車頭、朝前);左輪馬達 → E 埠;右輪馬達 → F 埠
from pybricks.hubs import PrimeHub
from pybricks.parameters import Direction, Port
from pybricks.pupdevices import Motor
from pybricks.robotics import DriveBase
from pybricks.tools import wait
from MBC_laser2_obj_Lib import MBC_LASER2

hub = PrimeHub()
laser2 = MBC_LASER2(3)                                 # 3 = C 埠
left = Motor(Port.E, Direction.COUNTERCLOCKWISE)       # 左輪:反過來裝,所以設成逆時針才是往前
right = Motor(Port.F)                                  # 右輪
robot = DriveBase(left, right, wheel_diameter=56, axle_track=112)   # 輪子直徑 56 mm、兩輪距離 112 mm

while True:
    if laser2.min_distance() < 20:    # 左右任何一邊小於 20 公分 → 前面有東西
        robot.stop()                  # 先停車
        hub.speaker.beep(880, 200)
        robot.straight(-100)          # 後退 100 mm(10 公分)
        robot.turn(90)                # 原地右轉 90 度
    else:
        robot.drive(150, 0)           # 每秒 150 mm 直直往前走
    wait(50)

Step by step: what the program does

  1. Tell the hub where the wheels are: in the official App it is "set movement motors to E+F"; on the MBC Blocks website and in Pybricks it is "drive base: left wheel E, right wheel F".
  2. Set the speed: 30% in the official App; 150 mm per second in the other two.
  3. Repeat forever: read the distance.
  4. If nearer distance < 20 → stop → beep → back up 10 cm → turn right on the spot. The official App's "turn right" is "move 0.5 rotations with steering 100", which is roughly 90 degrees on the standard LEGO car.
  5. Else → drive forward.

What you should see when it runs: the car drives forward, stops just before hitting a box, beeps, backs up a little, turns right, then carries on.

Common questions

  • It only stops after bumping into the obstacle? → It is driving too fast, or the obstacle is black/transparent (cannot be measured). Lower the speed, or raise the "20" a bit (for example 25).
  • It turns less than 90 degrees / too much? → Official App: change the "0.5 rotations" number; MBC Blocks website and Pybricks: change the "90".
  • The car drives backward / the direction is reversed? → The motors are mounted the opposite way from the standard LEGO car. Official App: mount the motors the way the LEGO "standard driving base" does; MBC Blocks website: in the "drive base" block, flip the "forward" direction of both the left and right wheel; Pybricks: change the left wheel to Direction.CLOCKWISE and the right wheel to Motor(Port.F, Direction.COUNTERCLOCKWISE).
  • It keeps spinning on the spot and never moves forward? → The sensor is mounted too low and is measuring the floor. Raise the sensor a bit and tilt it slightly upward.

Example 5: Drive up to a wall and square up

What this example does: the robot drives forward and stops 20 cm from the wall, then turns slowly on the spot until both lasers read the same distance (within 1 cm), which means the front of the car is facing the wall squarely. When done it beeps and shows a smiley face on the display. Teams often use this trick in competitions to "square up" the robot.

What you need: same as Example 4, plus a wall (or the flat side of a big cardboard box).

How to connect: plug the Ranger 2-Way into port C, mounted at the front pointing forward; left wheel motor on E, right wheel motor on F.

Download the program

Pybricks
ex05_square_up.py + library
Pybricks code
# 測距者 2 路 範例 5:往前開到離牆 20 公分停下,再原地轉到兩邊距離一樣(車頭對正牆面)
# 接線:測距者 2 路 → C 埠(裝在車頭、朝前);左輪馬達 → E 埠;右輪馬達 → F 埠
from pybricks.hubs import PrimeHub
from pybricks.parameters import Direction, Icon, Port
from pybricks.pupdevices import Motor
from pybricks.robotics import DriveBase
from pybricks.tools import wait
from MBC_laser2_obj_Lib import MBC_LASER2

hub = PrimeHub()
laser2 = MBC_LASER2(3)                                 # 3 = C 埠
left = Motor(Port.E, Direction.COUNTERCLOCKWISE)
right = Motor(Port.F)
robot = DriveBase(left, right, wheel_diameter=56, axle_track=112)

# 第 1 步:往前開,直到左右平均距離 ≤ 20 公分
robot.drive(100, 0)
while laser2.average() > 20:
    wait(20)
robot.stop()

# 第 2 步:原地轉,直到左右只差 1 公分以內
while abs(laser2.diff()) > 1:          # diff = 左 減 右
    if laser2.diff() < 0:              # 左邊比較近 → 車頭偏右了 → 往左轉
        robot.drive(0, -30)            # 速度 0(不前進),每秒左轉 30 度
    else:                              # 右邊比較近 → 往右轉
        robot.drive(0, 30)
    wait(20)
robot.stop()

# 第 3 步:完成!
hub.speaker.beep(880, 500)
hub.display.icon(Icon.HAPPY)

Step by step: what the program does (this example is not a "repeat forever"; it runs 3 steps in order and then ends)

  1. Step 1: drive forward, "wait until" the average distance ≤ 20 cm, then stop. In the official App the average distance is "raw blue ÷ 256, rounded down", written as "< 21", which means the same thing.
  2. Step 2: square up. "Repeat until" left and right differ by 1 cm or less:
    • left minus right < 0 (left side closer) → the front is pointing to the right → turn left;
    • else → turn right.
    • The official App sets "left minus right" to 99 first, so that the "repeat until" checks at least once.
  3. Step 3: done: stop, beep, show a smiley face.

What you should see when it runs: place the car at a slight angle to the wall (front pointing a little off), then press run. The car drives forward, stops, wiggles left and right to square up, then beeps.

Common questions

  • It keeps turning left and right and never stops? → The wall is not flat, or "within 1 cm" is too strict. Change the "1" to "2" (in the official App, change "< 2" to "< 3").
  • It squares up the wrong way and gets more crooked? → Left and right are as seen from behind the sensor, looking the way it faces (left = J5, right = J3). Go back to Example 1 and confirm left and right; if they are swapped, swap "turn left" and "turn right".
  • It cannot square up when the angle is too big (over 30 degrees)? → At a big angle one laser misses the wall completely (reads 120). Line the car up roughly first, then start.
  • The wall is black? → Black walls read shorter and less accurately. Use a light-colored wall or stick white paper on it.

Example 6 (advanced): Park precisely using millimeters

Note

This example comes in a Pybricks version only. The "millimeter distance" it uses lives in sensor mode 6, which the official LEGO App and the MBC Blocks website cannot read (they only read centimeters). The sensor firmware must be from 2026-10 or later; older firmware returns different numbers in that mode. The code itself is the example, so there are no screenshots.

What this example does: the robot drives forward, slows down at 20 cm from the wall, stops at 15 cm (150 mm), beeps, and shows the stopping distance (in cm) on the display. Centimeters only resolve to 1 cm, millimeters resolve to 0.1 cm, so the stopping position is more precise.

What you need: same as Example 5 (the car plus a wall).

How to connect: plug the Ranger 2-Way into port C, mounted at the front pointing forward; left wheel motor on E, right wheel motor on F.

Download the program

Pybricks
ex06_park_mm.py + library
Pybricks code
# 測距者 2 路 範例 6(進階):用毫米精準停車(離牆 20 公分放慢、15 公分停)
# 接線:測距者 2 路 → C 埠(裝在車頭朝前);左輪馬達 → E 埠;右輪馬達 → F 埠
# 只有 Pybricks 版:毫米距離放在感應器的「模式 6」,官方 App 和積木網站讀不到;感應器韌體要 2026-10 以後
from pybricks.hubs import PrimeHub
from pybricks.parameters import Direction, Port
from pybricks.pupdevices import Motor
from pybricks.robotics import DriveBase
from pybricks.tools import wait
from MBC_laser2_obj_Lib import MBC_LASER2

hub = PrimeHub()
laser2 = MBC_LASER2(3)                                 # 3 = C 埠
left = Motor(Port.E, Direction.COUNTERCLOCKWISE)
right = Motor(Port.F)
robot = DriveBase(left, right, wheel_diameter=56, axle_track=112)

robot.drive(100, 0)                                    # 每秒 100 mm 往前開
while laser2.average_mm() > 200:                       # 左右平均距離(毫米)還大於 200 mm = 20 公分
    wait(10)
robot.drive(40, 0)                                     # 剩 20 公分:放慢到每秒 40 mm
while laser2.average_mm() > 150:                       # 到 150 mm = 15 公分
    wait(10)
robot.stop()                                           # 停車
hub.speaker.beep()
mm = laser2.average_mm()                               # 停下來之後再量一次
hub.display.number(mm // 10)                           # 螢幕顯示公分(15 或 14)
print('停在', mm, 'mm')

Step by step: what the program does

  1. laser2.average_mm(): the average of left and right, in millimeters (0 to 1200; 1200 = nothing in front). The sensor works out the average itself, so you don't have to add them up.
  2. Drive forward at 100 mm per second and wait until the average distance ≤ 200 mm (20 cm).
  3. Switch to a slow 40 mm per second and wait until ≤ 150 mm, then stop.
  4. Beep, and show the stopping distance ÷ 10 (in cm) on the display.
  5. The library also has laser2.left_mm() and laser2.right_mm() (left and right in millimeters), plus laser2.device_id() and laser2.firmware_version() (sensor model and firmware version).

What you should see when it runs: the car drives forward, slows down as it nears the wall, stops about 15 cm from it, beeps, and the display shows 15 or 14.

Common questions

  • The stopping position is off by 1 to 2 cm each time? → The lasers themselves have an error of 1 to 2 cm, and the car has momentum. Make the "40" smaller (for example 25) to stop more precisely.
  • Want to use centimeters and millimeters at the same time? → You can, but don't mix them in the same loop: every mode switch costs the sensor a few dozen ms.
  • The number is stuck at 1200? → There really is nothing in front; or the sensor firmware is too old (before 2026-10) and has no millimeter mode, so please update the firmware.

More questions

  • The hub does not detect the sensor? Unplug and replug, wait 2 s, try another port. The official app shows it as a colour sensor — that is expected.
  • Can I use the official app and Pybricks on the same hub? One firmware at a time: Pybricks and the MBC Blocks website need Pybricks firmware, the official app needs LEGO firmware; you can switch back any time with the SPIKE app.

Still stuck? Contact us with your software and a screenshot of the program.

Downloads

Sources

  • Host and software list:_build/guides.json
  • Values and commands:_build/protocol/tof2.json (single source of truth)
  • Setup:_build/guides/software/spike-pybricks.en.md、_build/guides/product/tof2/spike-pybricks.en.md
  • Examples:sensors/tof2/spike-examples.md
Email for a quoteBuying Guide