SPIKE beginner examples: SharpShot ESP32CAM Vision Sensor (school edition)
Back to the SharpShot product page | Have the WRO edition (HUE12)? See the WRO edition beginner examples
Note
The Pybricks programs below are the same files as on the Chinese page, so the comments inside the code are in Chinese. The English explanation under each example tells you what every line does.
This page is written for people who have never written a program before. The 5 examples start with "seeing a color as a number" and build up step by step to "the robot turns its head to face a color blob" and "sound an alarm when someone walks by". Every example comes in 3 versions; just pick the one you have:
| Version | Who it's for | How to open the example file |
|---|---|---|
| 🟨 The official LEGO SPIKE App (blocks) | Schools, first-time SPIKE users | Download the .llsp3 → open the SPIKE App → top-left "File" → "Open" → pick the file |
| 🟦 The MBC Blocks website (Chinese blocks) | People who want Chinese blocks or need more sensor data | Open the MBC SPIKE Blocks website → top menu "File → Open" (or press Ctrl+O) → pick the downloaded .abp |
| 🐍 Pybricks (Python text code) | People who want to learn typed programming | Open code.pybricks.com → "Import a file" in the file panel on the left → import both the example file and MBC_cam_school_Lib.py → open the example → press ▶ to run |
Important
- The MBC Blocks website and Pybricks need the hub flashed with the Pybricks firmware first (on the MBC Blocks website, the top menu "SPIKE Hub → Install/Update Pybricks firmware" does it, about 3 minutes; you can switch back to the original LEGO firmware with the SPIKE App any time). The official LEGO App needs no change.
- The official LEGO App used here is the Education edition (SPIKE 3). In the home edition (Robot Inventor), "color" only goes 0 to 10 (one tenth of the Education edition), so you have to change the numbers in example 2 yourself.
- The numbers on this page are for the firmware currently shipping (hue 0 to 100). How to check: after power-up, look at the
Xnumber at the top of the sensor screen. If it tops out around 98, you have the new version; if it goes above 100 (up to 159), it is the old firmware; please contact us for an update first.
Note
Example 6 at the end is an advanced bonus, Pybricks only: the value it uses lives in a new mode of the sensor firmware from 2026-10 onward, which the blocks in the official LEGO App and the MBC Blocks website cannot read.
Before you start: set the color to look for on the sensor
The SharpShot has to be "told" which color to look for first, and that is only done with the buttons on the sensor body (a program cannot change it). The setting is saved in the sensor and survives a reboot.
Do these 3 things first
- Plug the sensor into the hub and turn the hub on. If the sensor screen stays on "LEGO Sync… / connect…", it is waiting for the hub; the picture only appears after the hub is on (you cannot set it up without a hub).
- Put the colored brick you want to use in front of the lens first. The picture freezes when you enter setup, so place the brick before you press.
- Buttons: the body has three buttons, Left, OK (middle), Right, plus one side button. Short-press the side button = enter the menu / go back one level.
Setup 1: COLOR (see a color, gives "hue", for examples 1 and 2)
- When the top of the screen shows
RUN, short-press the side button →SET 1:COLORappears at the top. - Press OK →
SET X: the picture freezes; use Left/Right to move the red vertical line onto the brick. - Press OK →
SET Y: use Left/Right to move the green horizontal line onto the brick. - Press OK →
TOL_HUE(color tolerance, keep the default 15 for now) → press OK →TOL_STA(keep the default) → press OK again to save and return toRUN.
Setup 2: TRACK (track a blob, gives "blob X/Y/area", for examples 3 and 4)
- On the
RUNscreen, short-press the side button → press Right to switch toSET 2:TRACK→ press OK. SET X,SET Y: the center of the crosshair must be right on the middle of the blob (it only samples the color at that one center point).TOL_HUE,TOL_STA: everything on screen with the same color as the target gets marked; adjust until only your brick is marked.MIN AREA(smallest blob): if small specks in the background get boxed, raise it a little → press OK to save; a tracking box appears on screen.
Warning
The picture is upside down after changing a camera setting. What now? The current firmware has a known issue: changing anything in
SET MODE CAM(the camera menu), including turning on the fill lightFlash LED, flips the picture upside down, and the blob Y flips with it. The fix: in the same camera menu, switchV-Flipto ON; the picture is upright again and the setting is remembered.
Should I turn on the fill light? Not yet. The ESP32-CAM fill light is very bright; LEGO brick surfaces reflect it and turn white, so the color gets harder to recognize, not easier. Only turn it on when the field is really dark (and check the V-Flip note above afterward).
How do I know the setup worked? Back on the RUN screen, the top of the display keeps showing H…(hue) A…(area) X… Y… M…(motion). These are exactly the numbers the example programs read, so look at the screen first and then put those numbers in your program; that is the most accurate way.
Values used on this page
| Name | Range | Meaning |
|---|---|---|
| Hue (color) | -1, 0 to 100 | Red 0 (100 is red too), yellow about 17, green about 33, cyan about 50, blue about 67, magenta about 83. -1 = black, white, gray (no color) |
| Blob X | 0 to 98 | Left/right position of the blob in the picture: left 0, right 98, center about 50 |
| Blob Y | 1 to 75 | Up/down position: small at the bottom, large at the top (bottom 1, top 75), middle about 37 |
| Blob area | 0 to 100 | How big the blob is. 0 = no blob found |
| Blob width | 0 to 98 | How wide the blob is. 0 = no blob found (the MBC Blocks website and Pybricks use this to check) |
| Motion value | 0 to 100 | How much the whole picture changed compared with the previous frame; the number goes up when something moves |
Tip
- If you skipped "Setup 1: COLOR", hue is always 0, which is the same as red! The program thinks it sees red when really nothing has been set up yet.
- When no blob is found, X and Y are both 0, which looks like "bottom-left corner". So always check whether a blob was found first (is area or width 0?) before you look at X.
In the official LEGO App the SharpShot shows up as a "Color Sensor", so you read it with the Color Sensor blocks:
| Official block | What you get |
|---|---|
| color | Hue (-1, 0 to 100); compare it as a number |
| reflected light | Motion value (0 to 100) |
| raw red (under "More Sensors") | Blob X |
| raw green | Blob Y |
| raw blue | Blob area (0 = not found) |
Caution
In the official App, do not use the "color is [red]?" block where you pick a color; it compares against LEGO's own color codes, not the SharpShot hue. Always put "color" into a variable and compare the numbers.
The data read by the MBC Blocks website and Pybricks (the "SharpShot school edition" blocks on the Blocks website, MBC_cam_school_Lib.py in Pybricks) adds saturation, brightness, blob width and blob height on top of what the official App gets, but has no area, so "blob width > 0" is used as "found" instead.
Example 1: What color do you see?
What this example does: The hub display keeps showing the "hue" number the SharpShot sees. Put bricks of different colors at the spot you chose in "Setup 1" and the number changes.
What you need
- 1 SPIKE hub
- 1 SharpShot (with "Setup 1: COLOR" done)
- One red, one green, one blue and one white brick
How to connect: SharpShot on port C.
Download the program
| Official LEGO App | MBC Blocks website | Pybricks |
|---|---|---|
| ex01_show_hue.llsp3 | ex01_show_hue.abp | ex01_show_hue.py + library |
🟨 Official LEGO App blocks

🟦 MBC Blocks website blocks

Pybricks code
# 神攝手(學校版)範例 1:看到什麼顏色(主機螢幕顯示色相)
# 接線:神攝手 → C 埠
from pybricks.hubs import PrimeHub
from pybricks.parameters import Port
from pybricks.tools import wait
from MBC_cam_school_Lib import MBC_CAM_SCHOOL
hub = PrimeHub()
cam = MBC_CAM_SCHOOL(Port.C) # 神攝手插在 C 孔
while True:
hue = cam.hue() # 色相:0~100(紅 0/100、綠約 33、藍約 67);-1 = 黑白灰
print(hue) # 電腦畫面印出來(比較快看到)
hub.display.text(str(hue)) # 主機螢幕一個字一個字顯示
wait(500) # 等 0.5 秒再讀下一次Step by step through the program
- Repeat forever: the blocks inside keep running until you press stop.
- Read the hue: the official App uses the "color" block and puts it into the variable "hue" (a variable = a box with a name that holds one number); the MBC Blocks website uses "SharpShot school edition C hue"; Pybricks uses
cam.hue(). - Show it on the display: the number scrolls across one character at a time. The MBC Blocks website and Pybricks also print it on the computer screen, which is quicker to read.
- Wait 0.5 seconds before reading again.
What you should see
- Red brick: about 0 to 5 or 95 to 100.
- Green brick: about 30; blue brick: about 65 (the lighting is different in every room, so the numbers vary a little).
- White paper, black brick: -1 (no color).
Common problems
- It reads 0 no matter what I put there? → "Setup 1: COLOR" has not been done yet.
- The number keeps jumping around? → Classroom lights flicker, and pale colors jump the most; use a brighter, more saturated brick, or move it closer.
- The number changed after moving to another room? → Different lighting; do "Setup 1" again.
Example 2: Beep when you see red
What this example does: When the SharpShot sees red, the light in the middle of the hub turns red and the hub beeps; for any other color the light turns off.
What you need: Same as example 1.
How to connect: SharpShot on port C.
Download the program
| Official LEGO App | MBC Blocks website | Pybricks |
|---|---|---|
| ex02_red_beep.llsp3 | ex02_red_beep.abp | ex02_red_beep.py + library |
🟨 Official LEGO App blocks

🟦 MBC Blocks website blocks

Pybricks code
# 神攝手(學校版)範例 2:看到紅色就亮紅燈、嗶一聲
# 接線:神攝手 → C 埠
from pybricks.hubs import PrimeHub
from pybricks.parameters import Color, Port
from pybricks.tools import wait
from MBC_cam_school_Lib import MBC_CAM_SCHOOL
hub = PrimeHub()
cam = MBC_CAM_SCHOOL(Port.C)
while True:
hue = cam.hue()
if 0 <= hue <= 5 or hue >= 95: # 紅色在色相的兩端:0 附近和 100 附近都是紅
hub.light.on(Color.RED)
hub.speaker.beep(880, 100) # 頻率 880 Hz,響 0.1 秒
else: # 其他顏色,或 -1(黑白灰)
hub.light.off()
wait(100)Step by step through the program
- Read the hue into a variable.
- If hue is between 0 and 5, or hue ≥ 95 (the official App writes it as "> 94", same meaning) → red light, beep. Red sits at both the start and the end of the hue scale, so you have to check both ends.
- Else (any other color, or -1 for no color) → light off.
- Wait 0.1 seconds and check again.
What you should see: Put the red brick at the setup spot → red light + continuous beeping; swap in green or white paper → light off, no sound.
Common problems
- It beeps all the time even with nothing there? → Hue is 0, which means "Setup 1: COLOR" has not been done (hue is 0 before setup, same as red).
- Orange beeps too? → Orange hue is very close to red (about 4 to 10); make the "5" smaller, for example 3.
- My red brick reads 7 and does not beep? → Use example 1 to see what your red reads, then change the "5" to that number plus a little.
- How do I pick the light color in the official App? → Click the color dot on the "set Power Button light to" block.
Example 3: Which side is the blob on?
What this example does: The hub display uses an arrow to tell you where the blob is in the picture: on the left → ⬅, on the right → ➡, in the middle → ⬆, not found → ✕.
What you need: Same as example 1; the sensor must have "Setup 2: TRACK" done first.
How to connect: SharpShot on port C.
Download the program
| Official LEGO App | MBC Blocks website | Pybricks |
|---|---|---|
| ex03_blob_arrow.llsp3 | ex03_blob_arrow.abp | ex03_blob_arrow.py + library |
🟨 Official LEGO App blocks

🟦 MBC Blocks website blocks

Pybricks code
# 神攝手(學校版)範例 3:色塊在哪一邊(主機螢幕顯示箭頭)
# 接線:神攝手 → C 埠
from pybricks.hubs import PrimeHub
from pybricks.parameters import Icon, Port
from pybricks.tools import wait
from MBC_cam_school_Lib import MBC_CAM_SCHOOL
hub = PrimeHub()
cam = MBC_CAM_SCHOOL(Port.C)
while True:
x = cam.blob_x() # 色塊 X:左 0 ~ 右 98,中間約 50
if not cam.found(): # 沒找到色塊(這時 X 是 0,不能拿來判斷)
hub.display.icon(Icon.FALSE) # 顯示 ✕
elif x < 35:
hub.display.icon(Icon.ARROW_LEFT)
elif x > 65:
hub.display.icon(Icon.ARROW_RIGHT)
else: # 35 ~ 65 都算中間
hub.display.icon(Icon.ARROW_UP)
wait(100)Step by step through the program
- Read blob X, then read "was it found": the official App checks "is raw blue (area) 0"; the MBC Blocks website checks "blob width = 0"; Pybricks uses
cam.found(). - If not found → show ✕ (X is 0 at this point and cannot be used for the decision, so this check comes first).
- Else, if X < 35 → left arrow.
- Else, if X > 65 → right arrow.
- Otherwise (35 to 65) → up arrow, meaning it is in the middle.
What you should see: Hold the colored block in front of the lens and move it slowly from left to right; the arrow goes ⬅ → ⬆ → ➡. Take the block away and it becomes ✕.
Common problems
- Left and right arrows are swapped? → The camera is mounted the opposite way from the picture. In the camera menu toggle
H-Mirroronce (then checkV-Flip, see the warning above). - An arrow shows even when the blob is gone? → Something of the same color in the background is being tracked: go back to "Setup 2", lower
TOL_HUEand raiseMIN AREA. - Why is the middle 35 to 65 and not just 50? → Leaving a band that "counts as the middle" keeps the arrow from flickering.
Example 4: Turn to follow the blob
What this example does: The robot turns in place to keep the blob in the center of the camera picture. Blob on the left → turn left; on the right → turn right; lined up (or nothing in view) → stop.
What you need
- Everything from example 3, plus
- A two-wheel car (two motors as wheels) with the SharpShot mounted at the front, lens facing forward
- A colored block that you have done "Setup 2: TRACK" on
How to connect
- SharpShot on port C
- Left wheel motor on E, right wheel motor on F
Download the program
| Official LEGO App | MBC Blocks website | Pybricks |
|---|---|---|
| ex04_turn_to_blob.llsp3 | ex04_turn_to_blob.abp | ex04_turn_to_blob.py + library |
🟨 Official LEGO App blocks

🟦 MBC Blocks website blocks

Pybricks code
# 神攝手(學校版)範例 4:轉頭追色塊(色塊在左就往左轉、在右就往右轉、在中間就停)
# 接線:神攝手 → C 埠;左輪馬達 → E 埠;右輪馬達 → F 埠
from pybricks.parameters import Direction, Port
from pybricks.pupdevices import Motor
from pybricks.robotics import DriveBase
from pybricks.tools import wait
from MBC_cam_school_Lib import MBC_CAM_SCHOOL
cam = MBC_CAM_SCHOOL(Port.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:
x = cam.blob_x()
if not cam.found(): # 沒看到色塊 → 停下來
robot.stop()
elif x < 40: # 色塊在左邊 → 原地左轉(速度 0,每秒轉 60 度)
robot.drive(0, -60)
elif x > 60: # 色塊在右邊 → 原地右轉
robot.drive(0, 60)
else: # 色塊在中間 → 已經對準,停
robot.stop()
wait(50)Step by step through the program
- Tell the hub where the wheels are: the official App uses "set movement motors to E+F"; the MBC Blocks website and Pybricks use "drive base: left wheel E, right wheel F".
- Set the speed: 20% in the official App; the other two use "60 degrees per second". Turning too fast blurs the camera picture, so turn slowly.
- If no blob found → stop.
- Else if X < 40 (blob on the left) → turn left in place (official App: steer -100).
- Else if X > 60 (blob on the right) → turn right in place (official App: steer 100).
- Else (40 to 60, lined up) → stop.
What you should see: Hold the block in front of the car and walk slowly to the left; the car turns to follow. Stop, and the car stops facing the block.
Common problems
- Blob on the left but the car turns right and keeps turning away? → Left and right are swapped: flip the sign of both turn numbers (official App: -100 and 100; the other two: -60 and 60), or toggle
H-Mirroras described in example 3. - It keeps wobbling left and right? → Turning too fast. Lower the speed in the official App (for example 15%); in the other two change 60 to 40. You can also widen the "middle" band (change 40/60 to 35/65).
- The car turns in place in a strange way? → 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 switch the "forward" direction of both wheels to the other option; Pybricks: change the left wheel to
Direction.CLOCKWISEand the right wheel toMotor(Port.F, Direction.COUNTERCLOCKWISE).
Example 5: Motion-detection alarm
What this example does: Use the hub as a "security guard" that stays still. When something moves in front of the camera (someone walks past, a hand waves), the hub turns on the red light, beeps, and shows on the display how many times it has happened; when nothing moves, the light is green.
What you need: SPIKE hub, SharpShot (no color setup needed for this example).
How to connect: SharpShot on port C, camera pointed at a doorway or a desk, the whole thing sitting still and steady.
Download the program
| Official LEGO App | MBC Blocks website | Pybricks |
|---|---|---|
| ex05_motion_alarm.llsp3 | ex05_motion_alarm.abp | ex05_motion_alarm.py + library |
🟨 Official LEGO App blocks

🟦 MBC Blocks website blocks

Pybricks code
# 神攝手(學校版)範例 5:動態偵測警報(有東西在鏡頭前動,就亮紅燈、嗶一聲、記一次)
# 接線:神攝手 → C 埠。機器人要放著不動!
from pybricks.hubs import PrimeHub
from pybricks.parameters import Color, Port
from pybricks.tools import wait
from MBC_cam_school_Lib import MBC_CAM_SCHOOL
hub = PrimeHub()
cam = MBC_CAM_SCHOOL(Port.C)
count = 0 # 警報響了幾次
while True:
if cam.motion() > 20: # 動態值:畫面變化越大數字越大(0~100)
hub.light.on(Color.RED)
hub.speaker.beep(880, 200)
count = count + 1
hub.display.number(count) # 螢幕顯示第幾次
print(count)
wait(1000) # 等 1 秒,同一個動作不要重複算
else:
hub.light.on(Color.GREEN) # 沒動靜:綠燈
wait(100)Step by step through the program
- Set "count" to 0 at the start (a variable that remembers how many times the alarm has gone off).
- Read the motion value: the official App uses "reflected light"; the MBC Blocks website uses "SharpShot school edition C motion value"; Pybricks uses
cam.motion(). - If motion value > 20 → red light, beep, add 1 to count, show count on the display, then wait 1 second (so one movement is not counted several times).
- Else → green light.
- Wait 0.1 seconds and check again.
What you should see: Wave a hand in front of the camera → red light + beep + display shows 1; wave again → 2… Keep your hands still and the light stays green.
Common problems
- It keeps going off with nobody moving? → "20" is too small. First print
cam.motion()in Pybricks, or watch theMnumber on the sensor screen, to see what it reads when nothing is moving, then set the threshold a bit above that. Flickering classroom lights and trees moving outside the window both push the number up. - Waving does nothing? → The threshold is too high; make it smaller (for example 10), or move your hand closer to the lens.
- Can I put it on a moving car? → No. When the car itself is moving, the whole picture keeps changing and the motion value stays high. The motion value is only meaningful when the robot is standing still.
Example 6 (advanced): Blob area: stop when close
Note
This example is Pybricks only. The "blob area" it uses is a number only available in sensor firmware from 2026-10 onward (two extra bytes in mode 9); the blocks in the official LEGO App and the current blocks on the MBC Blocks website cannot read it. The code itself is the example, so there are no screenshots.
What this example does: The robot drives toward a blob of the color you set up; the blob gets bigger in the picture the closer it is. Once the area reaches 1500 or more, the car stops and shows a green light. No blob in view → stop, red light; still driving → yellow light, and if the blob drifts left or right the car corrects its direction on the way.
What you need: Same as example 4 (the car plus a colored brick or box).
How to connect: SharpShot on port C, mounted at the front of the car; left wheel motor on E, right wheel motor on F. First set the 2:TRACK color on the sensor as described in "Before you start".
Download the program
| Pybricks |
|---|
| ex06_area_stop.py + library |
Pybricks code
# 神攝手(學校版)範例 6(進階):色塊面積:往色塊開過去,色塊在畫面裡變得夠大(夠近)就停
# 接線:神攝手 → C 埠(裝在車頭);左輪馬達 → E 埠;右輪馬達 → F 埠。先在感應器上設定 2:TRACK 的顏色
# 只有 Pybricks 版:面積是感應器韌體 2026-10 以後才有的數字,官方 App 和積木網站的積木讀不到
from pybricks.hubs import PrimeHub
from pybricks.parameters import Color, Direction, Port
from pybricks.tools import wait
from MBC_cam_school_Lib import MBC_CAM_SCHOOL
from pybricks.pupdevices import Motor
from pybricks.robotics import DriveBase
hub = PrimeHub()
cam = MBC_CAM_SCHOOL(Port.C)
left = Motor(Port.E, Direction.COUNTERCLOCKWISE)
right = Motor(Port.F)
robot = DriveBase(left, right, wheel_diameter=56, axle_track=112)
while True:
area = cam.area() # 色塊面積 = 寬 × 高(0~7500);沒找到是 0。越近越大
x = cam.blob_x() # 色塊左右位置 0~98,50 = 中間
if area == 0: # 沒看到色塊 → 停
robot.stop()
hub.light.on(Color.RED)
elif area >= 1500: # 夠大了 = 夠近了 → 停、綠燈
robot.stop()
hub.light.on(Color.GREEN)
else: # 還小 = 還遠 → 往色塊開過去,偏左偏右順便修正
robot.drive(80, (x - 50) * 2)
hub.light.on(Color.YELLOW)
print('面積', area, ' X', x)
wait(50)Step by step through the program
cam.area(): blob area = width × height (0 to 7500), 0 when nothing is found. It reads mode 9, the same as X and Y in examples 3 and 4, so no mode switch is needed.- If area = 0 → nothing in view → stop, red light.
- Else, if area ≥ 1500 → close enough → stop, green light.
- Otherwise → drive forward (80 mm per second) with steering = (X − 50) × 2, so the car steers toward whichever side the blob is on (same idea as example 4).
- The library also has
cam.blob_xya()(gets [X, Y, area] in one call, reading mode 6) pluscam.device_id()andcam.firmware_version().
What you should see: Put a red brick 50 cm away: yellow light, the car drives toward the brick; the area grows as it gets closer, and it stops at roughly 15 cm with a green light. Take the brick away: red light.
Common problems
- It stops while still far away / only stops after bumping into it? → "1500" depends on the size of your brick: print
cam.area()in Pybricks, read the area at the distance where you want it to stop, and use that number. - Area is always 0 but example 3 can see X? → The sensor firmware is too old (before 2026-10) and has no area; please update the firmware. On old firmware you can compute "width × height" yourself for now:
cam.blob_w() * cam.blob_h(). - Left/right correction is backwards? → The motors are mounted the wrong way around; swap them as described in the example 4 common problems.
Things to watch out for (read this first)
- The picture freezes and the values stop updating while you are in the menu: do not press the sensor's side button while a program is running; finish the setup, return to
RUN, then run the program. - If the hub is disconnected for more than 3 seconds, the sensor picture freezes while it waits to reconnect. That is normal; just run the program again.
- Black, white and gray are all -1: the current firmware cannot tell black from white.
- Still being verified on real hardware:
- The current firmware (2026-10 version) was just rebuilt with updated development tools. The number ranges above were compiled from the source code and have not yet been measured one by one on the new firmware; if your readings differ, please tell us.
- The MBC Blocks website and Pybricks use "blob width > 0" to decide whether a blob was found because those two have no area reading; we assume "found but width is 0" almost never happens, but this has not been confirmed on hardware.
- The threshold of 20 in example 5 and the red range 0 to 5 / 95 to 100 in example 2 are suggested values estimated from the source code; measure with example 1 on your own field and adjust.
Next steps
- For more precise blob tracking, change example 4 to "turn by as much as it is off": steering = (X − 50) × some number (like P control in line following).
- Full SharpShot documentation: product page