MBC SharpShot Vision × LEGO SPIKE App (Python)

Read SharpShot Vision with SPIKE App Python in three steps

The LEGO SPIKE App (Education) runs Python too, with no firmware change. In the App, SharpShot Vision is a color sensor, and the App cannot import your own files, so the order is: first paste the reading helper at the top and pick the camera mode, then create an object and name the camera, then call update() once per loop and call its functions with that name. Work down the steps on the left and watch the program grow on the right; drag the blobs, papers, blocks or line in the simulated camera view to see what the program prints.

Verified on SPIKE hardwareRun on real hubs on 2026-11-01 with shipping firmware v1.0-261101 (Pybricks library and blocks, Pybricks built-in blocks, the official app Education and home edition, MBC Blocks website).

1

Paste the helper, pick the camera mode

A SPIKE App Python project is a single file and cannot import your own .py, so paste the whole "reading helper" at the very top (its first lines say so: copy it as is). Without it the hub does not know UniCamApp and stops with NameError.

  1. Open the LEGO SPIKE App (Education, yellow SPIKE Prime hub), create a project and choose "Python".
  2. Paste the program marked ① on the right at the top (only the first helper line shows; press "Show helper" to see it all, and "Copy program" always copies everything). The helper alone: MBC_UniCam_App_helper.py (open it in a text editor and copy all; the file has Chinese and English comments).
  3. Plug the camera into any port A–F; the hub powers it. The camera needs the SPIKE firmware (the same firmware tells the App and Pybricks apart by itself).
  4. Pick the camera mode: choose the camera mode and sub-option in the camera's MODE menu, and click the same mode number below (mode number = camera mode × 10 + sub-option).
2

Create the object: name the camera

A robot can have several sensors, so you "create an object": tell the helper which port the camera is on (port.C comes from from hub import port) and which mode it is in, and give it a name. You use that name for every reading.

Which port is the camera on?

The second number is the mode number from step 1; switch the camera menu to the same mode (the App cannot read the camera's mode, so the helper splits the numbers by what you wrote; a mismatch gives nonsense).

3

update() every loop, then use a function

App programs go in async def main(): and runloop.run(main()) starts them; wait with await runloop.sleep_ms(100) (not Pybricks' wait()). Each loop first reads once with cam.update(), then uses "name + dot + function". Functions are grouped by camera mode; dashed ones belong to another mode (clicking one switches the mode for you).

Simulated camera view: drag things in the picture and watch the output change

The view is a sketch: values come straight from where things are on screen (X 0–159 left→right, Y 0–119 top→bottom, area % = width × height ÷ whole picture); a hue code is the color the paper or block really has (red 0, yellow 40, green 80, blue 160, purple 200, white table 244, black tape 252). It is not the camera's own algorithm, and real numbers vary with the light. Color tracking assumes 4 colors were taught on the camera: color 1 red, 2 green, 3 blue, 4 yellow. In object detection you pick each shape yourself (the camera does not judge it here); objects 1, 2… are sorted by area, largest first; X, Y is the shape's centroid (white dot), the dashed box is its bounding box, and the angle is the rotation you set.

An example for every function

Every function has an example you can drop into main() (name cam); the badge shows which modes it works in. "Try it" jumps to step 3 (and switches the mode if needed).

Full examples

Press "Copy" for the whole program (the same as on the SPIKE examples page). Values the helper cannot read (counts, areas, line flags, device ID…) are all in Pybricks MicroPython (the hub needs the Pybricks firmware).

Turn toward a blob (mode 13, left wheel E, right wheel F)

        

!Teach "target 1" on the camera first and set the camera menu to mode 13. Not seen: it spins to search; the hub display shows the X cell of color 1. "Copy" gives the whole program (helper included).

PD line following + stop at a junction (mode 41 black line)

        

!Point the camera down and forward. Left = negative; it stops and beeps at a cross or T junction, and searches toward the last side when the near line is gone.

Bytes 8–15: values the helper cannot read

The camera sends 16 bytes each time. The App's color_sensor.color(), reflection() and rgbi() only get the first 8, which is what the helper uses. On real hubs (2026-11-01), App Python's device.data(port.C) returns 8 values: byte 0, byte 1, then one int16 per 2 bytes (raw red, green, blue, bytes 8–9, 10–11, 12–13), so bytes 8–13 can be read and bytes 14–15 cannot. The helper does not use it; to get the values below, split them yourself as shown at the bottom, or switch to Pybricks MicroPython (same camera, same firmware; with the Pybricks firmware on the hub everything can be read). Full layouts are in the value reference.

ModeIn bytes 8–15 (not read by the helper)
11Color tracking ① Max colorscolor 8–14 X×10 + Y (8×6 grid, top = small)
12Color tracking ② Multi-colorcolor 1–7 count
13Color tracking ③ Standardcolor 1–4 count, color 1–4 area (% of picture)
14Color tracking ④ Finecolor 1–2 count, color 1–2 area (% of picture)
21Color at points ① HueS7–14 hue
22Color at points ② Hue + saturationS4–5 hue, S5 saturation, S6 hue, S6 saturation, S7 hue, S7 saturation
23Color at points ③ Hue + sat + valueS2–3 value, S4 hue, S4 saturation, S4 value
30Color orderblock 7–13 from the left, hue
41Line ① Black linemid offset (+100), line flags (near 1 + mid 2 + far 4), junction distance %, colored marker line color, marker line count, far line width %, near line left edge (+100), near line right edge (+100)
42Line ② White linemid offset (+100), line flags (near 1 + mid 2 + far 4), junction distance %, colored marker line color, marker line count, far line width %, near line left edge (+100), near line right edge (+100)
43Line ③ Colored linemid offset (+100), line flags (near 1 + mid 2 + far 4), junction distance %, colored marker line color, marker line count, far line width %, near line left edge (+100), near line right edge (+100)
51Objects ① Object listobject 4 code (color × 10 + shape), object 4 X×10 + Y (8×6 grid, top = small), object 5 code (color × 10 + shape), object 5 X×10 + Y (8×6 grid, top = small), object 6 code (color × 10 + shape), object 6 X×10 + Y (8×6 grid, top = small), object 7 code (color × 10 + shape), object 7 X×10 + Y (8×6 grid, top = small)
52Objects ② Object detailsobject 1 angle, object 2 X (pixels), object 2 Y (pixels, top = small), object 2 width (pixels), object 2 height (pixels), object 2 angle, object 1 vertex count, object count

Splitting bytes 8–13 with device.data() (each int16: low byte = the first byte, high byte = the second):

import device
from hub import port
import runloop


async def main():
    while True:
        d = device.data(port.C)      # 8 values: byte 0, byte 1, raw red, green, blue, bytes 8-9, 10-11, 12-13
        b8, b9 = d[5] & 255, (d[5] >> 8) & 255
        b10, b11 = d[6] & 255, (d[6] >> 8) & 255
        b12, b13 = d[7] & 255, (d[7] >> 8) & 255
        print(d[0], b8, b9, b10, b11, b12, b13)   # d[0] = the raw "color" slot (5 stays 5)
        await runloop.sleep_ms(500)

runloop.run(main())

Good to know

  1. Call update() every loop. All helper functions split the 8 bytes from the last update(); without it the values never change (they start as all 0).
  2. The mode number must match the camera menu. The App cannot read the camera's mode, so the helper splits by UniCamApp(port.C, mode); object functions in the wrong mode raise ValueError, the others just give meaningless numbers.
  3. This is SPIKE App 3 style, not Pybricks. Ports are port.C from from hub import port (not Port.C), and waiting is await runloop.sleep_ms() (not wait()), so Pybricks programs cannot be pasted in. This page is for the Education App; Python in the Robot Inventor (home) App is written differently (hub.port.C.device.get() returns 6 values in the Education layout), see the home-edition part of Reading it on SPIKE.
  4. color() turns 5 into 6. The Education app's color_sensor.color() changes a 5 sent by the camera into 6 (LEGO's green code); other numbers are as sent and reflection() is not affected, so 5 and 6 in the "color" slot cannot be told apart (e.g. color 1's X cell, colors found, junction type 5 dead end, object count, total blocks). To tell them apart read device.data(port.C)[0] (the raw value) instead.
  5. Positions are grid cells, not pixels. Modes 13 and 14 use a 16×12 grid (pixel ≈ cell×10−5); modes 11, 12 and object list 51 use 8×6 (pixel ≈ cell×20−10); (0, 0) = not seen. Only object 1 in mode 52 is in pixels. Y top = small; line offset: left = negative, right = positive (looking forward from behind the robot).
  6. The helper reads bytes 0–7 only. Step 1 lists what each mode gives; for the rest (counts, areas, mid offset, flags…) see "Bytes 8–15" above or use Pybricks MicroPython. Colors are taught on the camera; the program cannot change them.