This is your program. It is about twenty lines. A real car moves on the floor. นี่คือโปรแกรมของคุณ ยาวประมาณยี่สิบบรรทัด รถจริงวิ่งบนพื้น 这就是你的程序。大概二十行。真的小车在地上跑。
🇬🇧 English
Most Python programs only change the screen. This one changes the room.
You send a very short message. The robot hears it. Then the wheels turn.
The message is tiny. A# means "go forward". 0# means "stop".
You do not need to know Bluetooth. One library does that work for you.
🇹🇭 ไทย
โปรแกรม Python ส่วนใหญ่เปลี่ยนแค่หน้าจอ แต่อันนี้เปลี่ยนทั้งห้อง
คุณส่งข้อความสั้นมาก หุ่นยนต์ได้ยิน แล้วล้อก็หมุน
ข้อความเล็กมาก A# แปลว่า "เดินหน้า" 0# แปลว่า "หยุด"
คุณไม่ต้องรู้เรื่องบลูทูธ มีไลบรารีทำงานนั้นให้คุณ
🇨🇳 中文
大多数 Python 程序只改变屏幕。这个程序改变整个房间。
你发一条很短的消息。机器人听到了。然后轮子就转。
消息很小。A# 是"往前走"。0# 是"停"。
你不用懂蓝牙。有一个库帮你做这件事。
🚗 Meet the robot · รู้จักหุ่นยนต์ · 认识这台机器人
The car from above. This is a drawing, not a photo. รถมองจากด้านบน นี่คือภาพวาด ไม่ใช่ภาพถ่าย 从上面看这台小车。这是一张画,不是照片。
🇬🇧 English
The car has two wheels with motors. It has one small ball wheel at the back.
The brain is a micro:bit. It is a small computer for schools.
The micro:bit has a radio inside. That radio is Bluetooth.
Your laptop talks to that radio. So you do not need a cable.
🇹🇭 ไทย
รถมีล้อสองล้อที่มีมอเตอร์ ด้านหลังมีลูกกลมเล็ก ๆ หนึ่งลูก
สมองของรถคือ micro:bit เป็นคอมพิวเตอร์เล็ก ๆ สำหรับโรงเรียน
ใน micro:bit มีวิทยุอยู่ข้างใน วิทยุนั้นคือบลูทูธ
แล็ปท็อปของคุณคุยกับวิทยุนั้น คุณจึงไม่ต้องใช้สาย
🇨🇳 中文
小车有两个带马达的轮子。后面还有一个小圆球轮。
它的大脑是 micro:bit。这是给学校用的小电脑。
micro:bit 里面有一个无线电。那就是蓝牙。
你的电脑跟那个无线电说话。所以不用接线。
มอเตอร์สองตัว · 两个马达
ไฟสี · 彩色灯
ลำโพงเล็ก · 蜂鸣器
ตาวัดระยะ · 测距的眼睛
เซ็นเซอร์เส้น · 循线传感器
บลูทูธ · 蓝牙
🧰 What you need first · สิ่งที่ต้องมีก่อน · 先要准备什么
🇬🇧 English
You need four things. Check them now.
1. Python on your computer. The Start Python page shows you how.
2. A computer with Bluetooth. Most laptops have it.
3. The car, with good batteries.
4. The Bluetooth program on the car. Your teacher puts it there once.
🇹🇭 ไทย
คุณต้องมีสี่อย่าง ตรวจดูตอนนี้เลย
1. Python บนเครื่องของคุณ หน้า เริ่มเขียน Python บอกวิธีไว้แล้ว
2. คอมพิวเตอร์ที่มีบลูทูธ แล็ปท็อปส่วนใหญ่มี
3. ตัวรถ พร้อมแบตเตอรี่ที่ยังดีอยู่
4. โปรแกรมบลูทูธบนตัวรถ ครูใส่ให้ครั้งเดียว
🇨🇳 中文
你需要四样东西。现在就检查一下。
1. 电脑上要有 Python。开始学 Python 那一页教你怎么装。
2. 一台有蓝牙的电脑。大部分笔记本都有。
3. 小车,还要有电的电池。
4. 车上要有蓝牙程序。老师装一次就行。
โปรแกรมบลูทูธ · 蓝牙程序 📺Remote program For the handheld remote instead.
โปรแกรมรีโมท · 遥控器程序
1 Get the library · ติดตั้งไลบรารี · 装一个库
🇬🇧 English
A library is code that other people wrote. You can use it for free.
We use one library. Its name is bleak. It speaks Bluetooth for you.
Type this line in your terminal. Then press Enter.
🇹🇭 ไทย
ไลบรารีคือโค้ดที่คนอื่นเขียนไว้ คุณใช้ได้ฟรี
เราใช้ไลบรารีตัวเดียว ชื่อว่า bleak มันพูดบลูทูธแทนคุณ
พิมพ์บรรทัดนี้ในเทอร์มินัล แล้วกด Enter
🇨🇳 中文
库就是别人写好的代码。你可以免费用。
我们只用一个库,叫 bleak。它替你说蓝牙。
在终端里敲这一行,然后按 Enter。
pythonpython3 -m pip install bleak
2 Find the robot · หาหุ่นยนต์ให้เจอ · 找到机器人
🇬🇧 English
First we look for the car. The car shouts its name every second.
Its name starts with BBC micro:bit. We look for that name.
Make a new file. Call it find.py. Put this code in it.
🇹🇭 ไทย
ก่อนอื่นเราหารถก่อน รถจะประกาศชื่อตัวเองทุกวินาที
ชื่อของมันขึ้นต้นด้วย BBC micro:bit เราหาชื่อนั้น
สร้างไฟล์ใหม่ ตั้งชื่อว่า find.py แล้วใส่โค้ดนี้ลงไป
🇨🇳 中文
先找车。小车每秒都在喊自己的名字。
它的名字以 BBC micro:bit 开头。我们就找这个名字。
新建一个文件,叫 find.py,把这段代码放进去。
import asyncio
from bleak import BleakScanner
async def main():
print("Looking for the robot...")
devices = await BleakScanner.discover(timeout=10)
for d in devices:
if d.name and "micro:bit" in d.name:
print("Found it:", d.name)
asyncio.run(main())
pythonpython3 find.py
🇬🇧 English
The word async is new. It means "this can wait".
Bluetooth is slow. The program must wait for it.
await means "wait here, then go on".
Copy this shape for now. You will understand it later.
🇹🇭 ไทย
คำว่า async เป็นคำใหม่ แปลว่า "อันนี้รอได้"
บลูทูธช้า โปรแกรมต้องรอมัน
await แปลว่า "รอตรงนี้ แล้วค่อยไปต่อ"
ตอนนี้ลอกรูปแบบนี้ไปก่อน เดี๋ยวคุณจะเข้าใจเอง
🇨🇳 中文
async 是个新词。意思是"这里可以等"。
蓝牙很慢。程序必须等它。
await 的意思是"在这儿等一下,然后继续"。
先照着抄。以后你会明白的。
3 Turn on a light · เปิดไฟหนึ่งดวง · 点亮一盏灯
🇬🇧 English
Now we send our first command. We start with a light, not a wheel.
A light is safe. The car cannot run away.
G# makes the light red. M# turns it off.
The long number is an address. It is the robot's letter box.
🇹🇭 ไทย
ตอนนี้เราส่งคำสั่งแรก เริ่มที่ไฟก่อน ยังไม่ใช่ล้อ
ไฟปลอดภัย รถวิ่งหนีไม่ได้
G# ทำให้ไฟเป็นสีแดง M# ปิดไฟ
ตัวเลขยาว ๆ คือที่อยู่ มันคือตู้จดหมายของหุ่นยนต์
🇨🇳 中文
现在发第一条命令。先点灯,不动轮子。
灯很安全。小车跑不掉。
G# 把灯变红。M# 把灯关掉。
那串长长的数字是地址。就像机器人的信箱。
import asyncio
from bleak import BleakScanner, BleakClient
BOX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
async def main():
robot = await BleakScanner.find_device_by_filter(
lambda d, a: d.name and "micro:bit" in d.name)
print("Found it:", robot.name)
async with BleakClient(robot) as car:
await car.write_gatt_char(BOX, b"G#") # red
await asyncio.sleep(2)
await car.write_gatt_char(BOX, b"M#") # off
asyncio.run(main())
🇬🇧 English
Look at b"G#". The letter b is important.
It means "send bytes, not letters". Radios send bytes.
async with opens the door and closes it again.
When the block ends, Python hangs up for you.
🇹🇭 ไทย
ดูที่ b"G#" ตัวอักษร b สำคัญมาก
มันแปลว่า "ส่งเป็นไบต์ ไม่ใช่ตัวอักษร" วิทยุส่งไบต์
async with เปิดประตูแล้วปิดให้เอง
พอจบบล็อก Python จะวางสายให้คุณ
🇨🇳 中文
看 b"G#"。前面那个 b 很重要。
它的意思是"发字节,不是字母"。无线电发的是字节。
async with 会开门,也会自己关门。
这段代码结束时,Python 帮你挂断。
4 Make one helper · สร้างตัวช่วยหนึ่งตัว · 写一个小帮手
🇬🇧 English
write_gatt_char is a long name. We must type it many times.
So we make a small function. We call it say.
Now we write await say(car, "G"). That is much shorter.
The robot needs a small rest. So we sleep for a moment.
🇹🇭 ไทย
write_gatt_char เป็นชื่อที่ยาว เราต้องพิมพ์หลายครั้ง
เราจึงสร้างฟังก์ชันเล็ก ๆ ตั้งชื่อว่า say
ตอนนี้เราเขียน await say(car, "G") สั้นกว่ากันเยอะ
หุ่นยนต์ต้องพักนิดหนึ่ง เราจึงหยุดรอสักครู่
🇨🇳 中文
write_gatt_char 名字很长。我们要打很多次。
所以写一个小函数,叫 say。
现在只要写 await say(car, "G")。短多了。
机器人需要一点点休息。所以我们等一下下。
Grey lines are already in your file. Add the white lines. บรรทัดสีเทาคือของที่มีอยู่แล้ว ให้เพิ่มบรรทัดสีขาว 灰色的行你已经有了。加上白色的行。
BOX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
async def say(car, command):
await car.write_gatt_char(BOX, command.encode() + b"#")
await asyncio.sleep(0.05)
async def main():
...
🇬🇧 English
Why do we sleep for 0.05 seconds? The robot is small.
It reads one command at a time. Fast messages get lost.
This tiny rest fixes that. It is a real bug, and this is the fix.
🇹🇭 ไทย
ทำไมต้องหยุด 0.05 วินาที เพราะหุ่นยนต์ตัวเล็ก
มันอ่านคำสั่งได้ทีละคำสั่ง ถ้าส่งเร็วไป ข้อความจะหาย
การพักสั้น ๆ นี้แก้ปัญหาได้ นี่คือบั๊กจริง และนี่คือวิธีแก้
🇨🇳 中文
为什么要等 0.05 秒?因为机器人很小。
它一次只读一条命令。发太快,消息就丢了。
这一点点休息就能解决。这是真的 bug,这就是解法。
5 Make it move · ทำให้มันเคลื่อนที่ · 让它动起来
🇬🇧 English
Now the wheels. A is forward. 0 is stop.
Always write the stop line. A car with no stop keeps going.
It goes for one second. Then it stops.
🇹🇭 ไทย
ทีนี้มาที่ล้อ A คือเดินหน้า 0 คือหยุด
เขียนบรรทัดหยุดเสมอ รถที่ไม่มีคำสั่งหยุดจะวิ่งต่อไป
มันวิ่งหนึ่งวินาที แล้วก็หยุด
🇨🇳 中文
现在动轮子。A 是前进,0 是停。
一定要写停的那一行。没有停,车就一直跑。
它走一秒,然后停下来。
async with BleakClient(robot) as car:
await car.write_gatt_char(BOX, b"G#") # red
await asyncio.sleep(2)
await car.write_gatt_char(BOX, b"M#") # off
await say(car, "A") # forward
await asyncio.sleep(1)
await say(car, "0") # stop
🇬🇧 English
Now try a circle. Send forward, then turn, again and again.
C turns left. Only one wheel moves.
So the car turns on the spot. The forward step makes it travel.
Change the two numbers. The circle gets bigger or smaller.
🇹🇭 ไทย
ลองวิ่งเป็นวงกลมดู ส่งเดินหน้า แล้วเลี้ยว สลับกันไปเรื่อย ๆ
C คือเลี้ยวซ้าย ล้อหมุนแค่ข้างเดียว
รถจึงหมุนอยู่กับที่ ส่วนก้าวเดินหน้าทำให้มันเคลื่อนที่ไป
ลองเปลี่ยนตัวเลขสองตัว วงกลมจะใหญ่ขึ้นหรือเล็กลง
🇨🇳 中文
试试转圈。发前进,再发转弯,一直重复。
C 是左转。只有一个轮子在动。
所以车在原地打转。前进那一步让它走出去。
改那两个数字,圈就变大或变小。
async with BleakClient(robot) as car:
for i in range(8):
await say(car, "A") # forward
await asyncio.sleep(0.25)
await say(car, "C") # turn left
await asyncio.sleep(0.40)
await say(car, "0") # stop
6 Play a song with lights · เล่นเพลงพร้อมไฟ · 放歌加灯光
🇬🇧 English
The car has a buzzer. The numbers 1 to 8 are notes.
1 is do. 2 is re. 3 is mi. And so on.
This song is Twinkle Twinkle Little Star.
Each note also picks a colour. So the lights follow the music.
🇹🇭 ไทย
รถมีลำโพงเล็ก ๆ ตัวเลข 1 ถึง 8 คือโน้ตดนตรี
1 คือ โด 2 คือ เร 3 คือ มี ไล่ไปเรื่อย ๆ
เพลงนี้คือเพลง Twinkle Twinkle Little Star
โน้ตแต่ละตัวเลือกสีด้วย ไฟจึงวิ่งตามเพลง
🇨🇳 中文
车上有蜂鸣器。数字 1 到 8 是音符。
1 是 do,2 是 re,3 是 mi,往下类推。
这首歌是《小星星》。
每个音符也挑一个颜色。所以灯跟着音乐走。
BOX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
SONG = "1155665443322 1"
COLOUR = {"1": "G", "2": "J", "3": "H", "4": "K",
"5": "I", "6": "L", "7": "G", "8": "J"}
async def say(car, command):
...
async with BleakClient(robot) as car:
for note in SONG:
if note == " ":
await asyncio.sleep(0.4)
continue
await say(car, note) # the sound
await say(car, COLOUR[note]) # the light
await asyncio.sleep(0.3)
await say(car, "M") # light off
await asyncio.sleep(0.1)
🇬🇧 English
A string is a list of letters. So we can walk through the song.
for note in SONG takes one note each time.
A space means a rest. The music stops for a moment.
We turn the light off after each note. That makes it flash.
🇹🇭 ไทย
สตริงคือรายการของตัวอักษร เราจึงเดินไล่ไปในเพลงได้
for note in SONG หยิบโน้ตทีละตัว
ช่องว่างคือการพัก ดนตรีจะหยุดครู่หนึ่ง
เราปิดไฟหลังโน้ตแต่ละตัว ไฟจึงกะพริบ
🇨🇳 中文
字符串就是一串字母。所以我们能一个一个走过这首歌。
for note in SONG 每次取一个音符。
空格表示休止。音乐停一下。
每个音符之后我们把灯关掉。灯就会闪。
7 The whole program · โปรแกรมทั้งหมด · 完整的程序
🇬🇧 English
Here is everything in one file. Read it from the top.
try and finally are new. They keep you safe.
finally always runs. So the car always stops.
If your code breaks, the car still stops. That matters a lot.
🇹🇭 ไทย
นี่คือทั้งหมดในไฟล์เดียว อ่านจากบนลงล่าง
try กับ finally เป็นของใหม่ มันทำให้คุณปลอดภัย
finally ทำงานเสมอ รถจึงหยุดเสมอ
ถ้าโค้ดพัง รถก็ยังหยุดอยู่ดี เรื่องนี้สำคัญมาก
🇨🇳 中文
这里是一个文件里的全部内容。从头往下读。
try 和 finally 是新的。它们保护你。
finally 一定会运行。所以车一定会停。
就算代码出错,车还是会停。这件事很重要。
import asyncio
from bleak import BleakScanner, BleakClient
BOX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
SONG = "1155665443322 1"
COLOUR = {"1": "G", "2": "J", "3": "H", "4": "K",
"5": "I", "6": "L", "7": "G", "8": "J"}
async def say(car, command):
await car.write_gatt_char(BOX, command.encode() + b"#")
await asyncio.sleep(0.05)
async def main():
print("Looking for the robot...")
robot = await BleakScanner.find_device_by_filter(
lambda d, a: d.name and "micro:bit" in d.name)
if robot is None:
print("No robot. Is it on? Is the phone app closed?")
return
print("Found it:", robot.name)
async with BleakClient(robot) as car:
try:
print("Playing a song.")
for note in SONG:
if note == " ":
await asyncio.sleep(0.4)
continue
await say(car, note)
await say(car, COLOUR[note])
await asyncio.sleep(0.3)
await say(car, "M")
await asyncio.sleep(0.1)
print("Driving in a circle.")
for i in range(8):
await say(car, "A") # forward
await asyncio.sleep(0.25)
await say(car, "C") # turn left
await asyncio.sleep(0.40)
finally:
await say(car, "0") # stop, always
await say(car, "M") # lights off
print("Done.")
asyncio.run(main())
pythonpython3 robot.py
8 Draw a heart · วาดรูปหัวใจ · 画一颗心
🇬🇧 English
The micro:bit has 25 small lights. They sit in a 5 by 5 grid.
You can draw a picture on them. Let us draw a heart.
Each row is five places. # is a light that is on. . is off.
This part needs no robot. It draws in your terminal.
🇹🇭 ไทย
micro:bit มีไฟดวงเล็ก 25 ดวง เรียงเป็นตาราง 5 คูณ 5
คุณวาดรูปบนไฟพวกนี้ได้ มาวาดรูปหัวใจกัน
แต่ละแถวมีห้าช่อง # คือไฟติด . คือไฟดับ
ส่วนนี้ไม่ต้องใช้หุ่นยนต์ มันวาดในเทอร์มินัลของคุณ
🇨🇳 中文
micro:bit 有 25 个小灯。排成 5 乘 5 的格子。
你可以在上面画图。我们来画一颗心。
每一行有五个位置。# 是灯亮,. 是灯灭。
这部分不用机器人。它画在你的终端里。
from faces import icon, render
heart = icon(".#.#.",
"#####",
"#####",
".###.",
"..#..")
render(heart, "heart")
pythonpython3 heart.py
🇬🇧 English
Your picture is five numbers. One number for each row.
The row ##### is five lights on. That number is 31.
Now change the dots. Make your own picture.
faces.py has more. It knows faces, A to Z, and 0 to 9.
🇹🇭 ไทย
รูปของคุณคือตัวเลขห้าตัว หนึ่งตัวต่อหนึ่งแถว
แถว ##### คือไฟติดห้าดวง ตัวเลขนั้นคือ 31
ลองเปลี่ยนจุดดู แล้ววาดรูปของคุณเอง
faces.py มีมากกว่านี้ มันรู้จักหน้ายิ้ม A ถึง Z และ 0 ถึง 9
🇨🇳 中文
你的图就是五个数字。一行一个数字。
##### 这一行是五个灯全亮。那个数字是 31。
现在改一改那些点。画你自己的图。
faces.py 里还有更多。它认识表情、A 到 Z、还有 0 到 9。
pythonpython3 faces.py HELLO
9 Follow a black line · วิ่งตามเส้นสีดำ · 沿着黑线走
🇬🇧 English
The car has two small eyes under the front. They look down.
Black sends back little light. White sends back a lot.
So the car knows which side is on the line.
One command starts it. The car then drives by itself.
🇹🇭 ไทย
ใต้หน้ารถมีตาเล็ก ๆ สองดวง มันมองลงพื้น
สีดำสะท้อนแสงกลับมาน้อย สีขาวสะท้อนกลับมามาก
รถจึงรู้ว่าข้างไหนอยู่บนเส้น
คำสั่งเดียวก็เริ่มได้ แล้วรถจะวิ่งเอง
🇨🇳 中文
车头下面有两只小眼睛。它们往下看。
黑色反射回来的光少。白色反射回来的光多。
所以车知道哪一边在线上。
一条命令就能开始。然后车自己走。
async with BleakClient(robot) as car:
await say(car, "S") # line mode on
await asyncio.sleep(15)
await say(car, "0") # stop
pythonpython3 track.py
📁 Get the scripts · ดาวน์โหลดสคริปต์ · 下载脚本
🇬🇧 English
Here is every step as a whole file. You can read it or save it.
Click a card to save the file. Click a grey bar to read it here.
Put the file in one folder. Then run it with pythonpython3.
Start with find.py. Then light.py. Those two are safe.
🇹🇭 ไทย
นี่คือทุกขั้นตอนในรูปไฟล์เต็ม คุณอ่านหรือเซฟไว้ก็ได้
กดที่การ์ดเพื่อเซฟไฟล์ กดแถบสีเทาเพื่ออ่านตรงนี้
วางไฟล์ไว้ในโฟลเดอร์เดียว แล้วรันด้วย python
เริ่มที่ find.py แล้วต่อด้วย light.py สองอันนี้ปลอดภัย
🇨🇳 中文
这里是每一步的完整文件。你可以读,也可以存下来。
点卡片就能存文件。点灰色条就能在这里读。
把文件放在一个文件夹里。然后用 python 运行。
先跑 find.py,再跑 light.py。这两个是安全的。
หารถ · 找车 🌈light.pyLights on and off
เปิดปิดไฟ · 开灯关灯 🎵song.pyA song with lights
เพลงพร้อมไฟ · 放歌加灯 🚗move.pyDrive it with keys
ขับด้วยแป้นพิมพ์ · 用键盘开 🤖robot.pyEverything together
ทุกอย่างรวมกัน · 全部合在一起 😀faces.pyFaces and letters
หน้ายิ้มและตัวอักษร · 表情和字母 🛣️track.pyFollow a black line
วิ่งตามเส้น · 循线走 🙂smile.pyMake the robot smile
ทำให้หุ่นยิ้ม · 让机器人笑
🔍 find.py Safe. It does not move.
"""Step 2 - Find the robot car.
This script only looks. It does not move the car.
Run it:
Windows: python find.py
Mac: python3 find.py
Install bleak first:
Windows: python -m pip install bleak
Mac: python3 -m pip install bleak
On a Mac, say yes when it asks for Bluetooth.
If you miss it: System Settings > Privacy and Security >
Bluetooth > turn on your Terminal app.
"""
import asyncio
from bleak import BleakScanner
async def main():
print("Looking for the robot...")
devices = await BleakScanner.discover(timeout=10)
found = False
for d in devices:
if d.name and "micro:bit" in d.name:
print("Found it:", d.name)
found = True
if not found:
print("No robot.")
print("Is the car on?")
print("Is the phone app closed?")
print("Are you near the car?")
asyncio.run(main())
🌈 light.py Safe. It does not move.
"""Step 3 - Turn the lights on and off.
This script is safe. The car does not move.
Start here. If this works, your Bluetooth works.
Run it:
Windows: python light.py
Mac: python3 light.py
Install bleak first:
Windows: python -m pip install bleak
Mac: python3 -m pip install bleak
On a Mac, say yes when it asks for Bluetooth.
If you miss it: System Settings > Privacy and Security >
Bluetooth > turn on your Terminal app.
"""
import asyncio
from bleak import BleakClient, BleakScanner
# The robot's letter box. Messages go here.
BOX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
async def say(car, command):
"""Send one command to the robot."""
await car.write_gatt_char(BOX, command.encode() + b"#", response=False)
await asyncio.sleep(0.05)
async def find_robot():
"""Look for the car and give it back."""
return await BleakScanner.find_device_by_filter(
lambda d, a: d.name and "micro:bit" in d.name)
async def main():
print("Looking for the robot...")
robot = await find_robot()
if robot is None:
print("No robot. Is it on? Is the phone app closed?")
return
print("Found it:", robot.name)
async with BleakClient(robot) as car:
for name, code in [("red", "G"), ("green", "H"), ("blue", "I")]:
print("Light is", name)
await say(car, code)
await asyncio.sleep(1)
await say(car, "M")
print("Lights off.")
print("Done.")
asyncio.run(main())
🎵 song.py Safe. It does not move.
"""Step 6 - Play a song with flashing lights.
This script is safe. The car does not move.
The numbers are notes.
1=do 2=re 3=mi 4=fa 5=sol 6=la 7=si 8=high do.
A space is a rest.
Run it:
Windows: python song.py
Mac: python3 song.py
Install bleak first:
Windows: python -m pip install bleak
Mac: python3 -m pip install bleak
On a Mac, say yes when it asks for Bluetooth.
If you miss it: System Settings > Privacy and Security >
Bluetooth > turn on your Terminal app.
"""
import asyncio
from bleak import BleakClient, BleakScanner
BOX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
# Twinkle Twinkle Little Star. Change this and make your own song.
SONG = "1155665443322 1"
# Each note gets a colour. So the lights follow the music.
COLOUR = {"1": "G", "2": "J", "3": "H", "4": "K",
"5": "I", "6": "L", "7": "G", "8": "J"}
BEAT = 0.4 # how long one note lasts
ON = 0.7 # how much of the beat the light stays on
async def say(car, command):
"""Send one command to the robot."""
await car.write_gatt_char(BOX, command.encode() + b"#", response=False)
await asyncio.sleep(0.05)
async def find_robot():
return await BleakScanner.find_device_by_filter(
lambda d, a: d.name and "micro:bit" in d.name)
async def play(car, song):
for note in song:
if note == " ":
await asyncio.sleep(BEAT)
continue
await say(car, note) # the sound
await say(car, COLOUR[note]) # the light
await asyncio.sleep(BEAT * ON)
await say(car, "M") # light off
await asyncio.sleep(BEAT * (1 - ON))
async def main():
print("Looking for the robot...")
robot = await find_robot()
if robot is None:
print("No robot. Is it on? Is the phone app closed?")
return
print("Found it:", robot.name)
async with BleakClient(robot) as car:
print("Playing a song.")
try:
await play(car, SONG)
finally:
await say(car, "M")
print("Lights off.")
print("Done.")
asyncio.run(main())
🚗 move.py It MOVES. Floor only.
"""Step 5 - Drive the car with the keyboard.
WARNING: the car MOVES. Put it on the floor first.
It can fall off a table.
Type keys, then press Enter:
w = forward s = back
a = turn left d = turn right
q = spin left e = spin right
x = quit
You can type more than one key. "wwd" goes forward twice, then turns.
Every key moves the car for a short time. Then the car stops by itself.
So the car can never run away from you.
Run it:
Windows: python move.py
Mac: python3 move.py
Install bleak first:
Windows: python -m pip install bleak
Mac: python3 -m pip install bleak
On a Mac, say yes when it asks for Bluetooth.
If you miss it: System Settings > Privacy and Security >
Bluetooth > turn on your Terminal app.
"""
import asyncio
from bleak import BleakClient, BleakScanner
BOX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
# One key, one command.
KEYS = {
"w": "A", # forward
"s": "B", # back
"a": "C", # turn left
"d": "D", # turn right
"q": "E", # spin left
"e": "F", # spin right
}
# How long one key moves the car.
# Make it bigger for longer steps.
STEP = 0.5
async def say(car, command):
"""Send one command to the robot."""
await car.write_gatt_char(BOX, command.encode() + b"#", response=False)
await asyncio.sleep(0.05)
async def find_robot():
return await BleakScanner.find_device_by_filter(
lambda d, a: d.name and "micro:bit" in d.name)
async def drive(car):
print()
print("w = forward s = back")
print("a = turn left d = turn right")
print("q = spin left e = spin right")
print("x = quit")
print()
while True:
# Wait for typing. to_thread keeps Bluetooth alive while we wait.
line = await asyncio.to_thread(input, "> ")
line = line.strip().lower()
if line == "x":
return
for key in line:
if key not in KEYS:
print(" I do not know", key)
continue
await say(car, KEYS[key]) # go
await asyncio.sleep(STEP)
await say(car, "0") # stop again
async def main():
print("Looking for the robot...")
robot = await find_robot()
if robot is None:
print("No robot. Is it on? Is the phone app closed?")
return
print("Found it:", robot.name)
async with BleakClient(robot) as car:
print("Put the car on the floor.")
try:
await drive(car)
finally:
# This always runs. So the car always stops.
for i in range(3):
await say(car, "0")
await asyncio.sleep(0.15)
print("Stopped.")
print("Done.")
asyncio.run(main())
🤖 robot.py It MOVES. Floor only.
"""Step 7 - The whole program.
It finds the car. It plays a song with lights.
Then it drives a circle. Then it stops.
WARNING: the car MOVES. Put it on the floor first.
Run it:
Windows: python robot.py
Mac: python3 robot.py
Install bleak first:
Windows: python -m pip install bleak
Mac: python3 -m pip install bleak
On a Mac, say yes when it asks for Bluetooth.
If you miss it: System Settings > Privacy and Security >
Bluetooth > turn on your Terminal app.
"""
import asyncio
from bleak import BleakClient, BleakScanner
BOX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
SONG = "1155665443322 1"
COLOUR = {"1": "G", "2": "J", "3": "H", "4": "K",
"5": "I", "6": "L", "7": "G", "8": "J"}
async def say(car, command):
"""Send one command to the robot."""
await car.write_gatt_char(BOX, command.encode() + b"#", response=False)
await asyncio.sleep(0.05)
async def find_robot():
return await BleakScanner.find_device_by_filter(
lambda d, a: d.name and "micro:bit" in d.name)
async def main():
print("Looking for the robot...")
robot = await find_robot()
if robot is None:
print("No robot. Is it on? Is the phone app closed?")
return
print("Found it:", robot.name)
async with BleakClient(robot) as car:
try:
print("Playing a song.")
for note in SONG:
if note == " ":
await asyncio.sleep(0.4)
continue
await say(car, note)
await say(car, COLOUR[note])
await asyncio.sleep(0.3)
await say(car, "M")
await asyncio.sleep(0.1)
print("Driving in a circle.")
for i in range(8):
await say(car, "A") # forward
await asyncio.sleep(0.25)
await say(car, "C") # turn left
await asyncio.sleep(0.40)
finally:
# This always runs, even if something breaks.
# So the car always stops.
for i in range(3):
await say(car, "0")
await asyncio.sleep(0.15)
await say(car, "M")
print("Stopped.")
print("Done.")
asyncio.run(main())
😀 faces.py Safe. No robot needed.
"""Faces and letters for a 5x5 grid of lights.
The micro:bit screen is 25 lights in a 5 by 5 grid. A picture for it is
five numbers, one for each row. Numbers are hard to read, so here you
draw each picture with dots and hashes instead.
This draws in your terminal. It needs no robot and no Bluetooth, so it
works on any computer.
python faces.py # a smile
python faces.py heart # one picture
python faces.py HELLO # spell a word
python faces.py font # show everything
Run it:
Windows: python faces.py heart
Mac: python3 faces.py heart
"""
import sys
def icon(*rows):
"""Five strings of dots and hashes -> five numbers.
One number for each row. Bit 4 is the LEFT light, bit 0 the right one.
"""
out = bytearray()
for row in rows:
value = 0
for i, ch in enumerate(row[:5]):
if ch not in ". 0_":
value |= 1 << (4 - i)
out.append(value)
return bytes(out)
FACES = {
"smile": icon(".#.#.", ".#.#.", ".....", "#...#", ".###."),
"sad": icon(".#.#.", ".#.#.", ".....", ".###.", "#...#"),
"wink": icon(".#...", ".#.##", ".....", "#...#", ".###."),
"flat": icon(".#.#.", ".#.#.", ".....", "#####", "....."),
"heart": icon(".#.#.", "#####", "#####", ".###.", "..#.."),
"yes": icon(".....", "....#", "...#.", "#.#..", ".#..."),
"no": icon("#...#", ".#.#.", "..#..", ".#.#.", "#...#"),
"up": icon("..#..", ".###.", "#.#.#", "..#..", "..#.."),
"down": icon("..#..", "..#..", "#.#.#", ".###.", "..#.."),
}
FONT = {
" ": icon(".....", ".....", ".....", ".....", "....."),
"A": icon(".###.", "#...#", "#####", "#...#", "#...#"),
"B": icon("####.", "#...#", "####.", "#...#", "####."),
"C": icon(".####", "#....", "#....", "#....", ".####"),
"D": icon("####.", "#...#", "#...#", "#...#", "####."),
"E": icon("#####", "#....", "####.", "#....", "#####"),
"F": icon("#####", "#....", "####.", "#....", "#...."),
"G": icon(".####", "#....", "#..##", "#...#", ".###."),
"H": icon("#...#", "#...#", "#####", "#...#", "#...#"),
"I": icon("#####", "..#..", "..#..", "..#..", "#####"),
"J": icon("#####", "..#..", "..#..", "#.#..", ".##.."),
"K": icon("#...#", "#..#.", "###..", "#..#.", "#...#"),
"L": icon("#....", "#....", "#....", "#....", "#####"),
"M": icon("#...#", "##.##", "#.#.#", "#...#", "#...#"),
"N": icon("#...#", "##..#", "#.#.#", "#..##", "#...#"),
"O": icon(".###.", "#...#", "#...#", "#...#", ".###."),
"P": icon("####.", "#...#", "####.", "#....", "#...."),
"Q": icon(".###.", "#...#", "#...#", "#..#.", ".##.#"),
"R": icon("####.", "#...#", "####.", "#..#.", "#...#"),
"S": icon(".####", "#....", ".###.", "....#", "####."),
"T": icon("#####", "..#..", "..#..", "..#..", "..#.."),
"U": icon("#...#", "#...#", "#...#", "#...#", ".###."),
"V": icon("#...#", "#...#", "#...#", ".#.#.", "..#.."),
"W": icon("#...#", "#...#", "#.#.#", "##.##", "#...#"),
"X": icon("#...#", ".#.#.", "..#..", ".#.#.", "#...#"),
"Y": icon("#...#", ".#.#.", "..#..", "..#..", "..#.."),
"Z": icon("#####", "...#.", "..#..", ".#...", "#####"),
"0": icon(".###.", "#..##", "#.#.#", "##..#", ".###."),
"1": icon("..#..", ".##..", "..#..", "..#..", ".###."),
"2": icon("###..", "...#.", "..#..", ".#...", "#####"),
"3": icon("####.", "....#", "..##.", "....#", "####."),
"4": icon("#...#", "#...#", "#####", "....#", "....#"),
"5": icon("#####", "#....", "####.", "....#", "####."),
"6": icon(".###.", "#....", "####.", "#...#", ".###."),
"7": icon("#####", "....#", "...#.", "..#..", ".#..."),
"8": icon(".###.", "#...#", ".###.", "#...#", ".###."),
"9": icon(".###.", "#...#", ".####", "....#", ".###."),
"!": icon("..#..", "..#..", "..#..", ".....", "..#.."),
"?": icon(".###.", "#...#", "...#.", ".....", "..#.."),
}
def render(bitmap, label=""):
"""Print a picture in the terminal."""
if label:
print(f" {label}")
for row in bitmap:
line = "".join("#" if (row >> (4 - i)) & 1 else "." for i in range(5))
print(" ", line.replace("#", "[]").replace(".", " ."))
print(" numbers:", " ".join(str(b) for b in bitmap))
print()
def show(what):
"""Draw a face, a letter, or a whole word."""
if what.lower() == "font":
for name, bm in list(FACES.items()) + list(FONT.items()):
render(bm, name)
return
if what.lower() in FACES:
render(FACES[what.lower()], what.lower())
return
for ch in what.upper():
bm = FONT.get(ch)
if bm is None:
print(f" I have no picture for {ch!r}\n")
else:
render(bm, ch)
if __name__ == "__main__":
show(" ".join(sys.argv[1:]) or "smile")
🛣️ track.py It DRIVES ITSELF. Floor only.
"""Step 9 - the car follows a black line by itself.
WARNING: the car DRIVES ITSELF. Put it on the floor first.
PUT THE CAR ON THE BLACK LINE BEFORE YOU START.
If it does not start on the line, it just drives in circles
looking for one.
python track.py
Run it:
Windows: python track.py
Mac: python3 track.py
Install bleak first:
Windows: python -m pip install bleak
Mac: python3 -m pip install bleak
This script only uses line mode (S#). Yahboom's sheet lists two more
modes, T# and U#. Do NOT use them. They drive the car and 0# does not
stop them - only the power switch does. Tested on a real car.
"""
import asyncio
import sys
from bleak import BleakClient, BleakScanner
BOX = "6e400003-b5a3-f393-e0a9-e50e24dcca9e"
SECONDS = 15
async def say(car, command):
"""Send one command to the robot."""
await car.write_gatt_char(BOX, command.encode() + b"#", response=False)
await asyncio.sleep(0.05)
async def find_robot():
return await BleakScanner.find_device_by_filter(
lambda d, a: d.name and "micro:bit" in d.name)
async def main(seconds):
print("Looking for the robot...")
robot = await find_robot()
if robot is None:
print("No robot. Is it on? Is the phone app closed?")
return
print("Found it:", robot.name)
async with BleakClient(robot) as car:
print()
print("Put the car ON the black line now.")
print("It will follow the line by itself.")
for n in [5, 4, 3, 2, 1]:
print(" starting in", n)
await asyncio.sleep(1)
try:
await say(car, "S") # line mode on
print(" following the line for", seconds, "seconds...")
await asyncio.sleep(seconds)
finally:
# Send the stop more than once. One lost message would
# leave the car driving.
for i in range(3):
await say(car, "0")
await asyncio.sleep(0.15)
print("Stopped.")
print("Done.")
asyncio.run(main(float(sys.argv[1]) if len(sys.argv) > 1 else SECONDS))
🙂 smile.py Safe. It does not move.
"""Make the robot smile.
Yahboom's firmware draws a happy face while Bluetooth is connected,
and a sad face when it disconnects. So to make the bot smile, we
connect and simply hold the connection open.
python smile.py # smile for 30 seconds
python smile.py 120 # smile for 2 minutes
Run it:
Windows: python smile.py
Mac: python3 smile.py
Install bleak first:
Windows: python -m pip install bleak
Mac: python3 -m pip install bleak
"""
import asyncio
import sys
from bleak import BleakClient, BleakScanner
async def main(seconds):
print("Looking for the robot...")
robot = await BleakScanner.find_device_by_filter(
lambda d, a: d.name and "micro:bit" in d.name)
if robot is None:
print("No robot. Is it on? Is the phone app closed?")
return
print("Found it:", robot.name)
async with BleakClient(robot) as car:
print(f"Connected - the robot is smiling for {seconds}s.")
try:
await asyncio.sleep(seconds)
except KeyboardInterrupt:
pass
print("Disconnected - it goes sad again.")
asyncio.run(main(float(sys.argv[1]) if len(sys.argv) > 1 else 30))
📜 All the commands · คำสั่งทั้งหมด · 全部命令
🇬🇧 English
Every command is one or two letters. Then a # at the end.
The # tells the robot "the message ends here".
Try them. Change one letter and run it again.
🇹🇭 ไทย
ทุกคำสั่งมีหนึ่งหรือสองตัวอักษร แล้วปิดท้ายด้วย #
# บอกหุ่นยนต์ว่า "ข้อความจบตรงนี้"
ลองเล่นดู เปลี่ยนตัวอักษรหนึ่งตัว แล้วรันใหม่
🇨🇳 中文
每条命令是一两个字母,最后加一个 #。
# 告诉机器人"消息到这里结束"。
试试看。改一个字母,再跑一次。
| What it does · ทำอะไร · 做什么 | Command |
|---|---|
| Go forward · เดินหน้า · 前进 | A# |
| Go back · ถอยหลัง · 后退 | B# |
| Turn left · เลี้ยวซ้าย · 左转 | C# |
| Turn right · เลี้ยวขวา · 右转 | D# |
| Spin left · หมุนซ้าย · 原地左转 | E# |
| Spin right · หมุนขวา · 原地右转 | F# |
| Stop · หยุด · 停 | 0# |
| Red light · ไฟแดง · 红灯 | G# |
| Green light · ไฟเขียว · 绿灯 | H# |
| Blue light · ไฟน้ำเงิน · 蓝灯 | I# |
| Yellow light · ไฟเหลือง · 黄灯 | J# |
| Lights off · ปิดไฟ · 关灯 | M# |
| Notes do to high do · โน้ต โด ถึง โดสูง · do 到高音 do | 1# … 8# |
| Follow a black line · วิ่งตามเส้นดำ · 循黑线走 | S# |
| Avoid walls · หลบสิ่งกีดขวาง · 避开障碍 | T# |
Yahboom made this list. You can download their sheet. Yahboom เป็นคนทำรายการนี้ คุณดาวน์โหลดเอกสารของเขาได้ 这个表是 Yahboom 做的。你可以下载他们的文件。
S# is safe. 0# stops it. Do NOT use T# or U#. 0# does not stop those. Only the power switch does.
S# ปลอดภัย 0# หยุดได้ อย่าใช้ T# หรือ U# 0# หยุดสองอันนั้นไม่ได้ ต้องปิดสวิตช์เท่านั้น
S# 是安全的,0# 能停。不要用 T# 或 U#。0# 停不了它们。只有电源开关能停。
🔧 When it does not work · เมื่อมันไม่ทำงาน · 跑不起来的时候
| You see this | Do this |
|---|---|
No module named bleak |
Run pythonpython3 -m pip install bleak again.ติดตั้ง bleak อีกครั้ง · 再装一次 bleak |
| "No robot" every time | Turn the car on. Close the phone app. Sit near the car. เปิดรถ ปิดแอป นั่งใกล้รถ · 开车、关 App、坐近点 |
| It finds the car, then fails | The phone still holds it. Turn the phone Bluetooth off. มือถือยังจับอยู่ ปิดบลูทูธมือถือ · 手机还占着,关手机蓝牙 |
| Lights work, wheels do not | The batteries are low. Charge them. แบตอ่อน ชาร์จก่อน · 电池没电了,去充电 |
| The car will not stop | Turn the car off by hand. Then add finally.ปิดสวิตช์รถ แล้วใส่ finally · 手动关车,再加 finally |
| Some commands are ignored | You send too fast. Make the sleep bigger. ส่งเร็วไป เพิ่มเวลาพัก · 发太快了,把 sleep 调大 |
🚀 Make it your own · ทำให้เป็นของคุณเอง · 做成你自己的
| Try this | How | Level |
|---|---|---|
| A new song | Change SONG. Use numbers 1 to 8. | easy |
| A square, not a circle | Use a longer forward, then E to spin. | easy |
| Faster flashing | Make the sleep numbers smaller. | easy |
| One key for a whole dance | Put a list of moves under one key in move.py. | harder |
| Dance to your own song | Put the note list and the move list side by side. | harder |
| Stop before a wall | Read the distance the car sends back. | harder |