Weitere ähnliche Inhalte Ähnlich wie 86Duino 小六足機器人 DIY 課程教材 (20) 86Duino 小六足機器人 DIY 課程教材3. 大綱
第一天上午
86Duino Enjoy 3D 印表機簡介
使用 86Duino Enjoy 列印 86小六足零件
小六足列印件前處理
第一天下午
86Duino 簡介
組合小六足足部
組合小六足身體
4. 第二天上午
Arduino 和 86Duino 控制伺服機的方法簡介
86ME 機器人動作編輯器簡介
86ME 安裝和使用教學
第二天下午
認識六足 - 六足機構原理
認識六足 - 六足步態簡介
使用 86ME 編輯小六足動作
手機藍芽遙控 86小六足
7. 86Duino Enjoy 為一台基於 CNC 金屬框架的 3D 印
表機,剛性的結構有助於減少震動,並提供一個穩定
的列印環境。
86Duino Enjoy 3D 印表機內部設計一套簡單的校準
方法,可以輕易的列印或複製出您的作品。
8. 86Duino Enjoy 列印規格
成形方式:熔融層積 (Fused Filament Fabrication)
列印體積: 100 * 100 * 150 mm ( 1,500 cm3)
最小層高: 0.1 mm
噴嘴直徑: 0.3 mm
列印材料:PLA (玉米澱粉)
9. 86Duino Enjoy 軟體
列印軟體:Repetier-Host (簡稱 RH)
檔案傳輸方式:SD card (SDHC Class 10), USB,
Ethernet
10. 86Duino Enjoy 3D printer
Demo Video
影片網址: https://www.youtube.com/watch?v=oOsUWsNCfMY
22. 86小六足 DIY 流程
使用 86Duino Enjoy 3D 印表機列印小六足零件
列印件前處理
組合足部
組合身體
23. 86小六足 DIY 流程
使用 86Duino Enjoy 3D 印表機列印小六足零件
列印件前處理
組合足部
組合身體
24. 至 Thingiverse 網站下載 86小六足 STL 檔案:
http://www.thingiverse.com/thing:964149
點擊
下載
38. 86Duino Enjoy 驅動程式下載
http://www.ftdichip.com/Drivers/VCP.htm
下載 & 安裝驅動程式
39. 連接 86Duino Enjoy 和電腦
驅動程式安裝完成後,使用 USB 線連接電腦和 86Duino
Enjoy
USB 線
86Duino Enjoy
PC
41. 下載 86Duino Enjoy 專用的設定檔
http://www.roboard.com/temp/settings.zip
解壓縮後可以看到資料夾結構如下:
45. 按 ”連線” 按鈕,連線成功時會聽到 86Duino
Enjoy 發出連續三個音效,且連線按鈕會變成右下圖:
未連線 連線成功
連線
47. 按下歸 HOME 按鈕後,86Duino Enjoy 3D 印表機的
X、Y 、Z 軸會立即回到機械原點,代表我們已經可以
操作 86Duino Enjoy 3D 印表機了
55. 打開 86Duino Enjoy 設定檔資料夾, 進入CuraEngine 資
料夾,選擇 Print-Settings.rcp 設定檔,按下開啟舊檔
58. 在 Print Configuration 選項中,套用 86Duino
Enjoy 設定檔:選擇 Print-Settings
59. 在 Filament Setting 中,Extruder1 套用 86Duino
Enjoy 設定檔:選擇 Filament-Settings
60. 載入小六足 STL 檔
點擊 Load 按鈕,載入 86小六足足部檔案:
A_arm_bottom、A_arm_top、leg 、linker
72. 方法一: 使用 USB 線
切片完成後,直接按下列印按鈕,86DuinoEnjoy 會
立即開始列印
73. 方法二: 使用 SD 卡
不使用 USB 線連接 86Duino Enjoy,改插上
86Duino Enjoy 專用的 SD 卡至您的電腦
76. 從電腦拔出 SD 卡,將此 SD 卡置入 86Duino Enjoy
背面的 SD 卡插槽
SD 卡插槽
86Duino Enjoy 控制盒背面
77. 打開 86Duino Enjoy 電源,86Duino Enjoy 會自動讀
取 auto.gcode 檔開始列印!
電源
86Duino Enjoy 控制盒背面
78. 86小六足 DIY 流程
使用 86Duino Enjoy 3D 印表機列印小六足零件
列印件前處理
組合足部
組合身體
80. 認識工具
1. 鑽孔刀 2. 攻牙刀 3. 手握夾頭 4. 尖嘴鉗 5. 平銼刀 6. 圓銼刀
7. 螺絲起子 8. 斜口鉗
1 2
3
4
5
6 7
8
81. 額外材料
1. 2mm x 4mm 螺絲 2. 2mm x 8mm 螺絲 3. 2mm x 15mm 螺絲
4. 杜邦線 5. 電子擴充板 (for 86DuinoZero) 6. 杜邦針腳
1 2
3
4
5
6
106. 持續打磨直到 leg 零件置入後,可以輕鬆旋轉的程度:
※如果已經將 A_arm_bottom 磨掉很多了,leg 零件置入後轉起來還是很緊,
請改為打磨 leg 零件的接觸面
來回
打磨
輕鬆
旋轉
leg
114. 打磨到 leg 零件置入後,可以輕鬆旋轉的程度:
※如果已經將 A_arm_top 磨掉很多了, leg 零件置入後轉起來還是很緊,可
以改為打磨 leg 零件的接觸面
來回
打磨
輕鬆
旋轉
le
g
130. 它是世界上第一個發表的 x86
Arduino 相容板 (比 Intel Galileo 還早)
比 Arduino 的 CPU 時脈快數十倍
內建 Arduino UNO/MEGA 板上沒有
的額外硬體(如: SD 卡、LAN 網路)
可以跑 Windosw XP 與 Linux
作業系統
相容 Arduino Leonardo 腳位
什麼是 86Duino?
132. 86Duino 特色 (2/2)
軟體
相容 Arduino 的開發環境
完整相容 Arduino 程式語法、API、標準函式庫
額外內建 33 個 Arduino 相容函式庫
完完全全 Made In Taiwan(連 CPU 也是 Made In
Taiwan,板子上的零件多數也是 Made In Taiwan)
134. 86Duino 開發環境命名
Coding:培養使用者寫程式解決問題的能力,期望人們在應
用 86Duino 的過程中,能不斷精進寫程式(coding)能力,
進而以寫程式(coding)改變世界。
中文名稱:口丁,由於 86Duino 計劃的種子是由
OpenLab.Taipei 社群翻譯的 Arduino 記錄片所種下,「口丁」
有代表 OpenLab.Taipei 縮寫的意思,同時,它發音也近於英
文「Coding」,正好也隱含了用 coding 改變世界的意義
詳細內容請點此連結:http://www.86duino.com/index.php?p=5746&lang=TW
135. 生產 86Duino 的 DM&P 集團
DM&P 集團為一跨國性的嵌入式系統製造商,以台灣
為設計研發中心及營運總部,在美東、美西、英國、
日本、巴西、深圳、上海、西安均設有分公司。
138. 86DuinoZero 與 Arduino 效能比較表
Dhrystone 性能評測
Dhrystone 性能評測 sketch 下載:
https://www.facebook.com/download/1026109197423161/Arduino_dhrystone.ino
141. 連接 86Duino Zero
Zero 開發板沒有 RC 伺服機專用插座,但可透過以下任一
方式與 RC 伺服機連接:
方法一:使用轉接用的 Arduino shields
方法二:透過麵包板轉接
方法三:手工製作伺服機轉接插座
152. 連接方法 (2/2)
將 RC 伺服機依正確方向插上:
正確方向
GND (黑線) 電源 (紅線) PWM (黃線)
RC Servo – SG90
154. 注意事項 (1/4)
RC 伺服機本身有自己適合的工作電壓範圍,接上電
源之前,請先閱讀 RC 伺服機的規格書或說明書,確
認其工作電壓,如果輸入的電壓超過工作電壓,太高
可能導致伺服機永久燒毀,太低則會讓伺服機無法運
作。
155. 注意事項 (2/4)
有些廉價 RC 伺服機設計不良,在啟動瞬間會大幅干
擾 VIN 電源之供給,將 VIN 電源拉低至 6V 以下,這
會使 86Duino 的 CPU 模組啟動欠壓保護而停機。如
發生這種狀況,一個解決方法是更換可瞬間供應大電
流的外部電源(例如:具有高放電系數的遙控模型用
鋰電池)以克服伺服機的干擾。
156. 注意事項 (3/4)
另一方法是從 micro-USB 接頭另外供應穩定的 5V 電源給
CPU 模組,這是市面上伺服機控制板常見的雙電源供電方
式,以 One 為例,如下圖所示:
157. 注意事項 (4/4)
Zero 雖然可透過板上 5V 直接對吃電較小的伺服機供
電,但連接大電流的伺服機時,應使用雙電源供電。
micro USB:5V
外接電源
158. 86小六足 DIY 流程
使用 86Duino Enjoy 3D 印表機列印小六足零件
列印件前處理
組合足部
組合身體
161. 準備材料
2mm x 4mm 螺絲 3 顆
2mm x 8mm 螺絲 4顆
2mm x 15mm 螺絲 1顆
SG-90 伺服機 1 顆
十字型伺服機配件盤 1 個
※組合一個足部為例
166. 完成後用手搖動 A_arm_top 零件,如果發現 A_arm_top
搖動起來不順暢,表示 A_arm_top 和 linker 之間的磨擦
力太大,請將上鎖的螺絲鬆開一點再試試看:
搖動 A_arm_top
172. 86DuinoZero 歸零程式
#include <Servo86.h> // 使用 Servo86 函式庫
Servo myservo1; // 初始化 Servo 物件
void setup()
{
// 設定 Servo 腳位為 2
myservo1.attach(2);
// 送出 1500us 的 PWM 信號,使伺服機歸零至中點
myservo1.write(1500);
}
void loop() {}
173. 86DuinoOne 歸零程式
#include <Servo86.h> // 使用 Servo86 函式庫
Servo myservo1; // 初始化 Servo 物件
void setup()
{
// 設定 Servo 腳位為 21
myservo1.attach(21);
// 送出 1500us 的 PWM 信號,使伺服機歸零至中點
myservo1.write(1500);
}
void loop() {}
174. 燒錄 Sketch 程式至 86Duino
下載 86Duino Coding 210,將 sketch 燒錄至
86Duino
http://www.86duino.com/86Duino_IDE/86Duino_C
oding_210_WIN.zip
175. 燒錄完成後, 86Duino 會立刻從指定腳位送出 duty
為 1500us 的 PWM,接著我們要將伺服機與
86Duino 連接起來。
伺服機連接 86Duino 的步驟
86DuinoZero
1. 將 PWM 信號線連接至轉接板
2. 伺服機插上轉接板
86DuinoOne
直接將伺服機連接線接上 86DuinoOne 的伺服機座
182. 將 86Duino 接上電源/電池後,伺服機會立即轉到中
點位置,此時請用奇異筆標記如下位置,以利後續不
插電時辨識:
標
記
線
185. 用 4mm 長度的螺絲 2 根,鎖緊 A_arm_bottom
使用伺服機配件包中的自攻螺絲鎖緊十字配件盤
長度
4mm
螺絲
伺服機配件包
中的自攻螺絲
187. 用長度 8mm 螺絲 2 顆鎖上 leg 零件,最後完成圖如
下:
長度 2mm 螺絲
Leg
189. 86小六足 DIY 流程
使用 86Duino Enjoy 3D 印表機列印小六足零件
列印件前處理
組合足部
組合身體
190. 組裝概述
將 6 顆伺服機置入 body_bottom 零件中
蓋上 body_top 零件,用螺絲固定
鎖上 6 個已完成的足部、86Duino 開發板
連接並整理外露的伺服機連接線,完成 86小六足
191. 將 6 顆伺服機置於 body_bootom,如下圖:
196. 用 6 顆長度15mm 的螺絲鎖緊 body_top,如下圖紅
圈處:
長度 15 mm 螺絲
198. 將 6 顆伺服機分別歸零至中點,並畫上標記線
將一字型配件盤照下圖方式套至伺服機輸出軸:
45 度 45 度
45 度45 度
※ 身體邊角上的伺
服機,每個一字型
配件盤套上伺服機
時, 需要與左圖中的
紅色虛線呈 45 度
199. 用 3 顆 2mm x 4mm 螺絲固定足部 (2 顆固定配件盤,
另一顆固定 linker 與 body_bottom)
以自攻螺絲鎖緊伺服機一字型配件盤
長度 4mm 螺絲
長度 4mm 螺絲
長度 4mm 螺絲
伺服機自攻螺絲
203. 對應下圖紅圈處,用 3 顆 2mm x 4mm 螺絲固定
86DuinoZero 於 body_top 上
裝上 86DuinoZero 開發板
204. 用 2 顆 2mm x 4mm 螺絲固定擴充板:
長度 4mm 螺絲
205. 使用杜邦線連接 86DuinoZero 與擴充板
PWM 信號線、電源線、地線共 14 條,擴充板上的腳位對應
如下:
2 3 4
5
6 7 8
9
10 11 12
13
電源 (VIN)
地 (GND)
206. 使用 12 條黃色 (PWM)、1 條紅色(VIN)、1 條黑色
(GND)的杜邦線連接 86DuinoZero 和轉接板:
211. 對應下圖紅圈處,用 3 顆 2mm x 4mm 螺絲將
86DuinoOne 固定於 body_top 零件上
裝上 86DuinoOne 開發板
221. 附錄- 接上鋰電池
接上鋰電池前,請注意
7.4V 鋰電池充飽時,一般電壓是 8.2V ~ 8.4V,86小六
足使用的 SG-90 伺服機,操作電壓為 4.8V ~ 7.2 V。如
果直接接上充飽的鋰電池,會因過高的電壓造成 SG-90
運作時產生不規律抖動,再接上鋰電池之前,請先用三
用電表量測電壓,待電壓下降至 7.2V ~ 7.4V 時,再接
上 86小六足。
228. Arduino 控制伺服機:
使用 Servo 函式庫
attach() - 初始化 Servo pin
write() - 控制 Servo 轉動至 0 ~ 180 度
writeMicroseconds()- 輸入 PWM duty 來控制 Servo 角度
read() - 讀 Servo 目前角度
attached() - 檢查 Servo pin 是否 attach 過
detach() - 關閉 Servo pin
** Servo 函式庫使用方法大部分 Arduino 書籍皆有介紹,此處不再贅述**
229. 範例程式
#include <Servo.h>
Servo myservo;
void setup()
{
myservo.attach(9);
myservo.write(900);
delay(1000);
myservo.write(2000);
delay(1000);
myservo.write(900);
delay(1000);
myservo.write(2000);
}
void loop() {}
Demo 影片
伺服機以最快速度轉動,
無法直接控制速度
230. Servo 函式庫的改良:
86Duino Servo86 函式庫
可設定每顆伺服機轉動速度
可同步控制多顆伺服機轉動,並且在同時間內到達目標位置
可支援最多 45 顆伺服機同步控制
改善 PWM Duty 抖動(jitter)的問題
支持以 Frame 為基礎的機器人動作流程控制方法
231. 範例程式
#include <Servo86.h>
Servo myservo;
void setup()
{
myservo.attach(9);
myservo.write(900);
delay(1000);
myservo.setVelocity(1100);
myservo.write(2000);
delay(1000);
myservo.setVelocity(550);
myservo.write(900);
delay(2000);
myservo.setVelocity(2200);
myservo.write(2000);
}
void loop() {}
Demo 影片
伺服機轉動速度簡易可控
232. PWM Duty 抖動現象 (1/2)
由於舊的 Arduino Servo 函式庫裡 PWM 是用軟體模擬的
方式來實現,所以會出現以下情形:
實際輸出的 PWM duty 時間會有抖動現象 (jitter)
當使用的 PWM channel 超過 12 組, Arduino 會啟用
更多組 Timer, 多個 Timer 中斷彼此干擾, 有時會惡化
PWM jitter 現象
233. PWM Duty 抖動現象 (2/2)
以示波器量測 Arduino 輸出的 PWM duty,如下圖:
因抖動造成的誤差範圍與 CPU 特性及軟體模擬算法有關
抖動現象
235. PWM 抖動現象的影響
在命令解析度比較高的 RC Servo 上, 會造成 servo 輸出軸
實際的抖動
一般模型用的低價 RC Servo 解析度較低, 受 PWM 抖動現
象的影響不大
Arduino UNO
+
KONDO
KRS4014 Servo
Servo抖動實況影片
236. 在 Arduino 和 86Duino 上只使用 1 個 servo pin, 並量測
輸出的 PWM duty 與目標值的誤差,所測得的數據如下:
各板子的 PWM Duty 抖動實測 (1/2)
板子 目標
duty
實際量測值 duty
誤差範圍最小 最大
Arduino UNO 1000 us 1000.04 us 1006.42 us 約 6 ~ 7 us
Arduino
Leonardo
1000 us 1000.04 us 1007.92 us 約 7 ~ 8 us
Arduino DUE 1000 us 998.200 us 998.280 us 約 1 ~ 2 us
Arduino
Mega2560
1000 us 1001.12 us 1008.87 us 約 8 ~ 9 us
86Duino 1000 us 998.64 us 1001.1 us 約 1 ~ 2 us **
** 在 86Duino 有標註硬體 PWM 功能的 I/O pin 上, 誤差則是 0
237. 在 Arduino DUE / Mega2560 和 86Duino 上啟用 45 組
servo pins, 並量測其中一個 pin 輸出的 PWM duty 與目
標值的誤差, 所測得的數據如下表所示:
各板子的 PWM Duty 抖動實測 (2/2)
板子 目標 duty 實際量測值 duty 誤差範圍
最小 最大
Arduino DUE 1000 us 998.05 us 1004.68 us 約 2 ~ 5 us
Arduino
Mega2560
1000 us 1001.09 us 1076.96 us 約 1 ~ 77 us
86Duino 1000 us 998.70 us 1001.31 us 約 1 ~ 2 us
Arduino 的 Servo 函式庫在超過 12 組 channels 時, 會啟用 2 組以上 Timer
中斷, 以上表格可以看出多組 Timer 中斷互相影響所造成的 jitter 惡化情形
242. Frame (幀) 的概念
機器人的動作編輯,也可以視為在編輯圖片中人物的
動作,一個動作(畫面)稱為 ”幀 (Frame)”,多個
靜止動作透過 Servo86 函式庫連續播放出來,機器
人就會動起來了。
在一些專用的機器人控制板中,Frame 有時候被成為
Pose (姿勢)
244. 動畫 Frame 每張圖片上的人物姿勢
機器人 Frame 伺服機目標位置列表
Frame1: 1500, 1300, 1200, 900, 1765, 1809, 1243, 1200,990, 754, 2000 …
Frame2: 1340, 1200, 1543, 2178, 1222, 1456, 1723, 1111, 954, 1245…
Frame3: 1000, 2345, 2000, 800, 1200, 2019, 2430, 1432, 1270, 955, 1560…
247. 使用 86ME 的基礎觀念
Frame
各個伺服機角度所組成的一個姿勢
Motion
展現一連串 frame 的整個過程
homeframe
機器人上電之後所會展現的第一個 frame,編輯各個 frame 時的
初始值也會同 homeframe
offset
機器人實際的 homeframe 難免會因為組裝上有誤差而與自己的理
想值有偏移,這個偏移量即為 offset
248. 86ME 功能簡介
支援線上調整 offset 與 homeframe
支援線上調整 frame,讓使用者能立即看到編輯結果
並即時調整
支援編輯多個動作 (motion),並且可即時播放動作的
連續 frame
可設定 motion 的觸發條件,並且可以產生 86Duino
的 sketch 程式
251. 86ME 安裝
1. 下載最新版 86ME:
http://www.86duino.com/index.php?page_id=8923
&lang=TW
2. 解壓縮檔案,進入 86ME 資料夾後檢查有下列檔案
即完成安裝
3. 目前僅支援 Windows 環境下執行,且須要有 .NET
Framework 3.5 以上的環境才能正常啟動 86ME
254. 燒錄 86ME 的韌體至 86Duino
1. 打開 86Duino Coding IDE
2. 選擇工具 > 板子 > 86Duino Zero
3. 選擇工具 > COM port > (86Duino 的虛擬連接埠)
4. 選擇 檔案 > 範例 > Servo86 > MotionEditor
256. 燒錄 86ME 的韌體至 86Duino
按下燒錄按鈕,之後看到 Uploading the binary sketch …
Done 訊息,說明燒錄已完成
燒錄
完成
257. 開啟 86ME
韌體燒錄完成後,關閉 86Duino IDE,滑鼠左鍵雙擊
86ME,此時會看到連接埠選擇視窗
選擇 86Duino 虛擬連接埠,也可以選 Auto 由 86ME
自動選取
自動抓取 COM port
離線模式
選定一個 COM port
260. 新增專案 (3/6)
新 增 專 案 後 會 彈 出 Robot
Configuration 介面。這個介面
是用來設定所使用的 86Duino
型號、機器人的圖片、各 Pin 腳
的伺服機型號,以及設定 Home
的位置與各個伺服機的 Offset。
而這些設定也都能夠透過 Robot
Configuration 再調整
262. 新增專案 (5/6)
86小六足有十二個自由度,所以至少要選用 12 個伺
服機才能充分發揮小六足動作
範例中,86DuinoZero 規劃給 86小六足使用的腳位
為 2~13,型號為 TOWERPRO_SG90
這時利用線上調整功能將 Home 點設定好(調整
offset),讓小六足每隻腳都能夠接觸地面,設定完
成的部分畫面如下:
268. 編輯 Frame (1/6)
1. 在畫面右邊的 Motion Name 欄位中輸入字串,替動作
取名
2. 按下上方的 Add Motion 按鈕建立 Motion,Motion 可
以含有許多不同的 Frame 或其他 Action 來組成一個完
整的動作
1
2
269. 編輯 Frame (2/6)
3. 在 Action List 空白處按滑鼠右鍵
4. 選擇 Add new action at the first field
5. 選擇 Frame
選擇 Frame
270. 編輯動作 (3/6)
新增一個 Frame 後,你會在左邊的空白區塊看到以
CH<num>開頭的控制項出現在左邊的空白區域,而
num 即為伺服機腳位編號,編號後面接的數字是 PWM
duty,數字後面的拉桿可以調整 PWM duty 大小,一共
可看到三個這樣的控制項
278. 新增 Frame (1/3)
只有一個 Frame 無法完成前進、後退等等的動作,我
們需要新增更多 Frame 來完成一個 Motion
1) 在剛剛 Frame 0 的下方再新增一個 Frame 1
2) 滑鼠右鍵選擇
add new action at the next field -> frame
280. 新增 Frame (3/3)
另一個新增方式:Duplicate frame
會複製所選 Frame 並新增在下方,若下個 Frame 大部
分的伺服機角度與上個 Frame 相同,就可以利用此功
能來新增 Frame
282. 測試動作 (1/3)
有了 4 個 Frame,86ME 右上方像音樂播放器的按鈕,
可以幫助我們實現連續 Frame 的播放、暫停和停止:
283. 測試動作 (2/3)
播放:全部 Frame 會從頭執行到底,共一次
暫停:保持目前播放到的位置並暫停播放,再按一次
播放時會從上次暫停的地方開始
停止:從目前播放到的位置中斷但不記住位置
286. 循環播放
我們要用到兩個元素: Flag 和 Goto
Flag & Goto 必須成對才會有作用,流程如下:
播放到 Goto 時
是否有同
名的 Flag
是
否
不跳轉,繼續播放
依照 Goto
所設定之條
件判斷是否
跳轉
是
回到同名的
Flag 繼續播放
否
播放
289. 點擊 Goto 後,左邊空白處會出現設定項目:
Target Flag Name:選擇要跳到哪個 Flag
Enable Goto:選擇是否啟用 Goto 功能
Loop Infinitely:選擇是否啟用循環功能
292. 設定有限循環播放
將 Loop Infinitely 打勾取消,下方的 Number of
loops 的數值可以決定要 Goto 幾次後停止播放
以下圖為例, Number of loops 填 2,這邊的次數為
Goto 會跳轉的次數,並不是整個 Motion 的總執行
次數
294. 新增 Motion
1. 打上新的 Motion 名稱,按下 Add Motion 按鈕
2. 此時 Motion name 下拉式選單的內容也會跟著更
新,如下圖
297. 設定觸發方式
86ME 允許每個 Motion 設定一個觸發條件,目前共
有四種方式:
Auto
Keyboard
Bluetooth
PS2 Controller
301. 第四個觸發方式:PS2 搖桿
PS2 搖桿
Key:選擇搖桿上的按鈕以用來觸
發動作
Type:與 Keyboard 相同
DAT、CMD、ATT、CLK 為 PS2
接收器接上 86Duino 時需要接的
腳位,須選擇自己接線時所用的
Pin 腳
304. 產生 86Duino Sketch (1/3)
86ME 可以將編輯好的所有 Motion 產生成 86Duino
Sketch,燒錄產生的 Sketch 進 86Duino 後,86Duino
會根據觸發條件判斷是否操作這個 Motion
86ME 提供兩種產生 Sketch 的方式
• Frame 檔和 sketch 分開
• 所有 Frame 直接寫在 sketch 內
305. 產生 86Duino Sketch (2/3)
• Frame 檔與 sketch 分開:
• 按下下圖中的第一個按鈕,會產生 Offset 檔、86Duino Frame
檔與 sketch 程式 (.ino 檔)
• Offset 檔、 Frame 檔必須放在 SD 卡中,sketch 執行時會自動
讀取
306. 產生 86Duino Sketch (3/3)
• 所有 Frame 直接寫在 sketch 內(建議方式,不需 SD 卡)
• 按下下圖中第二個按鈕,只會產生一個 sketch 程式 (.ino 檔),
Offset 與 Frame 皆已寫好在程式中
• 用此方式可直接將產生的程式燒錄進 86Duino,不需要 SD 卡
311. 足部 serial 機構設計
單足 1 個自由度的設計
即使是 1 DOF,靈活性還是很好
影片網址:http://www.youtube.com/watch?v=a0NFrA-Nx4Y
312. 足部 serial 機構設計
單足 2 個自由度的設計
影片網址: https://www.youtube.com/watch?v=MMrbYbdmvqM
313. 足部 serial 機構設計
單足 3 個自由度的設計
影片網址: http://www.youtube.com/watch?v=0jyBiECoS3Q
314. 足部 serial 機構設計
單足 4 個自由度的設計
影片網址: http://www.youtube.com/watch?v=6J9GKPKTyb8
315. 足部 parallel 機構設計
單足 2 個自由度的設計
平行機構
影片網址: http://www.youtube.com/watch?v=RVqn-UZahpw
317. 足部機構設計
下列以 DMP Hexapod 示範
腿節長度由短變長
腿節的動作帶動脛帶的動作
只轉動腿節的馬達,脛節的馬達是不動的
足部夾角由小變大
336. DMP 小六足 (影片)
內部研發自我消遣用 (做好玩的)
平行機構
可自適應地形
具前方避障功能
內部使用逆運動學計算
步伐
影片網址:https://www.youtube.com/watch?v=MuY1w_5qIOk
Open Source on GitHub website:
https://github.com/acen2009/roboard-hexapod/tree/Copy_Files_from_Google
337. DMP 小六足 (影片)
DMP 暑期實習生專題
六足蠍子 - 史迦納
Serial 機構
內部使用逆運動學來
計算步伐
根據展現的動作會發出
不同音效
影片網址:https://www.youtube.com/watch?v=ujsKvYa32kY
Open Source on GitHub website:https://github.com/RoBoardGod/Robot-
425. USB 鍵盤觸發
在 86ME 中,假設以英文大寫字母 W、A 、D 分別代
表前進、左轉、右轉的動作,設定如下:
持續按著 W 鍵觸發
前進動作
持續按著 A 鍵觸發
左轉動作
持續按著 D 鍵觸發
左轉動作
前進 左轉 右轉
426. 藍牙觸發
在 86ME 中,假設以英文大寫字母 U、L 、R 分別代
表前進、左轉、右轉的動作,設定如下:
收到 U 字母觸發前進動作 收到 L 字母觸發左轉動作 收到 R 字母觸發右轉動作
前進 左轉 右轉
427. PS2 搖桿觸發
在 86ME 中,假設以PS2 搖桿上的十字鍵上、左 、右
分別代表前進、左轉、右轉的動作,設定如下:
持續按著十字鍵的”
上”觸發前進動作
持續按著十字鍵的”
左”觸發前進動作
持續按著十字鍵的”
右”觸發前進動作
※ 設定中 DAT、CMD 、ATT 、CLK 可以任選四根沒用到的腳位
前進 左轉 右轉
428. 全部設定完成後,按下 Generate 86Duino sketch
(All in One) 按鈕,將產生出來的 .ino 燒錄至
86Duino。然後拔除 86小六足的 USB 線,接上鋰電
池,開始用指定的第三方控制器控制 86小六足的動作!
下面我們將詳細介紹前進/左轉/右轉動作的藍牙觸發
設定方法,最後以手機遙控 86小六足。
434. HC-06 對外連接介面為 UART,連接腳有 4 支:VCC、
GND 、RXD 、 TXD
這裡我們以 86DuinoZero 的 Serial1 為例,對照下表,
連接 86DuinoZero 與 HC-06 :
436. 當 HC-06 接上電源後,可以看到上面的 LED 燈號快
速閃爍 (間隔約 0.2 秒),代表 HC-06 正在等待配對:
快速閃爍
437. 1) 選擇一個小六足動作
例如:forward
2) 選擇 Trigger 分頁
3) 選擇 Bluetooth 為觸發方式
4) 選擇要觸發這個動作的字元
該字元可以於手機藍牙 APP 中自由設定
例如:英文字大寫 U
5) 選擇 86Duino 與藍牙模組通訊的 Baud Rate
例如:9600
6) 選擇 86Duino 與藍牙模組通訊的序列埠
例如:Serial1
86ME 設定藍牙觸發
1
3
4
5
2
6
438. 86ME 產生 Sketch 程式
按下 86ME 右下角的 “Generate 86Duino sketch (All in
One” 按鈕,它將自動產生 86Duino sketch 程式
441. 下載藍牙遙控 APP
手機環境為 Android 系統:
在 Google 商店中搜尋 “Bluetooth Controller”
手機環境為 iOS 系統
APP store 中搜尋 “LightBlue”
※下面我們以 Android 系統上的 Bluetooth Controller App 為例,介紹其操
作方式。在 iOS 上,操作方法與 Bluetooth Controller App 大同小異
444. 對應 86ME 中選取的動作名稱,這裡的按鍵名稱也命
名為 “forward”,觸發字元為 “U”,如右下圖:
452. 我們將 86ME 產生出來的程式稱為 86小六足動作程式
86小六足動作程式運作流程如下:
解析命令 (有設定觸發條件的情況)
Servo86 函式庫
Timer
GPIO
GPIO
GPIO
… …
456. setVelocity()
設定伺服機的轉速。
傳入參數:轉動速度,單位 us/s
#include <Servo86.h>
Servo myservo;
void setup()
{
myservo.attach(9);
myservo.write(1500); // 將伺服機轉動到 1500us 角度
myservo.setVelocity(1000); // 設定速度 1000us/s
myservo.write(900); // 啟動伺服機,用 1000us/s 的速度轉到 900us 角度
}
void loop() {}
457. setPosition()
設定伺服機目標角度。(在呼叫 run() 之前,伺服機還不會轉動)
傳入參數:目標角度和轉動時間。您也可以不設定轉動時間,此時伺
服機會用最快速度轉到目標位置。
#include <Servo86.h>
Servo myservo;
void setup()
{
myservo.attach(9);
myservo.setPosition(1500); // 設定以最快速度轉動到 1500us 角度
myservo.run(); // 轉動伺服機
myservo.setPosition(1000, 1000); // 設定轉到 1000us 角度,用時 1 秒
myservo.run(); // 轉動伺服機
}
void loop() {}
458. setOffset()
設定伺服機原點的微調角度
用於校正伺服機原點誤差及機器人組裝的位置誤差
傳入參數:微調值,範圍 -256 ~ 256,單位 us
#include <Servo86.h>
Servo myservo;
void setup()
{
myservo.attach(9);
myservo.setOffset(-10); // 設定 -10 us 的微調角度
myservo.write(1500); // 將伺服機轉動到 1500us 角度 (實際上是 1500 - 10 = 1490us)
}
void loop() {}
461. run()
啟動伺服機(伺服機開始出力)往目標角度轉動
傳入參數:無
#include <Servo86.h>
Servo myservo;
void setup()
{
myservo.attach(9);
myservo.setPosition(1500); // 設定以最快速度轉動到 1500us 角度
myservo.run(); // 啟動伺服機
myservo.setPosition(1000, 1000); // 設定轉到 1000us 角度,用時 1 秒
myservo.run(); // 啟動伺服機
}
void loop() {}
464. #include <Servo86.h>
Servo myservo;
void setup()
{
myservo.attach(9);
myservo.write(1500); // 將伺服機轉到 1500us 初始位置
delay(100);
}
void loop()
{
myservo.setPosition(1800, 3000); // 設定伺服機的目標角度:1800us,時間:3 秒
myservo.run();
delay(1000);
myservo.pause(); // 伺服機暫停轉動
delay(1000); // 暫停 1 秒
myservo.resume(); // 伺服機恢復轉動
delay(3000);
}
468. 多伺服機同時動作函式
servoMultiRun() - 同時啟動多顆伺服機
servoMultiPause() - 同時暫停多顆伺服機
servoMultiResume() - 同時恢復多顆伺服機
servoMultiStop() - 同時停止多顆伺服機
isServoMultiMoving() - 同時檢查多顆伺服機是否
已全部到達目標位置
469. #include <Servo86.h>
Servo servo1; Servo servo2;
void setup()
{
servo1.attach(6); servo2.attach(10); // 使用 pin 6、10
servo1.setPosition(1500);
servo2.setPosition(1500);
servoMultiRun(servo1, servo2); // 將 servo1、servo2 轉到初始位置
}
void loop()
{
servo1.setPosition(2000, 2000);
servo2.setPosition(1800, 2000);
servoMultiRun(servo1, servo2); // 使 servo1 和 servo2 同時往新目標角度轉動
while(isServoMultiMoving() == true); // 等待所有伺服機都轉到目標位置
servo1.setPosition(1700, 2000);
servo2.setPosition(1600, 2000);
servoMultiRun(); // 使 servo1、servo2 同時往新目標角度轉動
while(isServoMultiMoving() == true); // 等待所有伺服機都轉到目標位置
}
472. positions[]
儲存所有伺服機位置的列表。最多 45 顆伺服機。
#include <Servo86.h>
Servo myservo0; Servo myservo1; Servo myservo2;
ServoFrame myframe; // 宣告一個 Frame 物件
void setup()
{
myservo0.attach(9); myservo1.attach(11); myservo2.attach(5);
myframe.positions[0] = 1800; // 設定 Frame 內容
myframe.positions[1] = 1300;
myframe.positions[2] = 2000;
// 設定以 500ms 的時間將伺服機轉動到 Frame 指定的位置 (myservo0 轉動到 position[0]
// 位置, myservo1 轉動到 position[1] 位置, myservo2 轉動到 position[2] 位置)
myframe.setPositions(500, myservo0 , myservo1, myservo2);
servoMultiRun(); // 根據設定值轉動所有伺服機
}
void loop() {}
474. #include <Servo86.h>
Servo myservo0; Servo myservo1; Servo myservo2;
ServoFrame myframe; // 宣告一個 Frame 物件
void setup()
{
myservo0.attach(9); myservo1.attach(11); myservo2.attach(5);
myframe.positions[0] = 1800; // 設定 Frame 內容
myframe.positions[1] = 1300;
myframe.positions[2] = 2000;
// 設定以 500ms 的時間將伺服機轉動到 Frame 指定的位置 (myservo0 轉動到 position[0]
// 位置, myservo1 轉動到 position[1] 位置, myservo2 轉動到 position[2] 位置)
myframe.setPositions(500, myservo0 , myservo1, myservo2);
servoMultiRun(); // 根據設定值轉動所有伺服機
}
void loop() {}
475. playPositions()
把代表 Frame 的目標位置列表指定給各伺服機並立即控制
伺服機移動到 Frame 指定的角度
等同先呼叫 setPositions() 再接著呼叫 servoMultiRun() 的
效果
輸入參數:和 setPositions() 一樣
476. #include <Servo86.h>
Servo myservo0; Servo myservo1; Servo myservo2;
ServoFrame myframe; // 宣告一個 Frame 物件
void setup()
{
myservo0.attach(9); myservo1.attach(11); myservo2.attach(5);
myframe.positions[0] = 1800; // 設定 Frame 內容
myframe.positions[1] = 1300;
myframe.positions[2] = 2000;
// 以 500ms 的時間將伺服機轉動到 Frame 指定的位置 (myservo0 轉動到 position[0]
// 位置, myservo1 轉動到 position[1] 位置, myservo2 轉動到 position[2] 位置)
myframe.playPositions(500, myservo0 , myservo1, myservo2);
}
void loop() {}
477. save()
儲存目前的 Frame 至指定檔案
輸入參數:86Duino Frame 檔名
#include <Servo86.h>
Servo myservo1; Servo myservo2; Servo myservo3;
ServoFrame myframe;
void setup()
{
myservo1.attach(9); myservo2.attach(11); myservo3.attach(5);
myframe.positions[0] = 1800; // 設定 Frame 內容
myframe.positions[1] = 1300;
myframe.positions[2] = 2000;
myframe.save(“frm0.txt”); // 將動作幀儲存至 SD 卡根目錄下的 "frm0.txt"
}
void loop() {}
478. load()
載入 86Duino Frame 檔案
輸入參數:86Duino Frame 檔名
#include <Servo86.h>
Servo myservo1; Servo myservo2; Servo myservo3;
ServoFrame myframe;
void setup()
{
myservo1.attach(9); myservo2.attach(11); myservo3.attach(5);
myframe.load(“frm0.txt”); // 從指定的檔案載入機器人動作幀
myframe.playPositions(500, myservo1, myservo2, myservo3); // 以
500 ms 的時間播放此 Frame
}
void loop() {}
482. ServoFramePololu 函式
ServoFramePololu 類別
positions[] – 功能與 ServoFrame 一樣
setPositions() – 功能與 ServoFrame 一樣
playPositions() – 功能與 ServoFrame 一樣
load() - 讀取 Pololu 的 .txt Frame 檔
save() – 功能與 ServoFrame 一樣
483. load()
讀取 Pololu Frame 檔案
傳入參數:檔案名稱、Sequence 名稱和 Frame 名稱
Sequence 名稱和 Frame 名稱可在 Pololu 編輯器中查
詢取得
回傳:true 為讀取成功,false 為失敗
484. #include <Servo86.h>
Servo myservo1; Servo myservo2; Servo myservo3;
ServoFramePololu myframe;
void setup()
{
myservo1.attach(9); myservo2.attach(11); myservo3.attach(5);
myframe.load(“pololu.txt”, “Sequence 0”, “Frame 0”); // 讀取 Pololu
Frame 檔中 Sequence 0 的 Frame 0
myframe.playPositions(myservo1, myservo2, myservo3); // 播放動作
}
void loop() {}
487. ServoFrameInno 函式
ServoFrameInno 類別
positions[] – 功能與 ServoFrame 一樣
setPositions() – 功能與 ServoFrame 一樣
playPositions() – 功能與 ServoFrame 一樣
load() - 讀取 Innovati 的 .ftxt Frame 檔
save() – 功能與 ServoFrame 一樣
489. #include <Servo86.h>
Servo myservo1; Servo myservo2; Servo myservo3;
ServoFrameInno myframe;
void setup()
{
myservo1.attach(9); myservo2.attach(11); myservo3.attach(5);
myframe.load(“Frame0.ftxt”); // 讀取 Innovati 的 Frame 0 檔案
myframe.playPositions(myservo1, myservo2, myservo3); // 播放動作
}
void loop() {}
492. KONDO Frame 函式
ServoFrameKondo 類別
positions[] – 功能與 ServoFrame 一樣
setPositions() – 功能與 ServoFrame 一樣
playPositions() – 功能與 ServoFrame 一樣
load() - 讀取 KONDO 的 .RCB Frame 檔
save() – 功能與 ServoFrame 一樣
capture() – 抓取 KONDO 伺服機目前角度(KONDO
伺服機專用的位置抓取函式)
493. load()
讀取 KONDO Frame 檔案
傳入參數:檔案名稱和 Frame 名稱
Frame 名稱可在 KONDO 編輯器中查詢取得
回傳:true 為讀取成功,false 為失敗
494. #include <Servo86.h>
Servo myservo1; Servo myservo2; Servo myservo3;
ServoFrameKondo myframe;
void setup()
{
myservo1.attach(9); myservo2.attach(11); myservo3.attach(5);
myframe.load(“kondo.rcb”, “Frame0”); // 讀取 KONDO Frame 檔中的 Frame0
myframe.playPositions(myservo1, myservo2, myservo3); // 播放動作
}
void loop() {}
497. KONDO 機器人專用伺服機 (2/2)
這種伺服機除了可以控制角度外,也具有抓取位置功能。
可以用來做教導式的機器人的動作編輯,如下面影片:
影片網址: https://www.youtube.com/watch?v=8ucti15PX20
499. capture()
讀取 KONDO 伺服機回傳的角度。注意,capture()
需要在所有伺服機皆為 release 狀態下才有作用,如
果您之前有啟動過任一伺服機,必須先呼叫 release()
後再呼叫此函式。
傳入參數:要 capture 的 servo 類別
回傳:讀到的角度,單位 us。
500. #include <Servo86.h>
Servo myservo0; Servo myservo1; Servo myservo2;
ServoFrameKondo myframe;
void setup()
{
myservo0.attach(9); myservo1.attach(11); myservo2.attach(5);
// 分別讀取 myservo0、myservo1、myservo2 的回傳角度
myframe.positions[0] = myframe.capture(myservo0);
myframe.positions[1] = myframe.capture(myservo1);
myframe.positions[2] = myframe.capture(myservo2);
Serial.println(myframe.positions[0]);
Serial.println(myframe.positions[1]);
Serial.println(myframe.positions[2]);
myframe.save(“captured_frame.txt”);
}
void loop() {}
501. KONDO 伺服機和 86Duino 連接的注意事項
86Duino 要透過 capture() 來讀取 KONDO 伺服機回傳的角度前,要
注意阻抗匹配問題,也就是說您必須在 PWM 信號腳加上一個 5k 以
下的 pull-up 電阻,才有辦法讀取回傳角度, 如下圖:
5K 電阻
3.3V
505. 產生小六足動作程式檔 (1/2)
先將小六足四個 Motion 的觸發設定為
forward:Always On
left :Always On
right :Always On
home :Always Off
forward
home right left
506. 產生小六足動作程式檔 (2/2)
按下 Generate 86Duino Sketch (All in One) 按鈕
將產生名稱為 AllinOne_Motion_Sketch 的 .ino 檔,
即小六足動作程式檔:
509. 小六足動作程式解析 – 第一段
#include <Servo86.h>
Servo myservo2;
Servo myservo13;
ServoOffset myoffs;
ServoFrame _86ME_HOME;
…
引入 Servo86 函式庫
宣告 Servo 變數,用來初始化
Servo 物件內部的變數,如:
PWM 範圍、Servo 數量等等
宣告 ServoOffset 變數來設定伺服機微
調值,即 86ME 裡面設定的 offset 值
宣告 ServoFrame 變數 _86ME_HOME,
用來讓機器人在開啟時即轉到 Home 點,
即 86ME 裡面設定的 HomeFrame
510. ServoFrame forward_frm0;
ServoFrame forward_frm5;
ServoFrame left_frm0;
ServoFrame left_frm5;
ServoFrame right_frm0;
ServoFrame right_frm5;
ServoFrame home_frm0;
…
宣告 ServoFrame forward_frm0
~ frm 5 ,用來儲存 forward 這個
Motion 各個 Frame 的值……
宣告 ServoFrame left_frm0 ~
frm 5 ,用來儲存 left 這個
Motion 各個 Frame 的值
宣告 ServoFrame right_frm0 ~
frm 5 ,用來儲存 right 這個
Motion 各個 Frame 的值
宣告 ServoFrame home_frm0,用來儲
存 home 這個 Motion Frame 的值
511. void setup()
{
myservo2.attach(2);
myservo13.attach(13);
myoffs.offsets[1] = -140;
myoffs.offsets[3] = -50;
myoffs.offsets[5] = -50;
myoffs.offsets[7] = -90;
myoffs.offsets[9] = -110;
myoffs.offsets[11] = -100;
…
初始化 Servo pin,這裡用到 pin
2 ~ pin 13,共 12 個 pins
初始化每個 pin 上伺服機的偏轉
角度,offset[0] 對應至 pin 2,
offset[1] 對應至 pin 3 … 依此類
推,不需要改變微調值的 pin 可
以跳過不設定,其預設值為 0,
例如左邊沒列出的 offset[0]、
offset[2]、 offset[4] 等值皆為 0
小六足動作程式解析 – 第二段
512. forward_frm0.positions[0] = 1700;
forward_frm0.positions[11] = 1700;
forward_frm1.positions[0] = 1700;
myoffs.setOffsets();
_86ME_HOME.playPositions(0);
} //end of setup
…
設定 forward 動作的第一個
frame ,所有伺服機的角度
依此類推,後面依序設定 left、right、home 各
個 Motion 所有 frame 的伺服機角度
………
將上一頁設定的所有 offset 值設定至伺服機
播放小六足的 homeframe,即
86ME 中設定的 HomeFrame,
讓小六足接電後便自動調整到
HOME 的姿勢
設定 forward 動作的第二個
frame ,所有伺服機的角度
513. void loop()
{
if(1)
{
forward_frm0.playPositions(300);
while(isServoMultiMoving() == true);
}
if(1)
{
left_frm0.playPositions(300);
while(isServoMultiMoving() == true);
}
}
…
依此類推,後面是 right 動作的判斷式,格式與
forward、left 相同
1. 按照指定播放時間來播放 left 動作
的每個 frame
2. 直到所有伺服機都轉到目標位置後,
才會在播放下一個 frame
因為 forward 動作的觸發設定為 Always On,所以判斷式為永遠成
立的 if(1),在 loop 迴圈中,forward 動作會一直重複不斷的播放
…
因為 left 動作的觸發設定為 Always On,所以判斷式為永遠成立的 if(1),在 loop
迴圈中,left 動作會一直重複不斷的播放 (順序在 forward 動作播放完之後)
小六足動作程式解析 – 第三段
1. 按照指定播放時間來播放 forward
動作的每個 frame
2. 直到所有伺服機都轉到目標位置後,
才會在播放下一個 frame
515. 更改觸發條件
以上是使用 Always On/Off 觸發所產生的小六足動作
程式,我們用它來認識基本的程式結構。
下面我們將改用藍牙/USB鍵盤/PS搖桿來觸發前進/左
轉/右轉動作,然後產生程式,看看產生出來的小六足
動作程式有哪裡不同,並了解那些不同的程式的作用。
517. 設定鍵盤觸發
在 86ME 中,假設以英文大寫字母 W、A 、D 分別代
表前進、左轉、右轉的動作,設定如下:
第一次按下 W 鍵觸
發前進動作
持續按著 A 鍵觸發
左轉動作
放開 D 鍵觸發左轉
動作
前進 左轉 右轉
519. setup() 上方會新增一個函式,為 key_state(),用來
判斷一個按鍵的狀態,狀態可分成:
第一次按下
持續按著
放開
下面來看看 key_state() 的程式碼,並了解其運作原理:
520. 回傳 0 代表第一次按下
回傳 1 代表持續按著
回傳 2 代表放開
共可判斷 128 個按鍵,陣列中的元素號碼對應到
一個鍵盤按鍵,例如:key_state[4] 為鍵盤 A 的狀
態
當鍵盤按鍵被按下時,按下的按鍵會
即時儲存至 current_key 變數中
按鍵的按下狀態,1 為按下,0 為放開
非以上狀態回傳 3
判斷是否第一次按下
判斷是否持續按著
判斷是否放開
524. 藍牙觸發
在 86ME 中,假設以英文大寫字母 U、L 、R 分別代
表前進、左轉、右轉的動作,設定如下:
收到 U 字母觸發前進動作 收到 L 字母觸發左轉動作 收到 R 字母觸發右轉動作
前進 左轉 右轉
526. 接收新指令,並且
把 指 令 存 到
Serial_Command
變數中沒有指令傳過來時,變數值
為 0xFFF,代表不做任何事
是否收到命令 ‘U’ 字
元
如果收到 ‘U’
字元,則播放
forward 動作
529. PS2 搖桿觸發
在 86ME 中,假設以PS2 搖桿上的十字鍵上、左 、右
分別代表前進、左轉、右轉的動作,設定如下:
持續按著十字鍵的”
上”觸發前進動作
持續按著十字鍵的”
左”觸發前進動作
持續按著十字鍵的”
右”觸發前進動作
※ 設定中 DAT、CMD 、ATT 、CLK 可以任選四根沒用到的腳
位
前進 左轉 右轉
531. Setup 函式中以 config_gamepad 來設定 PS2 接收
器與 86Duino 連接的腳位
532. 讀取 PS2 搖桿狀態 按下 + 非第一次按下 = 持續按下
如果持續按著十字
件的 ‘上’,則播
放 forward 動作
537. 加入 flag
每個 while 迴圈中,
判斷是否有新指令
到來,若有,則跳
到 flag 去接收新指
令,這麼一來,動
作就會立即改變了
後面的 left、right 動作的 while 迴圈中,加入上述相同的判斷式