🟧 micro:bit Examples: Laser Ranger 2-ch
Back to Laser Ranger 2-ch × micro:bit | Product page | Reference
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