davidce 发表于 2012-5-21 16:58:41

基于arduino nano的“机器猫”

本帖最后由 davidce 于 2012-5-21 17:12 编辑

买麦当劳“开心乐园餐”送的机器猫玩偶:


所需材料:



[*]arduino nano
[*]U盘
[*]手机震子
[*]拨动小开关
[*]双色发光二极管
[*]高亮草帽5mm白色发光二极管
[*]压电陶瓷片
[*]光敏电阻
[*]电阻:4.7K×1,220×2,1M×1,20×1

组装:



[*]改造U盘为合适尺寸并引出最外两个供电正负极引脚
[*]U盘引出的供电引脚正极经拨动开关到nano的Vin脚,负极直接到nano的GND
[*]手机震子接nano的GND并串20欧姆电阻到D7脚
[*]双色发光二极管是供阳极的,将220欧姆电阻串中间脚到nano +5V输出,其余两脚分别到D5和D6
[*]高亮白色发光二极管接nano的GND并串220欧姆电阻到D9
[*]压电陶瓷片并1M欧姆电阻正极接nano的A1,负极接GND
[*]光敏电阻接nano +5V和A0,4.7k欧姆电阻接A0和GND
[*]扬声器接nano D8脚和GND

代码:// 8-ohm speaker on digital pin D8
// shock moto on digital pin D7
// big light on digital pin D9
// led2 on degital pin D6
// led1 on degital pin D5

// photoresistor on analog A0 to 5V
// 4.7K resistor on analog A0 to ground

// + connection of the piezo attached to analog in A1
// - connection of the piezo attached to ground
// 1-megohm resistor attached from analog in A1 to ground

//randompin A2

#include "pitches.h"
#include "notes.h"
//output
const int redLed = 5;
const int greenLed = 6;
const int motopin = 7;
const int tonepin = 8;
const int bigLed = 9;
//input
const int lightpin=A0;
const int knockpin=A1;
const int randpin=A2;

int brightness = 0;    // how bright the LED is
int fadeAmount = 1;    // how many points to fade the LED by
int lightvalue;
boolean isactive = true;
//运行模式,0发声,1震动
int runmode = 0;
const unsigned long sleeptime = 300000;//5 min
long previousMillis = 0;
unsigned long currentMillis = 0;
const unsigned long mintev = 3600000; // 1 hour
//录制震动的数组
boolean shockarray;

void setup() {
randomSeed(analogRead(randpin));
shockarray=true;//激活的震动被看作一次输入
pinMode(bigLed, OUTPUT);
pinMode(redLed, OUTPUT);
pinMode(greenLed, OUTPUT);
pinMode(motopin, OUTPUT);
resetled();
setmodeled(runmode);//设置状态灯显示
lightvalue=analogRead(lightpin);
playmusic(notesstart,Durationsstart,sizeof(notesstart)/sizeof(notesstart),1);

}

void loop() {
//计算时间
tick();
//判断是否处于活动状态
if(isactive) {    //激活状态
    //遮挡 改变运行模式
    if(checkcover()) {
      runmode = runmode +1;
      if(runmode> 1) {
      runmode = 0;
      }
      //设置模式的led
      resetled();
      setmodeled(runmode);//设置状态灯显示
      resettick();
    }else{
      //震动 换歌 和 震动输入
      if(checkknock()) {
      if(runmode == 0) {    //换歌
          randomplay();
          setmodeled(runmode);//恢复状态灯显示
      }else if(runmode == 1) {//震动输入
          recordandplayshock();
      }
      resettick();
      }else{
      //goto sleep
      if(checktime(sleeptime)) {
          isactive = false;
          resetled();
          resettick();
      }
      }
    }
}else{      //休眠状态
    if(checkActive()) {
      isactive=true;
      resetled();
      setmodeled(runmode);   //恢复状态灯显示
      resettick();
    }else{
      //呼吸灯
      fade(bigLed,100,20);
      //运行休眠1小时的事件   报时
      if(checktime(mintev)) {
      playmusic(notesalarm,Durationalarm,sizeof(notesalarm)/sizeof(notesalarm),1);
      }
    }
}

//fade(bigLed,100,30);
//flash(bigLed,50);
//shockme(motopin,500,500);
//if(checkknock()) {
//    flash(bigLed,50);
//}
//if(checkcover()) {
//    flash(bigLed,50);
//}
//Blink(redLed,500,500);
//Blink(greenLed,500,500);
}
//录制和播放震动
void recordandplayshock() {
//进行录制 带闪光
int arraylen=sizeof(shockarray)/sizeof(shockarray);
flash(bigLed,100);

for(int i=1;i < arraylen;i++) {
    shockarray=checkknock();
    if(shockarray) {
      flash(bigLed,100);
    }else{
      delay(50);
    }
}
//播放
for(int i=0;i < arraylen;i++) {
    if(shockarray) {
      shockme(motopin,100,50);
    }else{
      delay(50);
    }
}
}
//随机播放
void randomplay() {
long randNumber = random(10);//0-9
switch (randNumber) {
      case 0:
      playmusic(notesstart,Durationsstart,sizeof(notesstart)/sizeof(notesstart),1);
      break;
      case 1:
      playmusic(notesalarm,Durationalarm,sizeof(notesalarm)/sizeof(notesalarm),1);
      break;
      case 2:
      playmusic(notesnokia,Durationsnokia,sizeof(notesnokia)/sizeof(notesnokia),1);
      break;
      case 3:
      playmusic(notescat,Durationscat,sizeof(notescat)/sizeof(notescat),1);
      break;
      case 4:
      playmusic(notemario,Durationsmario,sizeof(notemario)/sizeof(notemario),1);
      break;
      case 5:
      playmusic(noteMission,DurationsMission,sizeof(noteMission)/sizeof(noteMission),1);
      break;
      case 6:
      doflash(4);
      break;
      case 7:
      doblink(4);
      break;
      case 8:
      doshock(4);
      break;
      default:
      playmusic(notesstart,Durationsstart,sizeof(notesstart)/sizeof(notesstart),1);
    }
}

//设置运行模式状态led 无自动熄灭
void setmodeled(int mode) {
int pin = redLed;
if(mode==1)
{
    pin = greenLed;
}
digitalWrite(pin,LOW);   // set the LED on
}
//重置所有led
void resetled() {
digitalWrite(bigLed, LOW);
digitalWrite(redLed, HIGH);    // set the LED off
digitalWrite(greenLed, HIGH);    // set the LED off
}
//播放音符
void playmusic(int melody[],int noteDurations[],int notelengh,float notespeed) {
for (int thisNote = 0; thisNote < notelengh ; thisNote++) {
    // to calculate the note duration, take one second
    // divided by the note type.
    //e.g. quarter note = 1000 / 4, eighth note = 1000/8, etc.
    int noteDuration = 1000/noteDurations;
    tone(tonepin, melody,noteDuration);
    // to distinguish the notes, set a minimum time between them.
    // the note's duration + 30% seems to work well:
    int pauseBetweenNotes = noteDuration * notespeed;
    delay(pauseBetweenNotes);
    // stop the tone playing:
    noTone(tonepin);
}
}
void doshock(int count) {
int idx=0;
while(idx<count) {
    shockme(motopin,1000,500);
    idx=idx+1;
}
}

void doflash(int count) {
int idx=0;
while(idx<count) {
    flash(bigLed,50);
    delay(50);
    idx=idx+1;
}
}
void doblink(int count) {
int idx=0;
int temp = runmode;
resetled();
while(idx<count) {
    temp =temp+1;
    if(temp > 1) {
      temp=0;
    }
    int pin = redLed;
   if(temp==1) {
       pin = greenLed;
   }
    Blink(pin,100,100);
    idx=idx+1;
}
}

//呼吸灯 无自动熄灭
void fade(int pin,int maxl,int time) {
analogWrite(pin, brightness);   
// change the brightness for next time through the loop:
brightness = brightness + fadeAmount;
// reverse the direction of the fading at the ends of the fade:
if (brightness <= 0 || brightness >= maxl) {
    fadeAmount = -fadeAmount ;
}         
delay(time);
}
//闪烁
void Blink(int pin,int ontime,int offtime) {
digitalWrite(pin,LOW);   // set the LED on
delay(ontime);            
digitalWrite(pin, HIGH);    // set the LED off
delay(offtime);         
}
//闪光
void flash(int pin,int time) {
digitalWrite(pin, LOW);
digitalWrite(pin, HIGH);
delay(time);
digitalWrite(pin, LOW);
}
//震动
void shockme(int pin,int ontime,int offtime) {
digitalWrite(pin,HIGH);
delay(ontime);            
digitalWrite(pin, LOW);
delay(offtime);   
}

//检测震动
boolean checkknock() {
boolean isknocked = false;
int sensorReading = analogRead(knockpin);
    if (sensorReading >= 2) {
      isknocked=true;
    }
return isknocked;
}
//检测光线遮挡
boolean checkcover() {
boolean iscovered = false;
int temp=analogRead(lightpin);
if((lightvalue - temp) >= 50) {
    iscovered = true;
}
lightvalue = temp;
delay(50);
return iscovered;
}
//检测光线遮挡快速
boolean checkcoverfast() {
boolean iscovered = false;
int temp=analogRead(lightpin);
if((lightvalue - temp) >= 50) {
    iscovered = true;
}
lightvalue = temp;
return iscovered;
}
//检测激活
boolean checkActive() {
boolean isActive =false;
isActive = checkcoverfast();
if(!isActive)
{
    isActive = checkknock();
}
return isActive;
}

//计数器计时
void tick() {
currentMillis = millis();
//计时器溢出自动复位的处理
if(currentMillis < previousMillis) {
    unsigned long partMillis = 4294967295 -previousMillis + 1;
    previousMillis =-partMillis + 1;
}
}
//同时只允许使用一个计数器
boolean checktime(unsigned long time) {
boolean istimeup =false;
if(currentMillis - previousMillis >= time) {
    istimeup = true;
    resettick();
}
return istimeup;
}
//重置计数器
void resettick() {
previousMillis=currentMillis;
}项目引用的文件:
pitches.h/*************************************************
* Public Constants
*************************************************/

#define NOTE_B031
#define NOTE_C133
#define NOTE_CS1 35
#define NOTE_D137
#define NOTE_DS1 39
#define NOTE_E141
#define NOTE_F144
#define NOTE_FS1 46
#define NOTE_G149
#define NOTE_GS1 52
#define NOTE_A155
#define NOTE_AS1 58
#define NOTE_B162
#define NOTE_C265
#define NOTE_CS2 69
#define NOTE_D273
#define NOTE_DS2 78
#define NOTE_E282
#define NOTE_F287
#define NOTE_FS2 93
#define NOTE_G298
#define NOTE_GS2 104
#define NOTE_A2110
#define NOTE_AS2 117
#define NOTE_B2123
#define NOTE_C3131
#define NOTE_CS3 139
#define NOTE_D3147
#define NOTE_DS3 156
#define NOTE_E3165
#define NOTE_F3175
#define NOTE_FS3 185
#define NOTE_G3196
#define NOTE_GS3 208
#define NOTE_A3220
#define NOTE_AS3 233
#define NOTE_B3247
#define NOTE_C4262
#define NOTE_CS4 277
#define NOTE_D4294
#define NOTE_DS4 311
#define NOTE_E4330
#define NOTE_F4349
#define NOTE_FS4 370
#define NOTE_G4392
#define NOTE_GS4 415
#define NOTE_A4440
#define NOTE_AS4 466
#define NOTE_B4494
#define NOTE_C5523
#define NOTE_CS5 554
#define NOTE_D5587
#define NOTE_DS5 622
#define NOTE_E5659
#define NOTE_F5698
#define NOTE_FS5 740
#define NOTE_G5784
#define NOTE_GS5 831
#define NOTE_A5880
#define NOTE_AS5 932
#define NOTE_B5988
#define NOTE_C61047
#define NOTE_CS6 1109
#define NOTE_D61175
#define NOTE_DS6 1245
#define NOTE_E61319
#define NOTE_F61397
#define NOTE_FS6 1480
#define NOTE_G61568
#define NOTE_GS6 1661
#define NOTE_A61760
#define NOTE_AS6 1865
#define NOTE_B61976
#define NOTE_C72093
#define NOTE_CS7 2217
#define NOTE_D72349
#define NOTE_DS7 2489
#define NOTE_E72637
#define NOTE_F72794
#define NOTE_FS7 2960
#define NOTE_G73136
#define NOTE_GS7 3322
#define NOTE_A73520
#define NOTE_AS7 3729
#define NOTE_B73951
#define NOTE_C84186
#define NOTE_CS8 4435
#define NOTE_D84699
#define NOTE_DS8 4978notes.h //beep tone
// notes in the melody:
int notesalarm[] = {
NOTE_C4, NOTE_G3,NOTE_G3, NOTE_A3, NOTE_G3,0, NOTE_B3, NOTE_C4};
// note durations: 4 = quarter note, 8 = eighth note, etc.:
int Durationalarm[] = {
    4,8,8,4,4,4,4,4 };

//start tone
int notesstart[] = {
NOTE_C5, NOTE_G5,NOTE_E5, NOTE_G5};
int Durationsstart[] = {
   8, 8, 8,4 };
   
//nokia tone
int notesnokia[] = {
NOTE_G5, NOTE_F5, NOTE_A4, NOTE_B4,
NOTE_E5, NOTE_D5, NOTE_F4, NOTE_G4,
NOTE_D5, NOTE_C5, NOTE_E4, NOTE_G4,
NOTE_C5 };
int Durationsnokia[] = {
   8, 8, 4, 4,
   8, 8, 4, 4,
   8, 8, 4, 4,
   2};
   
   //machinecat
   int notescat[] = {
NOTE_G4, NOTE_A4, NOTE_C5, NOTE_E5,NOTE_A5,NOTE_E5,NOTE_G5,0,
NOTE_G5, NOTE_A5, NOTE_G5, NOTE_E5,NOTE_F5, NOTE_E5,NOTE_D5,0,
NOTE_A4,NOTE_D5, NOTE_D5,NOTE_F5, NOTE_B5, NOTE_B5, NOTE_A5, NOTE_G5,
NOTE_F5,NOTE_F5,NOTE_E5,NOTE_A4,NOTE_B4,NOTE_C5,
NOTE_D5,
NOTE_A5,NOTE_A5,NOTE_G5,NOTE_F5,NOTE_G5,NOTE_A5,NOTE_G5,
NOTE_D5,NOTE_E5,NOTE_FS5,NOTE_D5,NOTE_G5,0,
NOTE_A5,0,NOTE_G5,0,NOTE_F5,0,0,
NOTE_D5,NOTE_B5,NOTE_A5,NOTE_G5,NOTE_A5,NOTE_G5,NOTE_F5,
0,NOTE_G5,NOTE_A5,NOTE_E5,NOTE_D5,
NOTE_C5
};
int Durationscat[] = {
   4, 8, 4, 8, 4, 8,3,32,
   4, 8, 4, 8, 4, 8,3,16,
   4, 8, 4, 8, 4, 8,4,8,
   3, 3, 8, 3, 3, 8,
   1,
   3, 4, 8, 8, 8, 8,3,
   4, 8, 4, 8, 2, 8,
   4, 8, 4, 8, 4, 8, 4,
   3, 4, 8, 4, 8, 4, 4,
   4, 4, 8, 2, 8,
   1
};
   
   //Mario
   int notemario[] = {NOTE_E4, NOTE_E4, NOTE_E4, NOTE_C4, NOTE_E4, NOTE_G4, NOTE_G3,NOTE_C4,
   NOTE_G3, NOTE_E3, NOTE_A3, NOTE_B3, NOTE_AS3, NOTE_A3, NOTE_G3, NOTE_E4, NOTE_G4, NOTE_A4,
   NOTE_F4, NOTE_G4, NOTE_E4, NOTE_C4, NOTE_D4, NOTE_B3,NOTE_C4, NOTE_G3, NOTE_E3, NOTE_A3,
   NOTE_B3, NOTE_AS3, NOTE_A3, NOTE_G3, NOTE_E4, NOTE_G4, NOTE_A4, NOTE_F4, NOTE_G4, NOTE_E4,
   NOTE_C4, NOTE_D4, NOTE_B3,NOTE_G4, NOTE_FS4, NOTE_E4, NOTE_DS4, NOTE_E4, NOTE_GS3, NOTE_A3,
   NOTE_C4, NOTE_A3, NOTE_C4, NOTE_D4, NOTE_G4, NOTE_FS4, NOTE_E4, NOTE_DS4, NOTE_E4, NOTE_C5,
   NOTE_C5, NOTE_C5,NOTE_G4, NOTE_FS4, NOTE_E4, NOTE_DS4, NOTE_E4, NOTE_GS3, NOTE_A3, NOTE_C4,
   NOTE_A3, NOTE_C4, NOTE_D4, NOTE_DS4, NOTE_D4,NOTE_C4};
   int Durationsmario[] = {8,4,4,8,4,2,2,3,
   3,3,4,4,8,4,8,8,8,4,
   8,4,3,8,8,3,3,3,3,4,
   4,8,4,8,8,8,4,8,4,3,
   8,8,2,8,8,8,4,4,8,8,
   4,8,8,3,8,8,8,4,4,4,
   8,2,8,8,8,4,4,8,8,4,
   8,8,3,3,3,2};
   
   //Mission Impossible
   int noteMission[] = {NOTE_D5,NOTE_DS5, NOTE_D5,NOTE_DS5,NOTE_D5,NOTE_DS5,NOTE_D5,
   NOTE_DS5,NOTE_D5,NOTE_DS5,NOTE_D5,NOTE_DS5,NOTE_D5,NOTE_DS5,NOTE_D5,
   NOTE_DS5,NOTE_D5,NOTE_DS5,NOTE_D5,NOTE_DS5,NOTE_D5,NOTE_DS5,NOTE_D5,
   NOTE_DS5,NOTE_D5,NOTE_DS5,NOTE_D5,NOTE_DS5,NOTE_D5,NOTE_DS5,NOTE_D5,
   NOTE_DS5,NOTE_D5,NOTE_DS5,NOTE_D5,NOTE_DS5,NOTE_DS5,NOTE_E5,NOTE_F5,
   NOTE_G5,
   NOTE_E2,0,0,NOTE_E2,0,NOTE_E2,NOTE_G2,0,NOTE_A2,0,
   NOTE_E2,0,0,NOTE_E2,0,NOTE_E2,NOTE_D2,0,NOTE_DS2,0,
   NOTE_AS4,NOTE_G4,NOTE_D4,NOTE_D4,NOTE_AS4,NOTE_G4,NOTE_CS4,NOTE_CS4,NOTE_AS4,NOTE_G4,NOTE_C4,NOTE_C4,NOTE_B3,NOTE_C4,0,
   NOTE_B3,NOTE_G3,NOTE_FS4,NOTE_FS4,NOTE_B3,NOTE_G3,NOTE_F4,NOTE_F4,NOTE_B3,NOTE_G3,NOTE_E4,NOTE_E4,NOTE_DS4,NOTE_D4
   
   };
   int DurationsMission[] = {8,16,16,16,16,16,16,
   16,16,16,16,16,16,16,16,
   16,16,16,16,16,16,16,16,
   16,16,16,16,16,16,16,16,
   16,16,16,16,16,16,16,16,
   8,
   6,6,6,6,6,6,6,6,6,6,
   6,6,6,6,6,6,6,6,6,6,
   6,6,2,1,6,6,2,1,6,6,2,1,6,6,1,
   6,6,2,1,6,6,2,1,6,6,2,1,6,6
   };完成:


注意事项:

[*]压电陶瓷片尽量选用灵敏的、分贝高的,否则就不能感应声音只能感应震动了
[*]扬声器是原玩偶自带的16欧姆0.25W,建议串100欧姆电阻
[*]从U盘引出电源时注意造成短路

视频:
http://v.youku.com/v_show/id_XNDAwMDMyOTMy.html

致谢:
感谢“极客工房”论坛提供初学者入门教程。

幻生幻灭 发表于 2012-5-21 18:51:15

连机器猫都不放过,好歹USB的位置不算邪恶;P

davidce 发表于 2012-5-21 19:10:52

幻生幻灭 发表于 2012-5-21 18:51 static/image/common/back.gif
连机器猫都不放过,好歹USB的位置不算邪恶

你的想法太“邪恶”

heiketiguo 发表于 2012-5-21 23:54:20

{:soso_e179:}好

珜羽 发表于 2012-5-22 00:55:18

原理图有木有?难道是PWM的DA发声?

迷你强 发表于 2012-5-22 10:09:29

:funk:好先进,好惨的机器猫

davidce 发表于 2012-5-22 10:28:29

珜羽 发表于 2012-5-22 00:55 static/image/common/back.gif
原理图有木有?难道是PWM的DA发声?

参考 arduino 的 tone 函数

windowspp 发表于 2012-5-23 07:13:19

哈哈....;P;P

davidce 发表于 2012-6-3 19:42:37

xqi2 发表于 2012-6-3 15:09 static/image/common/back.gif
不 知道 你的音乐文件 是如何用数字定义的   这个太高深了真不懂

在 notes.h 文件中定义

darkorigin 发表于 2012-6-6 21:23:25

xqi2 发表于 2012-6-3 15:09 static/image/common/back.gif
不 知道 你的音乐文件 是如何用数字定义的   这个太高深了真不懂

论坛精华区有教程,固顶的,没看过?

darkorigin 发表于 2012-6-6 21:24:50

珜羽 发表于 2012-5-22 00:55 static/image/common/back.gif
原理图有木有?难道是PWM的DA发声?

精华区有。PWM可以,但是ARDUINO在PWM时候就不能做其他了,用tone函数同时还可以做其他事情。
精华区有教程。

smfox10 发表于 2012-7-18 14:34:44

好厉害!那些歌曲你是怎么生成的?自己对着乐谱打的吗?

davidce 发表于 2012-7-18 15:32:18

smfox10 发表于 2012-7-18 14:34 static/image/common/back.gif
好厉害!那些歌曲你是怎么生成的?自己对着乐谱打的吗?

差不多吧

Mone 发表于 2012-7-18 15:57:30

我也想用有一个............

mike6606 发表于 2015-3-31 22:41:11

哈哈,要是能走起来就好了:D
页: [1] 2
查看完整版本: 基于arduino nano的“机器猫”