EV3
Python
EV3DEV
Learn More →
參考資料:Program in Python with EV3 | www.ev3dev.org | ev3dev | EV3DEV API
Visual Studio Code 是一款由微軟開發且跨平台的免費原始碼編輯器,支援語法突顯、程式碼自動補全、程式碼重構功能,並且內建了命令列工具和 Git 版本控制系統,也可以透過安裝額外套件增加功能,支援 Windows 、 MacOS 和 Linux 。
與 LEGO® MINDSTORMS EV3Lab 的積木語言不同,使用 Visual Studio Code 進行編寫程式,安裝 EV3DEV 所推出的 vscode-ev3dev-browser 擴充插件後,可以直接上傳程式到 EV3 主機,也支援使用 SSH 等控制台。
EV3DEV 是基於 Debain Linux-based 系統下運行,可在多個 LEGO® MINDSTORMS 兼容平台上運行,包括 LEGO® MINDSTORMS EV3 和基於 Raspberry Pi 的 BrickPi。
Python 是一種高階程式語言,也是一種解釋型語言,強調程式碼的可讀性、簡潔的語法。Python為了讓程式碼具備高度的可閱讀性,在設計時盡量使用了其它語言常用的符號和英文單字。
Python 支援使用反斜槓作為行接續符,將多個物理行合成為一個邏輯行,作為通用型的程式語言,運用在 YouTube 、 Google 、 Yahoo! 、 Facebook 、 Dropbox 、Gmail 等等知名平台都在大量使用的程式語言,其特色是支援多種編寫方式,包括物件導向、命令式、函數式、程序式,也和Python和Ruby、Perl、Scheme一樣,擁有動態語法、強制縮排、Garbage Collection 和自動記憶體管理等等諸多的優勢,於未來的需求量也越來越多,涉獵的領域像是大數據分析、自動化腳本、人工智慧。
而 EV3DEV 所使用的 MicroPython 是一款小型的 Python 直譯器,它擁有自己的 Python 直譯器,在保留絕大部分 Python 的核心特色同時縮減周邊模組(函式庫),好讓 Python 這種出了名的吃記憶體的語言也能在像是 EV3 這樣的微控制板上運行。
EV3DEV 是基於 Debain Linux-based 系統下的 MicroPython ,因此需要另外準備記憶卡當作系統碟,一般容量建議在 4GB 。
準備一張 microSD 記憶卡,建議容量 4GB 以下。
下載燒錄軟體 Etcher
將記憶卡插入電腦後,依照下方步驟將映像檔燒錄至記憶卡。
燒錄完成後,確認 EV3 在關機狀態下將記憶卡插入到側邊的 MicroSD 插槽並開機。
為了讓 Python 程式檔案可以傳送至 EV3 ,需要安裝額外的延伸模組。
點選左邊延伸模組商店,輸入 EV3 點選 LEGO® MINDSTORMS® EV3 MicroPython。
重啟 IDE。
安裝成功會在左側欄中出現擴充的延伸模組。
和 MicroPython 語法基本一致,可以在燒錄記憶卡時先安裝在電腦上練習撰寫程式~
首先到官網下載 Python 的安裝檔。
點選 Downloads 進到下載頁面。
目前最新版本是 3.11,這邊是直接安裝此版本到環境中,因此如果有多個版本會需要額外設定,也有許多版本可下載,不同版本之間的語法有些小差異。
開啟安裝執行檔,並勾選 "Add python.exe to PATH" 自動設定路徑,並點選 Install Now 開始安裝。
安裝完後可以開啟 CMD ,並輸入 python
,如果安裝成功就可以進入到 Python,
撰寫第一個程式來測試看看吧!
print("Hello World")
快看! 電腦在向世界說 Hello 呢! (@^0^)
首先將 EV3 開機並且透過數據線連接至電腦,可以看見開機後的 EV3 主畫面也不同了,不過不用擔心,只要關機並且將記憶卡取出後再開機,就可以回到官方系統了。
接著創建一個新的專案,並輸入檔名。
接著左下方的可以看到我們剛剛所安裝的 EV3DEV Device Browser,點選 Click here to connect to a device
並選擇 ev3dev 。
等待出現綠色圓圈和 Status
可以顯示狀態就表示成功了!
自動發現任何連接的 ev3dev 主機,不需要額外設定。
每個設備的文件都列在 Brickman 中。
單擊一下即可將當前 VS Code 項目發送到 ev3dev 設備。
單擊任何可執行文件以運行它。
也可以右鍵點擊選擇 Run
錯誤消息將顯示在輸出窗格中。
需創建一個 ev3devBrowser
的 launch.json 文件以使用此功能。
{
"version": "0.2.0",
"configurations": [
{
"name": "Download and Run",
"type": "ev3devBrowser",
"request": "launch",
"program": "/home/robot/${workspaceRootFolderName}/hello",
"preLaunchTask": "build"
}
]
}
可以通過右鍵單擊設備在控制台中啟動 SSH 。
sudo hostnamectl set-hostname <name>
可以通過右鍵單擊設備輕鬆截取營幕。
首先來介紹自動生成的 main.py
,這個檔案室 EV3 程式開始的地方,我們先來了解一下 Python 的語法以及這自動生成的程式碼是甚麼吧!
粉紅色框內所表示的是 from ... import ...
這段程式碼是代表匯入「函式庫」,函式庫像是外部的我們之前 EV3Lab 積木語言所學到匯入 MyBlock ,將外部的程式碼匯入就可以在這個檔案中的程式使用。
藍色框內所表示的是設定硬體的物件,當我們需要使用馬達或是感測器時,需要告訴 EV3 主機,我的硬體是插在哪個 port 。
黃色框內就是我們主要撰寫程式碼的地方了!
首先來撰寫我們在 EV3 上的第一個 Python 程式吧!
在 ev3.speaker.beep()
後方加上
print("Hello World")
接著點選左側邊欄中的偵測與執行,接著點選上方的開始鍵,就可以將剛剛所撰寫的程式下載至 EV3 並且執行。
可以看到下面的輸出欄位,印出了 Hello World
,這次換 EV3 打招呼了喔~
那有沒有辦法將 Hello World
顯示到 EV3 螢幕上呢?
試試看剛剛改成下方這段程式碼吧,並且下載到 EV3 執行看看。
ev3.screen.print("Hello World!") # 在螢幕上顯示 Hello World
wait(5000) # 等待 5000 毫秒
成功了!
Q. 為甚麼要加上 wait(5000)
,等待 5000 毫秒呢?
A. 如果不加上的話,程式會印出Hello World! 結束,程式一結束便會回到主畫面,如此一來就來不及看到是否有印出了。
在Python中,while是一種迴圈語句,它允許在滿足特定條件的情況下重複執行程式碼塊。while語句的基本構造是:
while 條件:
程式碼
在這個語句中,當條件為True時,程式碼將被執行。每次執行完程式碼塊後,Python都會檢查條件是否仍為True,如果是,則再次執行程式碼。這個過程將繼續,直到條件變為False為止。
以下是一個while循環的簡單範例,該範例使用while循環顯示一系列數字,直到達到指定數字:
num = 0
while num < 5:
print(num)
num += 1
這段程式碼將從0開始顯示一系列數字,每個數字之間相差1,直到顯示數字5之前,因為條件“num < 5”仍然為True。在顯示數字5之後,條件變為False,因此while循環將停止執行。
需要注意的是,如果while循環的條件永遠不為False,則程式碼將陷入無限循環,這種情況應盡量避免。
Q. 請使用 while 印出五個 Hello World!
在 EV3 螢幕上。
# ans
num = 0
while num < 5:
ev3.screen.print("Hello World!") # 在螢幕上顯示 Hello World
num += 1
wait(1000) # 等待 1 秒
for 迴圈是一個重要的控制流程工具,與剛才介紹的 while
相似,新增了用於對序列物件(例如列表、元組、字串等)進行迭代的主要功能。
使用 for 迴圈的語法為:
for 變數 in 序列:
# 程式碼
在上述語法中,變數是用來存放每次迭代中序列中的一個元素,而包裹其中的程式碼是在每次迭代時需要執行的一段程式碼。當迭代完成後,for 迴圈也就結束了。
以下是一個使用 for 迴圈遍歷列表的範例:
fruits = ['蘋果', '香蕉', '橘子']
for fruit in fruits:
print(fruit)
在上述範例中,我們使用了一個名為 fruits 的列表,並使用 for 迴圈來遍歷這個列表中的每個元素。在每次迭代中,變數 fruit 會被賦值為列表中的一個元素,然後進入程式碼塊中執行 print 函式,將 fruit 輸出到螢幕上。
for 迴圈也可以和其他控制流程結構(例如 if、else 等)結合使用,來實現更複雜的邏輯運算。使用 for 迴圈,可以輕鬆地對序列物件進行迭代,讓我們可以更加靈活地處理大量資料。
if else 是最常見的條件判斷工具,可以用來根據不同的條件執行不同的程式碼。使用 if else 的語法為:
if 條件1:
# 條件1成立時要執行的程式碼
else:
# 條件1不成立時要執行的程式碼
條件1 是一個 bool
布林值(True 或 False),如果條件1 為 True,則執行 if 後的程式碼,否則執行 else 後的程式碼。
以下是一個使用 if else 判斷 Touch Sensor
是否按下的程式。
btn = TouchSensor(Port.S1) # 創建一個連結在Port.S1的TouchSensor
while True: # 使用無限迴圈讓程式持續執行
if btn.pressed(): # 當按鈕按下
ev3.screen.print("btn pressed")
else:
ev3.screen.print("btn not pressed")
首先我們先來拼裝出簡單的循跡車
馬達緩加減是指讓馬達在啟動或停止的時候,逐漸地加速或減速,不是瞬間就開始或停止。這樣做的原因是因為如果馬達瞬間啟動或停止,會對機器和電子元件產生很大的應力,導致損壞或壞掉,更會導致馬達的精準度不佳。
在 EV3
的輪型機器人上則是會輪子的打滑,起步和煞車如果過快,機器會因慣性和摩擦力導致行走起來不完整。
bMotor = Motor(Port.B)
target = 1000 # 目標角度
bMotor.reset_angle(0) # 將現在的角度歸零
while bMotor.angle() < target: # 當現在的角度小於目標角度時
speed = (target - bMotor.angle()) * 0.5 # 計算速度
if speed > 100: # 限制速度在 10~100 之間
speed = 100
elif speed < 10:
speed = 10
bMotor.dc(speed) # 設定速度
ev3.screen.print(bMotor.angle()) # 顯示現在的角度
bMotor.hold() # 停止馬達
# 緩動函數 cos
def easeInOutSine(x):
return -(math.cos(math.pi * x) - 1) / 2
# 彈跳函數
def easeOutBounce(x):
n1 = 7.5625
d1 = 2.75
if x < 1 / d1:
return n1 * x * x
elif x < 2 / d1:
x -= 1.5 / d1
return n1 * x * x + 0.75
elif x < 2.5 / d1:
x -= 2.25 / d1
return n1 * x * x + 0.9375
else:
x -= 2.625 / d1
return n1 * x * x + 0.984375
# 映射區間
def mapping(x, in_min, in_max, out_min, out_max):
return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min
# 緩加減速
def smoothMove(time, distance, minSpeed, maxSpeed):
i = 0
step = time / 100 / 2
target = bMotor.angle() + distance
while i <= 1:
t_angle = mapping(easeInOutSine(i), 0, 1, 0, target)
error = t_angle - bMotor.angle()
t_speed = error * 1.5
bMotor.dc(t_speed)
i += 0.01
wait(step)
while bMotor.angle() < target:
bMotor.dc(20)
bMotor.stop()
bMotor.hold()
# 使用範例 在3秒內移動到1000度
smoothMove(3000, 1000)
# 初始化馬達
left_motor = Motor(Port.B)
right_motor = Motor(Port.C)
# 初始化顏色感應器
line_sensor = ColorSensor(Port.S3)
# 初始化Drive
robot = DriveBase(left_motor, right_motor, wheel_diameter=55.5, axle_track=104)
# 計算反射光閥值
BLACK = 9
WHITE = 85
threshold = (BLACK + WHITE) / 2
# 設定移動速度為每秒 100 毫米。
DRIVE_SPEED = 100
# 設定比例控制器的增益。這意味著對於每一個光強度百分比偏離閥值,
# 我們就將駕駛座的轉向速度設置為 1.2 度/秒。
# 例如,如果反光值偏離閥值 10,則機器人的轉向速度為 10*1.2 = 12 度/秒。
PROPORTIONAL_GAIN = 1.2
# 開始無限地跟隨線條。
while True:
# 計算光線強度與閥值之間的偏差。
# 加負號可以走在線的另一邊
deviation = line_sensor.reflection() - threshold
# 計算轉向速度。
turn_rate = PROPORTIONAL_GAIN * deviation
# 設置駕駛座速度和轉向速度。
robot.drive(DRIVE_SPEED, turn_rate)
# 您可以在此循環中等待一小段時間或做其他事情。
wait(10)