/*
AniEyeball.h - Library for Openlab Taipei Animatronic Eveball.
Created by Ryan Tseng, May 27, 2014.
Released into the public domain.
*/
#ifndef AniEyeball_h
#define AniEyeball_h
#include <Arduino.h>
#include <Servo.h>
class AniEyeball
{
public:
AniEyeball();
AniEyeball(int pinServoP, int pinServoB);
void setPinP(int pinP);
void setPinB(int pinB);
void setPPos(int msec);
void setBPos(int msec);
void acting(int n);
void mix();
void center();
void turnLeftSlowly();
void turnRightSlowly();
void turnLeftBlinking();
void turnRightBlinking();
void guarding();
void sleepy();
private:
Servo _servoP;
Servo _servoB;
int _pinServoP;
int _pinServoB;
};
#endif
Class: AniEyeball
- 它內含兩個 Servo, 分別是眼皮(P)與眼球(B).
- 它的 constructor 需要餵 servo pin# 當參數. 也可以直接宣告不帶任何參數, 稍後再另行設定 servo pin#.
- 它的 method 主要包括有:
- setPPos(int msec): 設定眼皮的位置. 參數單位是 microseconds.
- setBPos(int msec): 設定眼球的位置. 參數單位是 microseconds.
- acting(int n): 指定眼皮眼球做某個預設動作組.
- 其它turnLeftSlowly(), turnRightBlinking(), guarding(), sleepy(): 這些都是預設動作組.
AniEyeball.cpp
/*
AniEyeball.cpp - Library for Openlab Taipei Animatronic Eveball.
Created by Ryan Tseng, May 27, 2014.
Released into the public domain.
*/
#include <Arduino.h>
#include "AniEyeball.h"
int posP, posB;
// 眼皮:
// - 1000: 全開
// - 1500: 半開
// - 2000: 閉眼
// 眼球:
// - 1000: 左
// - 1500: 中
// - 2000: 右
AniEyeball::AniEyeball()
{
}
AniEyeball::AniEyeball(int pinP, int pinB)
{
_pinServoP = pinP;
_pinServoB = pinB;
_servoP.attach(_pinServoP);
_servoB.attach(_pinServoB);
}
void AniEyeball::setPinP(int pinP)
{
_pinServoP = pinP;
_servoP.attach(_pinServoP);
}
void AniEyeball::setPinB(int pinB)
{
_pinServoB = pinB;
_servoB.attach(_pinServoB);
}
void AniEyeball::setPPos(int msec)
{
if (msec > 2000) posP = 2000;
if (msec < 1000) posP = 1000;
posP = msec;
if (!_servoP.attached()) _servoP.attach(_pinServoP);
_servoP.writeMicroseconds(posP);
delay(15);
//_servoP.detach();
}
void AniEyeball::setBPos(int msec)
{
if (msec > 2000) posB = 2000;
if (msec < 1000) posB = 1000;
posB = msec;
if (!_servoB.attached()) _servoB.attach(_pinServoB);
_servoB.writeMicroseconds(posB);
delay(15);
//_servoB.detach();
}
void AniEyeball::acting(int n)
{
switch (n)
{
case 1:
turnLeftSlowly();
break;
case 2:
turnRightSlowly();
break;
case 3:
turnLeftBlinking();
break;
case 4:
turnRightBlinking();
break;
case 5:
guarding();
break;
case 6:
sleepy();
break;
case 7:
mix();
break;
default:
break;
}
}
void AniEyeball::center()
{
if (!_servoP.attached()) _servoP.attach(_pinServoP);
if (!_servoB.attached()) _servoB.attach(_pinServoB);
posP = posB = 1500;
_servoP.writeMicroseconds(posP);
_servoB.writeMicroseconds(posB);
delay(15);
_servoP.detach();
_servoB.detach();
}
void AniEyeball::turnLeftSlowly()
{
if (!_servoP.attached()) _servoP.attach(_pinServoP);
if (!_servoB.attached()) _servoB.attach(_pinServoB);
posP = 1000;
posB = 1800;
_servoP.writeMicroseconds(posP);
_servoB.writeMicroseconds(posB);
delay(1000);
while (posB >= 1000)
{
_servoB.writeMicroseconds(posB);
posB -= 200;
delay(100);
}
// delay(3000);
_servoP.detach();
_servoB.detach();
}
void AniEyeball::turnRightSlowly()
{
if (!_servoP.attached()) _servoP.attach(_pinServoP);
if (!_servoB.attached()) _servoB.attach(_pinServoB);
posP = 1000;
posB = 1200;
_servoP.writeMicroseconds(posP);
_servoB.writeMicroseconds(posB);
delay(1000);
while (posB <= 2000)
{
_servoB.writeMicroseconds(posB);
posB = 200;
delay(100);
}
// delay(3000);
_servoP.detach();
_servoB.detach();
}
void AniEyeball::turnLeftBlinking()
{
// 眼皮:
// - 閉 -> 全開, 瞬開
// 眼球
// - 中 -> 左, 慢慢
// 眼皮:
// - 全開 -> 閉, 瞬閉
if (!_servoP.attached()) _servoP.attach(_pinServoP);
if (!_servoB.attached()) _servoB.attach(_pinServoB);
_servoP.writeMicroseconds(2000);
delay(1000);
_servoP.writeMicroseconds(1000);
delay(1000);
posB = 1700;
_servoB.writeMicroseconds(posB);
delay(500);
while (posB > 1000)
{
posB -= 50;
_servoB.writeMicroseconds(posB);
delay(30);
}
delay(3000);
_servoP.writeMicroseconds(2000);
// delay(1000);
_servoP.detach();
_servoB.detach();
}
void AniEyeball::turnRightBlinking()
{
// 眼皮:
// - 閉 -> 全開, 瞬開
// 眼球
// - 中 -> 右, 慢慢
// 眼皮:
// - 全開 -> 閉, 瞬閉
if (!_servoP.attached()) _servoP.attach(_pinServoP);
if (!_servoB.attached()) _servoB.attach(_pinServoB);
_servoP.writeMicroseconds(2000);
delay(1000);
_servoP.writeMicroseconds(1000);
delay(1000);
posB = 1300;
_servoB.writeMicroseconds(posB);
delay(500);
while (posB < 2000)
{
posB = 50;
_servoB.writeMicroseconds(posB);
delay(30);
}
delay(3000);
_servoP.writeMicroseconds(2000);
// delay(1000);
_servoP.detach();
_servoB.detach();
}
void AniEyeball::guarding()
{
// 眼皮:
// - 閉 -> 全開, 瞬開
// 眼球
// - 中+ -> 左 -> 右, 瞬轉
// 眼皮:
// - 全開 -> -半閉, 瞬閉
// - 重覆 2 遍
if (!_servoP.attached()) _servoP.attach(_pinServoP);
if (!_servoB.attached()) _servoB.attach(_pinServoB);
_servoP.writeMicroseconds(2000);
_servoB.writeMicroseconds(1800);
delay(1000);
_servoP.writeMicroseconds(1000);
_servoB.writeMicroseconds(1000);
delay(500);
_servoB.writeMicroseconds(2000);
for (int i=0; i<2; i++)
{
_servoP.writeMicroseconds(1800);
delay(500);
_servoP.writeMicroseconds(1000);
delay(500);
}
// delay(1000);
_servoP.detach();
_servoB.detach();
}
void AniEyeball::sleepy()
{
// 眼皮:
// - 閉 -> +半開, 慢慢張開
// - +半開 -> 閉, 瞬閉
// - 重覆 3 遍
if (!_servoP.attached()) _servoP.attach(_pinServoP);
if (!_servoB.attached()) _servoB.attach(_pinServoB);
posP = 2000;
for (int i=0; i<3; i++)
{
while (posP >= 1200)
{
_servoP.writeMicroseconds(posP);
posP -= 50;
delay(100);
}
delay(1000);
posP = 2000;
_servoP.writeMicroseconds(posP);
delay(1000);
}
// delay(1000);
_servoP.detach();
_servoB.detach();
}
void AniEyeball::mix()
{
if (!_servoP.attached()) _servoP.attach(_pinServoP);
if (!_servoB.attached()) _servoB.attach(_pinServoB);
posP = 2000;
posB = 1500;
_servoP.writeMicroseconds(posP);
_servoB.writeMicroseconds(posB);
delay(15);
// 眼皮:
// - 閉 -> 半開, 慢慢張開
while (posP >= 1300)
{
_servoP.writeMicroseconds(posP);
posP -= 50;
delay(100);
}
// 眼球:
// - 中 -> 右, 慢慢轉
// - 右 -> 左, 快轉
// - 左 -> 中, 慢慢轉
while (posB <= 2000)
{
_servoB.writeMicroseconds(posB);
posB = 50;
delay(100);
}
while (posB >= 1000)
{
_servoB.writeMicroseconds(posB);
posB -= 150;
delay(30);
}
while (posB <= 1500)
{
_servoB.writeMicroseconds(posB);
posB = 50;
delay(100);
}
// 眼皮:
// - 半開 -> 全開, 慢慢張開
// - 全開 -> 閉, 快快閉
// - 閉 -> 全開, 快快開
posP = 1700;
while (posP >= 1000)
{
_servoP.writeMicroseconds(posP);
posP -= 50;
delay(100);
}
while (posP <= 2000)
{
_servoP.writeMicroseconds(posP);
posP = 150;
delay(30);
}
while (posP >= 1000)
{
_servoP.writeMicroseconds(posP);
posP -= 150;
delay(30);
}
// delay(1000);
_servoP.detach();
_servoB.detach();
}
在 Arduino 端, 直接宣告 AniEyeball 陣列, 程式碼變得乾淨多了.
#include <Servo.h>
#include <AniEyeball.h>
#define N_EYEBALL 4
AniEyeball ot108eyeball[N_EYEBALL];
// 眼皮_PIN # i
// 眼球_PIN # i+1
//const byte servoPin[N_EYEBALL*2] = {2,3,4,5,6,7,8,9,10,11,12,13};
const byte servoPin[N_EYEBALL*2] = {2,3,4,5,6,7,8,9};
void setup()
{
Serial.begin(9600);
for (int i=0; i<N_EYEBALL; i++)
{
ot108eyeball[i].setPinP(servoPin[i*2]);
ot108eyeball[i].setPinB(servoPin[i*2+1]);
}
}
void loop()
{
for (int i=0; i<N_EYEBALL; i++)
ot108eyeball[i].setPPos(1000); // 眼皮全開
delay(500);
for (int pos=1000; pos<=2000; pos+=250)
{
for (int i=0; i<N_EYEBALL; i++)
{
ot108eyeball[i].setBPos(pos); // 眼球 左->右
delay(150);
}
}
delay(500);
for (int pos=2000; pos>=1000; pos-=250)
{
for (int i=N_EYEBALL-1; i>=0; i--)
{
ot108eyeball[i].setBPos(pos); // 眼球 右->左
delay(150);
}
}
delay(500);
for (int pos=1000; pos<=2000; pos+=500)
{
for (int i=0; i<N_EYEBALL; i++)
{
ot108eyeball[i].setBPos(pos); // 眼球 左->右
delay(150);
}
}
delay(500);
for (int pos=2000; pos>=1000; pos-=500)
{
for (int i=N_EYEBALL-1; i>=0; i--)
{
ot108eyeball[i].setBPos(pos); // 眼球 右->左
delay(150);
}
}
delay(500);
for (int i=0; i<N_EYEBALL; i++)
ot108eyeball[i].setPPos(2000); // 眼皮全閉
delay(500);
}
實際執行... 看來效果還不錯.
嗯.. 發現一個問題. 大眼仔彼此是獨立的, 一次一個輪流動作. 如果動作的久一點, 其它的大眼仔會處在 idle 狀態, 少了群動效果.
要怎麼做到群動效果呢? 萊恩大兵的解法是, 將兩個(或更多)的大眼仔接在同一腳位上. 例如:
AnyEyeball1 -> PIN #2, #3
AnyEyeball2 -> PIN #4, #5
AnyEyeball3 -> PIN #6, #7
AnyEyeball4 -> PIN #6, #7
| 藉由麵包板把兩隻大眼仔串在一起. |
![]() |
| 左邊兩隻是連動的, 和右邊不同動作. |
先到此, 再下來就是多片 arduino 板子之間的連動了.
[萊恩大兵的其它文章]
自製大四軸
* 自製大四軸, 實作分享@華山文創文區
* 自製大四軸, (1) 零組件篇, 遙控器 (Drone, Quadcopter, Futaba, Maker, Arduino, Animatronic Eye)
* 自製大四軸, (2) 零組件篇, 飛控板 (Drone, Quadcopter, MultiWii, Arduino, Futaba, Maker)
* 自製大四軸, (3) 零組件篇, 自行雷切木質機架 (Drone, Quadcopter, Maker, Laser Cut)
* 自製大四軸, (4) 零組件篇, 馬達與電變調整 (Drone, Quadcopter, Maker, Electric Speed Control, Motor)
* 自製大四軸, (5) 組裝篇, 四軸飛行器成形 (Drone, Quadcopter, MultiWii, Arduino, Maker, Electric Speed Control, Motor)
* 自製大四軸, (6) 調整篇, 飛行前兩三事 (Drone, Quadcopter, Maker, Futaba, Arduino, MultiWii)
* 自製大四軸, (7) 充電篇, iMax B6 充電器操作記要 (Charger, Battery)
* 自製大四軸, (8) 問題篇, 機架損壞維修 (Drone, Quadcopter, Laser Cut)
* 自製大四軸, (9) 改良篇, 方便拆卸的木質機架 (Drone, Quadcopter, Maker, Laser Cut)
自動報球速的棒球
* 自動報球速的棒球, (1) 概念與雛形 (Arduino, MPU-6050, HC-06)
* 自動報球速的棒球, (2) 第一版試作品 (Arduino, NanoWii, microSD, MPU6050)
* 自動報球速的棒球, (3) 拋接實驗的數據分析 (Arduino, NanoWii, microSD, MPU6050)
* 自動報球速的棒球, (2) 第一版試作品 (Arduino, NanoWii, microSD, MPU6050)
* 自動報球速的棒球, (3) 拋接實驗的數據分析 (Arduino, NanoWii, microSD, MPU6050)
* 做實驗, 寫入 EEPROM 的速度能否跟得上 MPU6050 的數據產出? (Arduino, MPU-6050, EEPROM)
* 筆記, NanoWii, 一些經驗分享 (Arduino, NanoWii, MPU6050)
* Murmur, 很小很強大的穿戴式裝置模組 (Realtag, Bluetooth, CC2540, MPU6050, BMP180)
* 筆記, NanoWii, 一些經驗分享 (Arduino, NanoWii, MPU6050)
* Murmur, 很小很強大的穿戴式裝置模組 (Realtag, Bluetooth, CC2540, MPU6050, BMP180)
CC2540 Bluetooth Low Energy
* 筆記, CC2540 Bluetooth Low Energy, (1) 開發環境 架設 (Bluetooth, CC2540)
* 筆記, CC2540 Bluetooth Low Energy, (2) 跑第一個範例程式 (Bluetooth, CC2540)
* 筆記, CC2540 Bluetooth Low Energy, (3) SimpleBLEPeripheral 簡單介紹 (Bluetooth, CC2540)
* 筆記, CC2540 Bluetooth Low Energy, (4) 在智慧手機上執行範例程式 (Bluetooth, CC2540)
* 筆記, CC2540 Bluetooth Low Energy, (5) 偵測與發送 iBeacon 訊號 (Bluetooth, CC2540, iBeacon)
* 實作, iBeacon 發訊器 x 防丟器 (Bluetooth, CC2540, iBeacon)
* 實作, iBeacon 尋寶遊戲 (Bluetooth, CC2540, iBeacon, iOS app)
* 實作, BLE + iOS app, 遙控燈泡君 (Bluetooth, CC2540, iOS app)
* 做實驗, 用 iBeacon 做自動控制的可行性 (Bluetooth, iBeacon, CC2540, Automation, URL Scheme, iOS app)
* 筆記, CC2540 Bluetooth Low Energy, (2) 跑第一個範例程式 (Bluetooth, CC2540)
* 筆記, CC2540 Bluetooth Low Energy, (3) SimpleBLEPeripheral 簡單介紹 (Bluetooth, CC2540)
* 筆記, CC2540 Bluetooth Low Energy, (4) 在智慧手機上執行範例程式 (Bluetooth, CC2540)
* 筆記, CC2540 Bluetooth Low Energy, (5) 偵測與發送 iBeacon 訊號 (Bluetooth, CC2540, iBeacon)
* 實作, iBeacon 發訊器 x 防丟器 (Bluetooth, CC2540, iBeacon)
* 實作, iBeacon 尋寶遊戲 (Bluetooth, CC2540, iBeacon, iOS app)
* 實作, BLE + iOS app, 遙控燈泡君 (Bluetooth, CC2540, iOS app)
* 做實驗, 用 iBeacon 做自動控制的可行性 (Bluetooth, iBeacon, CC2540, Automation, URL Scheme, iOS app)
藍色小鋪一起來做
* 藍色小鋪一起來做, (1) 用 beacon 控制開關的枱燈
* 藍色小鋪一起來做, (2) 講解 BLE CC2540 UART 通訊範例程式 (Bluetooth, CC2540, UART)
* 藍色小鋪一起來做, (3) 藍牙枱燈專案實作 (上) (Bluetooth, CC2540)
* 藍色小鋪一起來做, (4) 藍牙枱燈專案實作 (下) (Bluetooth, CC2540)
* 藍色小鋪一起來做, (5) iBeacon scanner 專案示範與解說 (Bluetooth, CC2540, iBeacon)
* 藍色小鋪一起來做, (6) 完成, 用 iBeacon 控制開關的枱燈 (Bluetooth, CC2540, iBeacon)
小惡魔 無線溫度感測器
* 小惡魔, (1) 溫度感測 + 物聯網 (Electric Imp, Xively, LM35, Internet of Things)
* 小惡魔, (2) 溫度感測 + 物聯網 + 事件觸發 (Electric Imp, Xively, LM35, Internet of Things)
* 小惡魔, (2) 溫度感測 + 物聯網 + 事件觸發 (Electric Imp, Xively, LM35, Internet of Things)
108 大眼仔
Plot Clock
* 體驗, 蛋生音互動裝置@兒童美術館 (Arduino, 3D Printing, HC-SR04, Interactive)
* 實作, 電容感應音樂樹
* 修理, 樂高馬達 8883 (LEGO 8883 Power Functions M-Motor)
* 修理, (part 2) 樂高馬達 8883 (LEGO 8883 Power Functions M-Motor)
* 修理, 液晶螢幕 (LCD)
* 108 大眼仔, 初登場 (Arduino, SG-90, Maker Faire Taipei 2014, Animatronic Eye)
* 108 大眼仔, 進化, (1) 專屬程式庫 (Arduino, SG90, Animatronic Eye)
* 108 大眼仔, 進化, (2) 當我們串在一起 (Arduino, SG90, Animatronic Eye, I2C)
* 108 大眼仔, 進化, (3) 檢查 Gmail 信箱 (Arduino, SG90, Animatronic Eye, Temboo)
* 108 大眼仔, 進化, (4) 看著我的臉 (Arduino, SG90, Animatronic Eye, OpenCV, Processing, I2C)
* 108 大眼仔, 進化, (5) 迎著人來人往 (Arduino, SG90, Animatronic Eye, OpenCV, Processing, I2C)
* 108 大眼仔, 檢討筆記, 我要一個打十個 (Arduino, SG90, Animatronic Eye)
* 108 大眼仔, 進化, (1) 專屬程式庫 (Arduino, SG90, Animatronic Eye)
* 108 大眼仔, 進化, (2) 當我們串在一起 (Arduino, SG90, Animatronic Eye, I2C)
* 108 大眼仔, 進化, (3) 檢查 Gmail 信箱 (Arduino, SG90, Animatronic Eye, Temboo)
* 108 大眼仔, 進化, (4) 看著我的臉 (Arduino, SG90, Animatronic Eye, OpenCV, Processing, I2C)
* 108 大眼仔, 進化, (5) 迎著人來人往 (Arduino, SG90, Animatronic Eye, OpenCV, Processing, I2C)
* 108 大眼仔, 檢討筆記, 我要一個打十個 (Arduino, SG90, Animatronic Eye)
* Murmur, 有趣的零件售價
* Murmur, Arduino 保險桿 (Arduino, bumper, 3D printing)
* Murmur, 許一個 maker 分享網站
* Murmur, 物聯網新概念- The Physical Web (Internet of Things, The Physical Web)
* Murmur, 關於 HP Sprout 的一點想法
* Murmur, 說中文很難嗎? (Toy, Reed Switch, Voice Recorder Module)
* Murmur, 停車場自動繳費機的兩三事 (Kiosk)
* Murmur, 為什麼是 WiFi? 關於小米空氣清淨器的一點看法.. (Internet of Things)
* Murmur, 機器人是時尚元素? (Robot, Fashion)
* 體驗, 原住民互動故事書@宜蘭大同鄉泰雅生活館* Murmur, Arduino 保險桿 (Arduino, bumper, 3D printing)
* Murmur, 許一個 maker 分享網站
* Murmur, 物聯網新概念- The Physical Web (Internet of Things, The Physical Web)
* Murmur, 關於 HP Sprout 的一點想法
* Murmur, 說中文很難嗎? (Toy, Reed Switch, Voice Recorder Module)
* Murmur, 停車場自動繳費機的兩三事 (Kiosk)
* Murmur, 為什麼是 WiFi? 關於小米空氣清淨器的一點看法.. (Internet of Things)
* Murmur, 機器人是時尚元素? (Robot, Fashion)
* 體驗, 蛋生音互動裝置@兒童美術館 (Arduino, 3D Printing, HC-SR04, Interactive)
* 開箱, 鋼彈小劇場 (Pepper's Ghost, GUNDAM)
* 開箱, 偉力控二號機, 小四軸飛行器 (CG022, Quadcopter)
* 偉力控二號機, 修理防護罩與飛行心得 (CG022, Quadcopter)
* 偉力控二號機, 我想有個家 (CG022, Quadcopter)
* 偉控力二號機, 換馬達 (CG022, Quadcopter)
* 偉力控二號機, 盒子上的洞 (CG022, Quadcopter)
* 開箱, 偉力控二號機, 小四軸飛行器 (CG022, Quadcopter)
* 偉力控二號機, 修理防護罩與飛行心得 (CG022, Quadcopter)
* 偉力控二號機, 我想有個家 (CG022, Quadcopter)
* 偉控力二號機, 換馬達 (CG022, Quadcopter)
* 偉力控二號機, 盒子上的洞 (CG022, Quadcopter)
* 修理, 樂高馬達 8883 (LEGO 8883 Power Functions M-Motor)
* 修理, (part 2) 樂高馬達 8883 (LEGO 8883 Power Functions M-Motor)
* 修理, 液晶螢幕 (LCD)


沒有留言:
張貼留言