Ranger 2-Way (TOF2) × micro:bit × MakeCode
Interactive tutorialmicro:bit
First time? Try the interactive tutorial in your browser first, then follow the steps below with your hub.
This page covers MakeCode (blocks / JavaScript) only: how to set it up for the Ranger 2-Way (TOF2) on BBC micro:bit V1 / V2, how to read every value, the commands it supports and examples. Use the switcher above to change product, host or software.
Which edition and how to connect
Get the Universal I2C edition and connect it to the I2C header of a micro:bit breakout (SDA = P20, SCL = P19), factory address 0x29. It draws little current, so VCC can go to the micro:bit 3V pin (about 90 mA on V1, 190 mA on V2); on batteries the rail can sag below 3 V, so switch to external 5 V if readings are unstable (share GND with the micro:bit).
Setup
What you need
- Sensor: Ranger 2-Way (TOF2) (Universal I2C edition). SPIKE and EV3 editions run different firmware and cannot be read by a micro:bit.
- Board: BBC micro:bit V1 or V2, plus a breakout board or crocodile-clip adapter to reach P19 / P20.
- Software: MakeCode for micro:bit in the browser (makecode.microbit.org, blocks / JavaScript); the offline app (Windows / Mac) also works, but adding an extension the first time needs internet.
- Extension: pxt-mbc-sensors v2 (MIT, nothing to download, just paste the URL).
Important
Bench test pending: extension v2.0.5 compiles in MakeCode (V1 + V2) but has not yet been checked block by block on real hardware. Block names follow the GitHub release.
Install the software
- Open makecode.microbit.org → New Project.
- Traditional Chinese block names are included: switch the editor language (gearwheel → Language) if you prefer.
Make the software see the sensor
- Click Advanced → Extensions at the bottom of the toolbox (also in the gearwheel menu).
- Paste
https://github.com/contactmbcrobot/pxt-mbc-sensorsinto the search box and press Enter. - Click the mbc-sensors card. An "MBC Sensors" category appears with six groups: Line, Distance, Gamepad, IMU, Camera and Device.
- To use an example: switch to JavaScript at the top right → paste the example → download the
.hexand drag it onto the MICROBIT drive.
Tip
No approval, no download: teachers just hand the URL to students. To pin a version, paste
https://github.com/contactmbcrobot/pxt-mbc-sensors#v2.0.5.
Wiring
The micro:bit I2C pins are fixed: P19 = SCL, P20 = SDA (on the edge connector, so you need a breakout board or clip adapter). On the MBC 4-pin sensor cable TX goes to SCL and RX to SDA, exactly as when wiring to an Arduino.
| Sensor | micro:bit | Note |
|---|---|---|
| SCL (TX) | P19 | I2C clock |
| SDA (RX) | P20 | I2C data |
| VCC | 3V or external 5 V | power-hungry products must not draw from the micro:bit 3V pin |
| GND | GND | with external power, share GND with the micro:bit |
- 3V pin current: V1 about 90 mA, V2 about 190 mA; on batteries the rail can drop to just over 2 V. Ranger 8-way, Controller PS4 / PS5 and the SharpShot must use external 5 V; other products can try 3V first, with external 5 V recommended on batteries.
- Logic level: MBC product I2C lines are 3.3 V, compatible with the micro:bit without a level shifter.
- This product's factory address is
0x29; products with different addresses can share the same P19 / P20 bus.
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.
First test
- Check the wiring first with the "Device → wait for device at 0x29 ready" or "device at 0x29 is ready" block.
- Download the
.hexof example 1 on this page to the micro:bit. - If the number on the LEDs changes with what is in front of the sensor, everything is connected.
FAQ
- Values are always 0? With no device connected the reporter blocks return 0 (the internal −32768 is filtered), every yes / no block returns false, and nothing throws. Check in order: wiring (SDA = P20, SCL = P19) → external power on → "device at … is ready" is true.
- On a V1, the compass and accelerometer stop working too? On V1 the external I2C bus is shared with the onboard accelerometer, so a sensor holding SDA low also kills them. V2 has a separate external bus.
- Works on and off? STM32 products (Pathfinder, Ranger, PS2, IMU) clock-stretch, and the nRF52 on the V2 has a known clock-stretching issue (errata 219), so V1 and V2 both need a bench test. ESP32 products (PS4, SharpShot) do not stretch; the extension already waits 2 ms after writing the value id.
- Two products of the same kind? They share an address: first change one with "Device → change device at … to address …" (applied after reboot), then tell the extension with that product's "use address" block.
Reading values
After adding pxt-mbc-sensors, find the blocks in the MBC Sensors category; the JavaScript form is shown too, address 0x29.
left distance (cm) leftCm
| 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 |
(distance 2-ch [left v] \([cm v]\) :: #00A4E4)
let leftCm = mbc.tof2Distance(MbcTofSide.Left, MbcDistUnit.Cm) // left distance (cm):0~120 cmReturns 0 when the sensor does not answer; check with "device at … is ready" first.
right distance (cm) rightCm
| Range | Meaning |
|---|---|
0~120 cm |
distance from the right sensor, 0~120 cm (right = sensor 1); 120 = nothing in range / sensor failed |
(distance 2-ch [right v] \([cm v]\) :: #00A4E4)
let rightCm = mbc.tof2Distance(MbcTofSide.Right, MbcDistUnit.Cm) // right distance (cm):0~120 cmReturns 0 when the sensor does not answer; check with "device at … is ready" first.
nearer distance (cm) nearCm
| Range | Meaning |
|---|---|
0~120 cm |
the smaller of left and right, 0~120 cm |
(distance 2-ch nearest \(cm\) :: #00A4E4)
let nearCm = mbc.tof2NearestCm() // nearer distance (cm):0~120 cmRelated block "on distance 2-ch nearer than 10 cm"
mbc.onTof2Near(10, function () {
})Returns 0 when the sensor does not answer; check with "device at … is ready" first.
left distance (mm) leftMm
| Range | Meaning |
|---|---|
0~1200 mm |
left sensor distance 0~1200 mm; 1200 = nothing in range / sensor failed |
(distance 2-ch [left v] \([mm v]\) :: #00A4E4)
let leftMm = mbc.tof2Distance(MbcTofSide.Left, MbcDistUnit.Mm) // left distance (mm):0~1200 mmReturns 0 when the sensor does not answer; check with "device at … is ready" first.
right distance (mm) rightMm
| Range | Meaning |
|---|---|
0~1200 mm |
right sensor distance 0~1200 mm; 1200 = nothing in range / sensor failed |
(distance 2-ch [right v] \([mm v]\) :: #00A4E4)
let rightMm = mbc.tof2Distance(MbcTofSide.Right, MbcDistUnit.Mm) // right distance (mm):0~1200 mmReturns 0 when the sensor does not answer; check with "device at … is ready" first.
init bitmap initOk
| Range | Meaning |
|---|---|
0~3 bit |
bit0 = left, bit1 = right; 1 = that sensor initialised at power-on (no retry); 3 = both OK |
No dedicated block; in JavaScript read it with mbc.readValue(address, id) (−32768 when nothing answers). Related block: "distance 2-ch [left] sensor is OK".
let initOk = mbc.readValue(0x29, 0x06) // init bitmap:0~3 bitfault bitmap fault
| 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 |
No dedicated block; in JavaScript read it with mbc.readValue(address, id) (−32768 when nothing answers). Related block: "distance 2-ch [left] sensor is OK".
let fault = mbc.readValue(0x29, 0x07) // fault bitmap:0~3 bitaverage distance (mm) avgMm
| 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 |
(distance 2-ch average \(mm\) :: #00A4E4)
let avgMm = mbc.tof2AverageMm() // average distance (mm):0~1200 mmReturns 0 when the sensor does not answer; check with "device at … is ready" first.
Examples
This page is for people who have never written code. The 5 examples start with "show a value on the LEDs" and build up to "drive a car". Everything is written for the MakeCode web editor with the MBC extension pxt-mbc-sensors v2: switch to JavaScript, paste an example and it runs; switch back to Blocks to see which blocks it becomes.
Important
- Extension pxt-mbc-sensors v2 has not been verified on hardware yet. Every example on this page compiles with the MakeCode CLI (once for V1, once for V2); value directions, ready times and power are still to be confirmed on a real board, see "to be tested" in the hardware checklist below.
- Use the Universal I2C edition of the product. The SPIKE and EV3 editions have different firmware and cannot be read by a micro:bit.
Software
| Editor | micro:bit V1 | micro:bit V2 | How |
|---|---|---|---|
| MakeCode web editor (makecode.microbit.org, Blocks / JavaScript) | ✔ (less memory, but every example here fits) | ✔ | New Project → gear → Extensions → paste https://github.com/contactmbcrobot/pxt-mbc-sensors → switch to JavaScript (top) → paste the example → Download the .hex and drag it onto the MICROBIT drive |
| MakeCode offline app (Windows / Mac) | ✔ | ✔ | Same; adding the extension the first time needs internet |
| Python Editor (MicroPython) | — | — | no MBC module yet |
- Sound: V2 has a built-in speaker; a V1 needs a buzzer or headphones on P0.
- Servos / motors: the examples use
pins.servoWritePin: one 9 g servo (SG90) on P1; for driving, two continuous-rotation servos (e.g. FS90R), left wheel P1, right wheel P2. Always power servos from an external 4.8–6 V battery pack whose − is joined to the micro:bit GND (common ground); never drive servos from the micro:bit 3V pin. - Block names: with the editor language set to English the blocks read as in the tables below; the tables also give the JavaScript call.
Before you start: hardware checklist (to be tested)
The micro:bit is a 3.3 V board. Each check must pass before an MBC product is connected; "to be tested" marks items extension v2 has not yet confirmed on real hardware.
| Check | This product | Status |
|---|---|---|
| Voltage | MBC products use 3.3 V I2C levels: connect straight to P19 / P20, no level shifter | ✔ |
| Power | about 40 mA for the two lasers, so the micro:bit 3V pin (limit about 90 mA on V1, 190 mA on V2) may do; use external 5 V if readings are unstable | to be tested |
| I2C pull-ups | the micro:bit already has 4.7 kΩ; if the product also has pull-ups, check the low level stays ≤ 0.3×VDD | to be tested |
| Clock stretching | the STM32 slave stretches the clock by default; the V2 (nRF52833) has a known issue with stretching, test on V1 and V2 | to be tested |
| Address clash | factory address 0x29, the same as the 8-ch ranger; to use two rangers change one with the "change device address" block (Device group) | — |
| Ready time | ready (F3 b0) once both lasers are initialised, about 1 s; a failed sensor reads 120 cm | to be tested |
If you read nothing: check the wiring (SDA = P20, SCL = P19) → the external power → whether the "device at … is ready" block (Device group, advanced) returns true.
Wiring (the same for every example)
| Sensor | micro:bit |
|---|---|
| SDA | P20 |
| SCL | P19 |
| VCC | 3V (or external 5 V) |
| GND | GND (the servo battery − goes here too) |
The values used on this page
Distances are in cm (0..120); 120 = nothing in front (or that sensor failed). "Left / right" is seen from behind the robot.
| Block | JavaScript | Range | Meaning | Used in |
|---|---|---|---|---|
| distance 2-ch nearest (cm) | mbc.tof2NearestCm() |
0~120 | the nearer of the two | 1, 2, 3 |
| distance 2-ch left / right (cm / mm) | mbc.tof2Distance(MbcTofSide.Left, MbcDistUnit.Cm) |
0~120 / 0~1200 | one sensor on its own | 1, 2, 4, 5 |
| on distance 2-ch nearer than … cm | mbc.onTof2Near(10, ...) |
事件 | fires once when the nearer distance drops below the limit, again only after it has gone away | 2, 5 |
| distance 2-ch average (mm) | mbc.tof2AverageMm() |
0~1200 | (left + right) ÷ 2 in mm (not used here; swap it in for finer numbers) | — |
| wait for device at … ready | mbc.waitReady(mbc.ADDR_TOF, 3000) |
true / false | waits up to 3 s, true once both lasers are up (Advanced → Device) | 1 |
Example 1: How far is it
What this example does: An LED bar shows how close the object in front is: the closer, the more LEDs. Press A to show the left sensor in cm, B the right one. Use it to check the wiring and that both lasers work.
What you need
- micro:bit V1 or V2 + USB cable
- Laser Ranger 2-ch (Universal I2C edition) + 4-pin cable
- a book or a board as the target
Wiring: As in the wiring table above: SDA → P20, SCL → P19, VCC → 3V, GND → GND.
Download: ex01_show_distance.ts (right-click, save) → MakeCode New Project → gear → Extensions → paste https://github.com/contactmbcrobot/pxt-mbc-sensors → switch to JavaScript (top) → select all, delete, paste the file → Download and drag the .hex onto the MICROBIT drive.
Code
// Distance sensor 2-ch × micro:bit example 1: how far is it (LED bar + number)
// What it does: the closer your hand, the more LEDs light; press A to show the left sensor in cm, B the right one.
// Wiring: sensor SDA → P20, SCL → P19, VCC → 3V (or external 5 V), GND → GND.
// Setup: MakeCode new project → Extensions → paste https://github.com/contactmbcrobot/pxt-mbc-sensors → switch to JavaScript, paste this whole file → download to the micro:bit.
// You see: a tick at power-on; nothing in front → all dark; hand at 60 cm → half lit; within 10 cm → almost all lit.
let busy = false
if (mbc.waitReady(mbc.ADDR_TOF, 3000)) { // ready once both laser sensors are up
basic.showIcon(IconNames.Yes)
} else {
basic.showIcon(IconNames.No) // no answer: check P19 / P20 and power
}
basic.forever(function () {
if (busy) {
basic.pause(100)
return
}
let d = mbc.tof2NearestCm() // the nearer of the two, 0..120 cm, 120 = nothing in front
led.plotBarGraph(120 - d, 120) // the closer, the longer the bar
basic.pause(100)
})
input.onButtonPressed(Button.A, function () {
busy = true
basic.showNumber(mbc.tof2Distance(MbcTofSide.Left, MbcDistUnit.Cm)) // the left sensor (seen from behind the robot)
busy = false
})
input.onButtonPressed(Button.B, function () {
busy = true
basic.showNumber(mbc.tof2Distance(MbcTofSide.Right, MbcDistUnit.Cm)) // the right sensor
busy = false
})Step by step
mbc.waitReady(mbc.ADDR_TOF, 3000): wait for both lasers to initialise, tick; X if no answer within 3 s.basic.forever: every 0.1 s readmbc.tof2NearestCm()(the nearer of the two, 0..120).led.plotBarGraph(120 - d, 120): the bar-graph block.120 − dmakes nearer objects a bigger number, so more LEDs.- Buttons A / B:
mbc.tof2Distance(MbcTofSide.Left, MbcDistUnit.Cm)reads one sensor andbasic.showNumberscrolls it;busypauses the bar meanwhile.
What you should see
- Power-on: a tick.
- Nothing in front: all dark (120).
- Board at 60 cm: half lit; move in to 10 cm: almost all lit.
- A and B: the two numbers should be about the same (board square-on).
FAQ
- Always 120? → Target too far (over 120 cm), too small or too dark (black felt reflects nothing). Try a white book.
- A or B is always 120? → That laser did not initialise or has failed. Read status bit 1 (any sensor failed) with the advanced Device blocks, then power-cycle.
- An X right at power-on (sensor not found)? → Check SDA = P20 and SCL = P19 are not swapped, that the external power is on, and with crocodile clips that no clip touches the neighbouring pad.
- All zeros in the simulator? → Normal. The MakeCode simulator has no real I2C, every read is 0; download to the micro:bit to see real values.
- No sound on a V1? → The V1 has no speaker; connect a buzzer or headphones between P0 and GND.
Example 2: Parking sensor
What this example does: Starts beeping inside 40 cm, faster the closer you get; inside 10 cm an X appears (event block, once per approach). Press A to see whether the object is more to the left or the right.
What you need
- Everything from example 1
- On a V1 also a buzzer or headphones on P0
Wiring: Same as example 1.
Download: ex02_parking_alarm.ts (right-click, save) → MakeCode New Project → gear → Extensions → paste https://github.com/contactmbcrobot/pxt-mbc-sensors → switch to JavaScript (top) → select all, delete, paste the file → Download and drag the .hex onto the MICROBIT drive.
Code
// Distance sensor 2-ch × micro:bit example 2: parking sensor (faster beeps when closer)
// What it does: starts beeping inside 40 cm, faster as you get closer; inside 10 cm it shows an X. Press A to see whether the object is more to the left or the right.
// Wiring: sensor SDA → P20, SCL → P19, VCC → 3V, GND → GND. On a V1 connect a buzzer or headphones to P0 for sound (V2 has a speaker).
// Setup: extension and paste steps as in example 1.
// You see: hand approaching → beep … beep … beepbeepbeep; inside 10 cm → X; press A → an arrow toward the nearer side.
mbc.onTof2Near(10, function () { // fires once each time the nearer distance drops below 10 cm
basic.showIcon(IconNames.No, 0)
})
basic.forever(function () {
let d = mbc.tof2NearestCm() // 0..120 cm
if (d < 40) {
led.plotBarGraph(40 - d, 40)
music.playTone(Note.A, 100) // beep for 0.1 s
basic.pause(d * 10) // 30 cm waits 0.3 s, 10 cm waits 0.1 s: closer = faster
} else {
basic.showIcon(IconNames.Happy, 0) // all clear
basic.pause(100)
}
})
input.onButtonPressed(Button.A, function () {
let l = mbc.tof2Distance(MbcTofSide.Left, MbcDistUnit.Cm)
let r = mbc.tof2Distance(MbcTofSide.Right, MbcDistUnit.Cm)
if (l < r) {
basic.showArrow(ArrowNames.West) // the left sensor is nearer
} else if (r < l) {
basic.showArrow(ArrowNames.East)
} else {
basic.showArrow(ArrowNames.North) // equal: straight ahead
}
})Step by step
mbc.onTof2Near(10, ...): an event block. Runs once when the nearer distance first drops below 10 cm → X. It fires again only after the object has moved away and come back.basic.forever: readd = mbc.tof2NearestCm().d < 40: draw the bar withled.plotBarGraph,music.playTone(Note.A, 100)beeps for 0.1 s, thenbasic.pause(d * 10): 30 cm waits 0.3 s, 10 cm waits 0.1 s, so closer = faster.d >= 40: happy face, silence.- Button A: compare the two sensors and show an arrow toward the nearer one; equal → up arrow.
What you should see
- Hand approaching slowly: happy → beeping starts → faster and faster.
- Inside 10 cm: an X flashes (then the bar carries on).
- Hand to the left, press A: left arrow.
FAQ
- The X only flashes briefly? → Normal, the next forever pass redraws the bar. To keep it longer add
basic.pause(500)inside the event. - The beeping sounds choppy? → Try
Note.C5instead ofNote.Aand 50 instead of 100, or drop the sound and keep only the bar.
Example 3: Automatic barrier (servo)
What this example does: Something inside 15 cm → the barrier opens (servo to 90°); 2 s after it leaves the barrier closes (0°). A / B raise / lower the threshold by 5. Teaches "move the motor only when the state changes".
What you need
- Everything from example 1
- one 9 g servo (SG90) with a lolly stick as the barrier
- a 4.8–6 V battery pack and jumper wires
Wiring: Sensor as in example 1. Servo orange (signal) → P1, red → external 4.8–6 V battery +, brown → battery −, and run a second wire from battery − to micro:bit GND (common ground).
Download: ex03_servo_gate.ts (right-click, save) → MakeCode New Project → gear → Extensions → paste https://github.com/contactmbcrobot/pxt-mbc-sensors → switch to JavaScript (top) → select all, delete, paste the file → Download and drag the .hex onto the MICROBIT drive.
Code
// Distance sensor 2-ch × micro:bit example 3: automatic barrier (servo)
// What it does: something inside 15 cm → the barrier opens (servo to 90°); 2 s after it leaves the barrier closes (0°). A / B raise / lower the threshold by 5.
// Wiring: sensor SDA → P20, SCL → P19, VCC → 3V, GND → GND. Servo orange (signal) → P1, red → external 4.8–6 V battery +, brown → battery − joined to micro:bit GND.
// Setup: a 9 g servo (SG90) with a lolly stick as the barrier.
// You see: hand in front → barrier lifts, tick; hand away for 2 s → barrier drops, X.
let limit = 15 // inside this many cm counts as 'something there'
let lastSeen = -10000 // time (ms) something was last seen
let open = false
pins.servoWritePin(AnalogPin.P1, 0) // start closed
basic.showIcon(IconNames.No)
basic.forever(function () {
let d = mbc.tof2NearestCm()
if (d > 0 && d < limit) {
lastSeen = control.millis() // remember the time
}
let wantOpen = control.millis() - lastSeen < 2000 // keep open for 2 s after the last sighting
if (wantOpen != open) { // move the servo only when the state changes
open = wantOpen
pins.servoWritePin(AnalogPin.P1, open ? 90 : 0)
basic.showIcon(open ? IconNames.Yes : IconNames.No, 0)
}
basic.pause(50)
})
input.onButtonPressed(Button.A, function () {
limit = Math.constrain(limit + 5, 5, 100)
basic.showNumber(limit)
})
input.onButtonPressed(Button.B, function () {
limit = Math.constrain(limit - 5, 5, 100)
basic.showNumber(limit)
})Step by step
limit = 15: the threshold;lastSeen: when something was last seen;open: is the barrier open now.- At start
pins.servoWritePin(AnalogPin.P1, 0)closes it. forever: ifdis below the threshold,lastSeen = control.millis()(note the time in ms).wantOpen = now − lastSeen < 2000: seen within the last 2 s → "should be open".wantOpen != open: only when the wanted state differs from the current one move the servo and change the icon, so the servo does not twitch.- A / B:
limit ± 5, kept between 5 and 100 withMath.constrain, and the new threshold is shown.
What you should see
- Power-on: barrier at 0°, X.
- Hand within 15 cm: barrier lifts to 90°, tick.
- Hand away: drops after 2 s, X.
- Press A: shows 20, now it opens inside 20 cm.
FAQ
- The barrier keeps opening and closing? → The object sits right at the threshold. Raise the threshold, or change 2000 to 3000 to keep it open longer.
- Servo jitters, micro:bit resets? → Power the servo from the battery pack with a common ground, never from the 3V pin.
Example 4: Follow-me car
What this example does: The car keeps 20 cm from the object in front: too far → forward, too close → back, object to the left (right sensor farther) → turn left. A = start, B = stop. The difference between the two lasers is the direction.
What you need
- A two-wheel car: two continuous-rotation servos (e.g. FS90R) as wheels plus a caster
- the ranger at the front facing forward
- a 4.8–6 V battery pack
- an A4-sized board as the "person"
Wiring: Sensor as in example 1, mounted at the front facing forward. Left continuous-rotation servo signal → P1, right → P2; both servo red wires to the 4.8–6 V battery pack +, brown to battery −, and battery − also to micro:bit GND.
Download: ex04_follow_me.ts (right-click, save) → MakeCode New Project → gear → Extensions → paste https://github.com/contactmbcrobot/pxt-mbc-sensors → switch to JavaScript (top) → select all, delete, paste the file → Download and drag the .hex onto the MICROBIT drive.
Code
// Distance sensor 2-ch × micro:bit example 4: follow-me car
// What it does: the car keeps 20 cm from the object in front (your hand or a board): too far → forward, too close → back, object to the left → turn left. A = start, B = stop.
// Wiring: sensor SDA → P20, SCL → P19, VCC → 3V, GND → GND. Left continuous-rotation servo signal → P1, right → P2; servos on a 4.8–6 V battery pack whose − is joined to micro:bit GND.
// Setup: a two-wheel car with the sensor at the front facing forward.
// You see: after A hold your hand 20 cm in front: move it back and the car follows, move it closer and the car reverses; take it away (over 60 cm) and the car stops with a puzzled face.
const TARGET = 20 // distance to keep (cm)
let running = false
// left servo P1, right servo P2 (continuous rotation); left / right = −100..100, positive = forward
function drive(left: number, right: number): void {
left = Math.constrain(left, -100, 100)
right = Math.constrain(right, -100, 100)
pins.servoWritePin(AnalogPin.P1, Math.round(90 + left * 0.9)) // 90 = stop, 180 = full forward, 0 = full reverse
pins.servoWritePin(AnalogPin.P2, Math.round(90 - right * 0.9)) // the right servo is mounted mirrored, so subtract
}
input.onButtonPressed(Button.A, function () {
running = true
basic.showIcon(IconNames.Happy, 0)
})
input.onButtonPressed(Button.B, function () {
running = false
drive(0, 0)
basic.showIcon(IconNames.No, 0)
})
basic.forever(function () {
if (!running) {
basic.pause(100)
return
}
let l = mbc.tof2Distance(MbcTofSide.Left, MbcDistUnit.Cm)
let r = mbc.tof2Distance(MbcTofSide.Right, MbcDistUnit.Cm)
let d = Math.min(l, r) // the nearer one
if (d >= 60) {
drive(0, 0) // too far: object gone, stop
basic.showIcon(IconNames.Confused, 0)
} else {
let speed = Math.constrain((d - TARGET) * 4, -60, 60) // farther than 20 cm → positive = forward; nearer → negative = back
let turn = Math.constrain((r - l) * 2, -30, 30) // right sensor farther → object is to the left → turn left
drive(speed - turn, speed + turn)
if (turn < -5) {
basic.showArrow(ArrowNames.East, 0)
} else if (turn > 5) {
basic.showArrow(ArrowNames.West, 0)
} else {
basic.showArrow(ArrowNames.North, 0)
}
}
basic.pause(30)
})Step by step
function drive(left, right): left wheel P1, right wheel P2, −100..100, positive = forward; the right servo is mirrored so it subtracts.- A:
running = true; B: stop. forever: read leftland rightr,d = Math.min(l, r).d >= 60: object gone → stop, puzzled face.speed = (d − 20) × 4: at 30 cm → +40 forward; at 10 cm → −40 back;Math.constrainkeeps it within ±60.turn = (r − l) × 2: right farther → object to the left → positive turn →drive(speed − turn, speed + turn)left wheel slower = turn left. The arrow shows the direction.
What you should see
- Press A, board 20 cm in front: car still, up arrow.
- Move the board back: the car follows; bring it closer: the car reverses.
- Move the board left: the car turns left.
- Take the board away: stop, puzzled face.
FAQ
- The car oscillates back and forth? → Change
× 4to× 3, orbasic.pause(30)to 60. - It turns the wrong way? → Sensor mounted backwards (left and right swapped): change
(r − l)to(l − r). - The car reverses after A? → Servos mounted the other way: flip the signs in
drive.
Example 5: Obstacle-avoiding car (all together)
What this example does: The car drives forward; something inside 15 cm → back up, spin toward the more open side, carry on; the LEDs count the detours and a skull flashes (event) the moment something comes inside 15 cm. A = start, B = stop.
What you need
- The car from example 4
- a few boxes as obstacles
Wiring: Same as example 4.
Download: ex05_obstacle_avoid.ts (right-click, save) → MakeCode New Project → gear → Extensions → paste https://github.com/contactmbcrobot/pxt-mbc-sensors → switch to JavaScript (top) → select all, delete, paste the file → Download and drag the .hex onto the MICROBIT drive.
Code
// Distance sensor 2-ch × micro:bit example 5: obstacle-avoiding car (all together)
// What it does: the car drives forward; something inside 15 cm → back up, spin toward the more open side, carry on; the LEDs count the detours. A = start, B = stop.
// Wiring: as example 4 (sensor P19 / P20, left wheel P1, right wheel P2, servos on their own battery, common ground).
// Setup: the two-wheel car and a few boxes as obstacles.
// You see: after A the car drives, backs up before an obstacle, turns and continues; the number goes up by 1 each detour; a skull flashes the moment something comes inside 15 cm.
const STOP_CM = 15
let running = false
let detours = 0
// left servo P1, right servo P2 (continuous rotation); left / right = −100..100, positive = forward
function drive(left: number, right: number): void {
left = Math.constrain(left, -100, 100)
right = Math.constrain(right, -100, 100)
pins.servoWritePin(AnalogPin.P1, Math.round(90 + left * 0.9)) // 90 = stop, 180 = full forward, 0 = full reverse
pins.servoWritePin(AnalogPin.P2, Math.round(90 - right * 0.9)) // the right servo is mounted mirrored, so subtract
}
mbc.onTof2Near(STOP_CM, function () { // event: flash once each time something comes inside 15 cm
basic.showIcon(IconNames.Skull, 0)
})
input.onButtonPressed(Button.A, function () {
detours = 0
running = true
basic.showArrow(ArrowNames.North, 0)
})
input.onButtonPressed(Button.B, function () {
running = false
drive(0, 0)
basic.showIcon(IconNames.No, 0)
})
basic.forever(function () {
if (!running) {
basic.pause(100)
return
}
let l = mbc.tof2Distance(MbcTofSide.Left, MbcDistUnit.Cm)
let r = mbc.tof2Distance(MbcTofSide.Right, MbcDistUnit.Cm)
if (Math.min(l, r) < STOP_CM) {
detours += 1
drive(-50, -50) // back up for 0.4 s
basic.pause(400)
if (l > r) {
drive(-40, 40) // left is more open → spin left
} else {
drive(40, -40) // spin right
}
basic.pause(500)
basic.showNumber(detours)
} else {
drive(50, 50) // clear ahead: straight
basic.showArrow(ArrowNames.North, 0)
}
basic.pause(30)
})Step by step
STOP_CM = 15: inside this is an obstacle.mbc.onTof2Near(STOP_CM, ...): event, a skull flashes once per approach (runs separately from the main loop).forever: readlandr;Math.min(l, r) < STOP_CM→ avoid.- Avoid:
detours + 1,drive(−50, −50)back for 0.4 s;l > r(left more open) →drive(−40, 40)spin left for 0.5 s, else spin right; show the count. - Clear:
drive(50, 50)straight, up arrow.
What you should see
- Press A: the car drives; near a box → skull → back up → turn → shows 1 → carries on.
- Box front-left: turns right; front-right: turns left.
- Press B: stop.
FAQ
- It does not turn enough and still hits? → Change
basic.pause(500)to 700 to turn longer, orSTOP_CMto 20 to react earlier. - Stuck going back and forth in a corner? → Neither side is open. Change the reverse time 400 to 800 to back up further before turning.
Next steps
- Every block, value and hardware note: Laser Ranger 2-ch × micro:bit
- What each value id means: Reference
- Extension source and issues: https://github.com/contactmbcrobot/pxt-mbc-sensors
More questions
- Cannot find the MBC blocks? In MakeCode Extensions, paste https://github.com/contactmbcrobot/pxt-mbc-sensors.
Still stuck? Contact us with your software and a screenshot of the program.
Downloads
- MakeCode extension pxt-mbc-sensors (paste this URL in MakeCode Extensions)
- Download centre (libraries, firmware, catalogue for every product)
Sources
- Host and software list:
_build/guides.json - Values and commands:
_build/protocol/tof2.json(single source of truth) - Setup:
_build/guides/software/microbit-makecode.en.md、_build/guides/product/tof2/microbit-makecode.en.md - Examples:
sensors/tof2/microbit-examples.md