前一陣子也看到有位工程師(不折不扣的Mirai Suenaga控)放棄其千萬年薪(應該是勇敢的去開創自己的新世界,賺更多),並立志要將他心中的Mirai Suenaga變成智能娃娃(Small Doll),其過程感人肺腑(害歐吉尚也想買一個)。
Source: Smart Doll by Danny Choo (CC BY-NC-SA 2.0)
根據資策會與主計處的產業研究報告,台灣於2014年出生率與死亡率交叉,至2030年後將出現18萬名勞工的短缺! 這對許多亞洲國家(日本首當其衝)而言,為了舒緩未來短缺的勞動人口與高齡照護等工作,機器人工業幾乎是不得不的趨勢! 當你邁入高齡,陪在你身旁的肯定是Robi或Doll之類的,可能不會是自己孩子喔?!
因此,歐吉尚認為這個發明(Smart Doll)相當不得了! 首先呢,將微縮的個人電腦(PC)人型化、變成寵物或是玩偶,再結合語多種感測器(如溫/濕度、Image、IrDA、Bluetooth、GPS、Accelerator)、WebCam、影像/語音識別等等,讓日常生活中許多控制變的更互動、豐富而有趣。
想想看,將來GPS、時鐘、媒體儲存播放系統等等將不再只是平面的冰冷顯示器,而是一位會用溫柔語音告訴你氣候、時間、新聞、與一天行程,並使用豐富的肢體動作指引你汽車方向、走過頭或走錯路還會罵你(喔不! 是安慰你)的可愛少女。平時她會用內建的Camera幫你拍照、錄影、紀錄你平常沒注意的生活點滴,還會自動幫你Summarize你每日、每月或每年的精彩剪輯,與你分享(如果有投影機的話)。出國旅遊時,她可以幫你翻譯,告訴你哪裡有好玩的,大眾運輸怎麼搭較省錢,一邊呱噪的講解當地的歷史人文,當一位稱職的導遊。她跟你一起去上課(幫你筆記),一起去購物(告訴你哪裡買更便宜),直到你生活跟本少不了她!
Source: Smart Doll (圖為Smart Doll發明人Danny Choo)
…好了! 做完白日夢! 又離題了! 各位有沒有發覺? 當我們在指責別人或大環境如何、如何的時候,別人是怎麼充分利用時間,如何去努力實踐自己理想並改善人們生活方式的嗎? 所以趕快加把勁,讓自己跟上世界的脈動吧!
在Basic Stamp、Arduino微控制器與許多搭配的感測器火紅之後,Raspberry Pi(算是一款價格低廉、功能齊全的PC)、BeagleBone(根本是一款內含Linux的強大PC)等IoT應用開發板如雨後春筍出現,連微軟都出來攪局了。最近,又看到淘寶有在賣用Raspberry Pi板組裝的「Programmable DIY Robot」。
Source: RAPIRO
因此,繼上一回使用手機內建的加速度儀(Acceleration Sensor),透過藍芽並迅速產生對應需要較敏捷操控訊號的裝置(例如四驅車或四軸飛行器等)與相關的手機App撰寫之後,今天重點擺在如何實作具有「類關節」,可用手機加速度儀App透過藍芽控制的生物。而「機器蟲」又是入門之中最簡單的,只要兩顆伺服馬達(~90元台幣/每顆)、一些膠帶再剪一些鐵絲即可搞定!
一些前置作業(知識):
- 關於手機App藍芽控制程式與Arduino的通訊,請參閱: Android與Arduino的藍芽通訊、App簡訊廣告看板、用手機App遙控家電開關、實作App遠程遙控智慧家電控制中心等。
- 關於Arduino馬達簡介與機電控制原理,請參閱: 實作App遠程遙控門禁管制。
- 關於Arduino機電與馬達控制的原理,請參閱: DIY實作Blumoduino控制板。
- 關於Arduino機電與馬達控制的運用,請參閱: DIY手機App藍芽遙控車。
- 關於手機加速度儀App程式的開發,請參閱: 活用手機加速度感測器與藍芽控制。
BOM表 (把虛擬通路也一起放進來Survey)
項目(不含運費)
|
台灣(台幣)
|
淘寶(人民幣)
|
Arduino UNO R3
|
290~450
|
12~40
|
Bluetooth HC-06
|
210~350
|
17~30
|
L293D Board (H-橋式電機驅動器)
|
180~250
|
12~21
|
2顆伺服馬達
|
70~90(每顆)
|
12~16(每顆)
|
美勞或植栽用鋁線(書局有賣)
|
20
|
NA
|
科學怪蟲組裝測試:
將兩顆伺服馬達以90度相位差對接,如圖,左側(Severo1)規劃為前腳,右側(Severo2)規劃為後腳。其中,因為馬達的組成多少有些電磁干擾,建議使用厚一點的泡棉隔開,以免誤動作。之後再以膠帶補強接點。
身體完成之後,用美勞或植栽用的鋁線製作蟲的四肢。我買的線太細了,因此將其纏繞並彎曲成彈性與剛性適中的狀態,才能夠支撐Blumodunio外加電池的龐大身軀跟重量。下圖為綁上四肢後的側視圖,其中呈狗腿式彎曲的是蟲的後腿,較短的則是前腳。
下圖分別為為府視與底部(可以看清楚蟲的屁股弧度與兩顆伺服電機的配置),其中,鋁絲做的四肢是用實心線(用剝皮鉗去皮)綑綁固定住的! 蟲的背部(上方)貼了一塊厚泡棉,用來拖住以Blumodunio板的身體與大腦(Arduino程式)。
蟲的四肢最後再纏上電火布(黑色),以增加其腳步運行時的磨擦力,最後來一張前視定裝照。
Android App手機程式規劃
沿用之前的活用手機加速度感測器與藍芽控制的程式,懶的寫程式的朋友可以使用下面的QR Code下載執行檔,安裝方式請參閱前幾回的Android與Arduino的藍芽通訊。
Arduino Uno端系統與程式規劃--科學怪蟲的四肢活動測試(使用手機App控制前)
Arduino系統端的程式則分析上述的「加速度值」來判斷要前進(手機前傾)或後退(手機後傾)。各別對應為兩顆伺服馬達的轉速與轉角。比較麻煩的是,蟲四肢的形狀除了要能支撐重量,也跟程式規劃伺服馬達運轉角度有關,這裡最花時間,可能要調整蠻多次才能符合需求(至少要能前進跟後退)。Arduino程式、蟲腳的形狀、伺服馬達的的左/右擺幅也要配合程式運作,不斷的修改與調整。
函式bugInit用來規劃伺服馬達運轉角度,前腳使用Servo1,用來將身體略為抬起,因此角度不宜過大,而後腳使用Servo2,用來將身體推進(或退),所以角度會大一些。程式透過序列埠讀取指令,「i」表示初始化(bugInit)、「f」表示前進(bugForward)、「b」表示後退(bugBackward)而「x」則表示暫停。當蟲停止後,須重設(bugInit)之後才能前進或後退。至於序列埠與藍芽控制的部分,請參考活用手機加速度感測器與藍芽控制,不再贅述。
Arduino程式--科學怪蟲的四肢活動測試(使用手機App控制前)
#include <SoftwareSerial.h>
#include <Servo.h>
#define MAX_UARTCMDLEN 128
// Pin10/SERVO1_PWM, and Pin9/SERVO2_PWM for L293D motor shield
#define SERVO_FRONT 9
#define SERVO_BACK 10
#define BUG_FORWARD 1
#define BUG_BACKWARD 2
// 伺服器馬達 紅色(VDD), 棕色(GND), 橙色(Signal)
Servo frontServo; // front leg
Servo backServo; // back leg
// up to 128 bytes UART command received from the Android system
byte uartCmdBuff[MAX_UARTCMDLEN];
int uartCmdLen = 0; // received BT command length
// define bug's movement
int frontRUp;
int frontLUp;
int backRForward;
int backLForward;
void setup() {
Serial.begin(9600); // connect to the HC_06, after downloading the software
bugInit(10,30); // 初始化蟲的前後腳轉動角度大小
}
void loop() {
if ( listenSerialCmd()>0 )
executeSerialCmd();
}
void executeSerialCmd() { // update bug's status
char cmd[MAX_UARTCMDLEN];
char* token = NULL;
char* p = NULL;
// parse UART command
sprintf(cmd,"%s",uartCmdBuff);
if ( (p=strchr(cmd,','))==NULL )
return;
*p = '\0';
switch( cmd[0] ) {
case 'i':
bugInit(10,20);
break;
case 'f':
bugForward(500);
break;
case 'b':
bugBackward(500);
break;
case 'x':
bugStop();
break;
default:
break;
}
delay(200);
}
int listenSerialCmd() {
char tmp;
uartCmdLen = 0;
memset(uartCmdBuff,0,MAX_UARTCMDLEN);
while( Serial.available()>0 ) {
if( (tmp=Serial.read())=='O' ){
uartCmdLen = 0;
}
uartCmdBuff[(uartCmdLen++)%MAX_UARTCMDLEN] = tmp;
delay(5); // wait RX signal
}
return uartCmdLen;
}
void bugInit(int afront,int aback) {
frontServo.attach(SERVO_FRONT);
backServo.attach(SERVO_BACK);
frontServo.write(90);
backServo.write(90);
frontRUp = 90-afront;
frontLUp = 90+afront;
backRForward = 90-aback;
backLForward = 90+aback;
}
void bugStop() {
frontServo.write(90);
backServo.write(90);
delay(500);
frontServo.detach();
backServo.detach();
}
void bugForward(int dvalue) {
int backDelay = (500-dvalue)<200?200:(500-dvalue);
int frontDelay = (200-dvalue/2)<100?100:(200-dvalue/2);
backServo.write(90-30); // R
delay(backDelay);
frontServo.write(90-10); // R
delay(frontDelay);
backServo.write(90+40); // L
delay(backDelay);
frontServo.write(90+10); // L
delay(frontDelay);
}
void bugBackward(int dvalue) {
int backDelay = (500-dvalue)<200?200:(500-dvalue);
int frontDelay = (200-dvalue/2)<100?100:(200-dvalue/2);
backServo.write(90+40); // 90+aback
delay(backDelay);
frontServo.write(90-10);
delay(frontDelay);
backServo.write(90-30); // 90-aback
delay(backDelay);
frontServo.write(90+10);
delay(frontDelay);
}
|
Arduino Uno端系統與程式規劃--使用手機加速度儀與藍芽控制
沿用之前的活用手機加速度感測器與藍芽控制,手機傳給Arduino的指令格式也不變,藍芽控制指令由偵測加速度儀變化產生,以「accel」命令開頭緊接著x、y與z三軸的加速值(目前z軸不使用),格式如下:
<Command>,<xAccel -10~10>,<yAccel -10~10>,<zAccel>
例如:
accel,0,-5,9 x、y與z三軸的加速值分別為0,-5,9 (手機往前傾)
accel,0,5,9 x、y與z三軸的加速值分別為0,5,9 (手機往後傾)
accel,-5,0,9 x、y與z三軸的加速值分別為-5,0,9 (手機往右傾)
accel,5,0,9 x、y與z三軸的加速值分別為5,0,9 (手機往左傾)
Arduino程式--科學怪蟲的四肢活動測試(使用手機App控制前)
#include <SoftwareSerial.h>
#include <Servo.h>
#define MAX_UARTCMDLEN 128
// Pin10/SERVO1_PWM, and Pin9/SERVO2_PWM for L293D motor shield
#define SERVO_FRONT 9
#define SERVO_BACK 10
#define BUG_FORWARD 1
#define BUG_BACKWARD 2
// 伺服器馬達 紅色(VDD), 棕色(GND), 橙色(Signal)
Servo frontServo; // front leg
Servo backServo; // back leg
// up to 128 bytes UART command received from the Android system
byte uartCmdBuff[MAX_UARTCMDLEN];
int uartCmdLen = 0; // received BT command length
// define bug's movement
int frontRUp;
int frontLUp;
int backRForward;
int backLForward;
int bugDir = BUG_FORWARD; // bug's move direction
int bugSpeed = 10;
int gAccel[3] = {0,0,0}; // accel x,y,z values
void setup() {
Serial.begin(9600); // connect to the HC_06, after downloading the software
bugInit(10,30);
}
void loop() {
if ( listenSerialCmd()>0 )
executeSerialCmd();
moveBug();
}
void executeSerialCmd() { // update bug's status
char cmd[MAX_UARTCMDLEN];
char* token = NULL;
char* p = NULL;
int accel[3] = {0,0,0}; // accel x,y,z values
int bugSpeed = 0;
// parse UART command
sprintf(cmd,"%s",uartCmdBuff);
if ( (p=strchr(cmd,','))==NULL )
return;
*p = '\0';
Serial.println(cmd);
// check if the accel command, the format is <accel,x,y,z,>
if ( strcmp(cmd,"accel") )
return;
// get speed
for ( int ii=0; ii<3; ii++ ) {
token = p+1;
if ( (p=strchr(token,','))==NULL )
break;
*p = '\0';
accel[ii] = atoi(token);
}
if ( !(accel[0]!=gAccel[0] || accel[1]!=gAccel[1]) )
return; // no change (ignore z axis)
gAccel[0] = accel[0];
gAccel[1] = accel[1];
gAccel[2] = accel[2];
// update speed, forward/backward depends on the yAccel
bugSpeed = abs(accel[1])*10; // 0~200
// update bug's status
bugDir = accel[1]<0?BUG_FORWARD:BUG_BACKWARD; // update direction
if ( bugDir==BUG_FORWARD )
bugForward(bugSpeed);
else
bugBackward(bugSpeed);
delay(200);
#if 0 // debugging
switch( cmd[0] ) {
case 'i':
bugInit(10,20);
break;
case 'f':
bugForward(500);
break;
case 'b':
bugBackward(500);
break;
case 'r':
bugRight();
break;
case 'l':
bugLeft(500);
break;
case 'x':
bugStop();
break;
default:
break;
}
delay(200);
#endif
}
int listenSerialCmd() {
char tmp;
uartCmdLen = 0;
memset(uartCmdBuff,0,MAX_UARTCMDLEN);
while( Serial.available()>0 ) {
if( (tmp=Serial.read())=='O' ){
uartCmdLen = 0;
}
uartCmdBuff[(uartCmdLen++)%MAX_UARTCMDLEN] = tmp;
delay(5); // wait RX signal
}
return uartCmdLen;
}
void bugInit(int afront,int aback) {
frontServo.attach(SERVO_FRONT);
backServo.attach(SERVO_BACK);
frontServo.write(90);
backServo.write(90);
frontRUp = 90-afront;
frontLUp = 90+afront;
backRForward = 90-aback;
backLForward = 90+aback;
}
void bugStop() {
frontServo.write(90);
backServo.write(90);
delay(500);
frontServo.detach();
backServo.detach();
}
void bugForward(int dvalue) {
int backDelay = (500-dvalue)<200?200:(500-dvalue);
int frontDelay = (200-dvalue/2)<100?100:(200-dvalue/2);
backServo.write(90-30); // R
delay(backDelay);
frontServo.write(90-10); // R
delay(frontDelay);
backServo.write(90+40); // L
delay(backDelay);
frontServo.write(90+10); // L
delay(frontDelay);
}
void bugBackward(int dvalue) {
int backDelay = (500-dvalue)<200?200:(500-dvalue);
int frontDelay = (200-dvalue/2)<100?100:(200-dvalue/2);
backServo.write(90+40); // 90+aback
delay(backDelay);
frontServo.write(90-10);
delay(frontDelay);
backServo.write(90-30); // 90-aback
delay(backDelay);
frontServo.write(90+10);
delay(frontDelay);
}
|
電池的部分,一般的9V方電是疊層電池,容量很小且不適合大電流放電,大多用於一些小電流高電壓的場合,例如室內無線電話機。9V電池短路電流一般約200m A(好的能達到1A ),而1.5V的五號電池約3A ,因此當需要啟動電流較大的終端設備時,9V電池支持不了那麼大電流,而且會很快沒電,因此建議買一個四顆1.5V串接的電池盒來接。
覺得這隻蟲過大嗎? 大家有福了,最近 Kickstarter 發表了「晶片般大小的Arduino」,比官方的Nano還小! 而且竟然還內建OLED顯示器! 正式迎接IoT時代,百家爭鳴,各式各樣紛紛出籠的「改變群眾生活方式的創意」。不禁要問:「你Arduino了沒?」!
Source KickStarter