给狗子和猫咪的福利:激光逗狗/逗猫玩具-Arduino中文社区 - Powered by Discuz! Archiver

softice 发表于 2019-4-29 16:55

给狗子和猫咪的福利:激光逗狗/逗猫玩具



以前是直接拿一个激光笔和狗子玩的,后来感觉挺累的,所以做了个这个,放在高处,只需要按一下,就能让狗嗨几分钟,太省心了……


因为是要放在高的地方,所以里面用了一个18650电池。用一个充电管理的模块,给电池充电,同时供电给Arduino Nano。背面是开关,和一个充电口。





红外遥控的,以免狗子发现是我在弄。。。在远处哪怕隔着玻璃都能开起来玩。这个外壳原来是白色的,用手喷漆喷成了黑色。





打开看看,没有意外的很乱,线也接的很随缘。推荐按照:VCC=红,GND=黑,IO=黄 这样接线的话,以后坏了也方便查找问题。





舵机可能是价格太便宜了还是怎么,空载的时候会抖。所以随缘给它加了一个104电容(手边只有这个了),就不抖了。。。


然后重点是那颗电解,没有它的话,舵机一启动,一下会拉低很多电压,单片机就复位。有了它,就没问题了。用的是 3300μF 的(手边只有这个了)。





感觉自带了点忧郁的气质。





合影来一张。遥控器的方向键可以设置横向、纵向的范围,也就是狗子嗨的幅度,数字1-9是设置运行的时长的。

OK 是开始嗨。嗨到设置的时长为止。不然狗容易累到打人。


**** Hidden Message *****
视频在此:https://www.bilibili.com/video/av50884184/
注:因为狗嗨的太智障所以只有机器的运行视频因此并没有狗出镜。




softice 发表于 2019-4-29 23:17

源码在此:
#include <Servo.h>
#include <IRremote.h>
#include "TM1637.h"

#define pinIR 2
#define pinIndicatorLed 3
#define pinLaser 4
#define pinServoH 7
#define pinServoV 8
#define picLcdCLK 9
#define pinLcdDIO 10

Servo servoH;
Servo servoV;

IRrecv irrecv(pinIR);
decode_results results;

TM1637 tm1637(picLcdCLK, pinLcdDIO);

unsigned int rangeH = 25;
unsigned int rangeH_pre;
unsigned int rangeV = 20;
unsigned int rangeV_pre;
unsigned int rangeT = 60;
unsigned int rangeT_pre;
unsigned int limitH = 75;
unsigned int limitV = 35;
unsigned int midH = 80;
unsigned int midV = 40;
unsigned int heartBeat = 5;
bool preButton ;
bool playing = false;
unsigned long lastDisplay = 0;
unsigned long lastButtonChange = 0;
unsigned long gameStartTime = 0;
unsigned int buttonWaitDelay = 2000;
unsigned long lastCheckTime = 0;
bool displayCleared = false;
unsigned int tmp_second;
int gameTimeRemain = 0;
bool timerPoint = false;


void setup() {
pinMode(pinLaser, OUTPUT);
pinMode(pinIndicatorLed, OUTPUT);
digitalWrite(pinLaser, HIGH);
randomSeed(analogRead(0));
irrecv.enableIRIn();

// welcome
tm1637.init();
tm1637.set(BRIGHT_TYPICAL);
hi();

// debug
// Serial.begin(9600);
}

void hi() {
tm1637.display(3, 0);
delay(400);
tm1637.display(2, 0);
tm1637.display(3, 0);
delay(400);
tm1637.point(1);
tm1637.display(1, 0);
tm1637.display(2, 0);
tm1637.display(3, 0);
delay(400);
tm1637.display(0, 0);
tm1637.display(1, 0);
tm1637.display(2, 0);
tm1637.display(3, 0);
delay(400);
tm1637.clearDisplay();
delay(200);
tm1637.point(1);
tm1637.display(0, 0);
tm1637.display(1, 0);
tm1637.display(2, 0);
tm1637.display(3, 0);
delay(200);
tm1637.clearDisplay();
delay(200);
tm1637.point(1);
tm1637.display(0, 0);
tm1637.display(1, 0);
tm1637.display(2, 0);
tm1637.display(3, 0);
delay(1000);
servoH.attach(pinServoH);
servoV.attach(pinServoV);
servoMigrateOne(servoH, 90, 15);
servoMigrateOne(servoV, 10, 15);
servoH.detach();
servoV.detach();
}

void servoMigrateOne(Servo &myServo, int newPos, int wait) {
int pos = myServo.read();
if (pos < newPos) {
    for (int i = pos; i < newPos; i++) {
      myServo.write(i);
      delay2(wait);
    }
} else {
    for (int i = pos; i > newPos; i--) {
      myServo.write(i);
      delay2(wait);
    }
}
flashOnboardLed();
}

void servoMigrateHV(int h, int v, int wait) {
int posH = servoH.read();
int posV = servoV.read();
int maxSteps = max(abs(h - posH), abs(v - posV));

for (int i = 0; i <= maxSteps; i++) {
    if (posH < h) {
      servoH.write(posH + i * (h - posH) / maxSteps);
      delay2(wait);
    } else {
      servoH.write(posH - i * (posH - h) / maxSteps);
      delay2(wait);
    }
    if (posV < v) {
      servoV.write(posV + i * (v - posV) / maxSteps);
      delay2(wait);
    } else {
      servoV.write(posV - i * (posV - v) / maxSteps);
      delay2(wait);
    }
}
flashOnboardLed();
}

void flashLaser() {
digitalWrite(pinLaser, HIGH);
delay2(1000);
for (int i = 0; i <= 10; i++) {
    digitalWrite(pinLaser, LOW);
    delay2(25);
    digitalWrite(pinLaser, HIGH);
    delay2(50);
}
digitalWrite(pinLaser, LOW);
}

void loop() {
if (irrecv.decode(&results)){
    // Serial.println(results.value, HEX);
    switch (results.value) {
      case 0xFF38C7:
      // ok
      if (playing) {
          pauseGame();
      } else {
          delay(1000);
          servoH.attach(pinServoH);
          servoV.attach(pinServoV);
          playing = true;
          gameStartTime = millis();
          digitalWrite(pinLaser, LOW);
      }
      break;
      case 0xFFA25D:
      // 1
      rangeT = 10;
      break;
      case 0xFF629D :
      // 2
      rangeT = 20;
      break;
      case 0xFFE21D :
      // 3
      rangeT = 30;
      break;
      case 0xFF22DD :
      // 4
      rangeT = 40;
      break;
      case 0xFF02FD :
      // 5
      rangeT = 50;
      break;
      case 0xFFC23D :
      // 6
      rangeT = 60;
      break;
      case 0xFFE01F :
      // 7
      rangeT = 70;
      break;
      case 0xFFA857 :
      // 8
      rangeT = 80;
      break;
      case 0xFF906F :
      // 9
      rangeT = 90;
      break;

      case 0xFF18E7 :
      //up
      if (rangeV + 5 <= limitV) {
          rangeV += 5;
      }
      break;
      case 0xFF10EF :
      //left
      if (rangeH   >= 5) {
          rangeH -= 5;
      }
      break;
      case 0xFF5AA5 :
      //right
      if (rangeH + 5 <= limitH) {
          rangeH += 5;
      }
      break;
      case 0xFF4AB5 :
      //down
      if (rangeV>= 5) {
          rangeV -= 5;
      }
      break;

    }
    irrecv.resume(); // Receive the next value
}

// check range
if (rangeH != rangeH_pre) {
    rangeH_pre = rangeH;
    // display new H value
    tm1637.point(1);
    tm1637.display(0, 21);
    tm1637.display(1, 16);
    tm1637.display(2, rangeH / 10);
    tm1637.display(3, rangeH % 10);
    lastDisplay = millis();
    displayCleared = false;
}
if (rangeV != rangeV_pre) {
    rangeV_pre = rangeV;
    tm1637.point(1);
    tm1637.display(0, 21);
    tm1637.display(1, 18);
    tm1637.display(2, rangeV / 10);
    tm1637.display(3, rangeV % 10);
    lastDisplay = millis();
    displayCleared = false;
}

if (rangeT != rangeT_pre) {
    rangeT_pre = rangeT;
    // display new T value
    tm1637.point(1);
    tm1637.display(0, 20);
    tm1637.display(1, rangeT / 60);
    tmp_second = rangeT - 60 * (rangeT / 60);
    tm1637.display(2, tmp_second / 10);
    tm1637.display(3, tmp_second % 10);
    lastDisplay = millis();
    displayCleared = false;
}

// clear display
if (millis() - lastDisplay > 2000 && !displayCleared) {
    //tm1637.point(0);
    //tm1637.clearDisplay();
    displayCleared = true;
}

if (playing) {
    playGame();
    tasks();
    if (gameTimeRemain <= 0) {
      // stop game
      pauseGame();
    }
}
}

void playGame() {
servoMigrateHV(random(midH - rangeH, midH + rangeH), random(midV - rangeV, midV + rangeV), random(10, 30));
if (random(15) <= 1) {
    flashLaser();
}
}

void pauseGame() {
// debug
digitalWrite(pinLaser, HIGH);
// Serial.println("sleep");
delay(1000);
servoMigrateOne(servoH,90,15);
servoMigrateOne(servoV,30,15);
delay(1000);
servoH.detach();
servoV.detach();
playing = false;
tm1637.point(1);
tm1637.display(0, 0);
tm1637.display(1, 0);
tm1637.display(2, 0);
tm1637.display(3, 0);
}

void flashOnboardLed() {
digitalWrite(pinIndicatorLed, HIGH);
delay(15);
digitalWrite(pinIndicatorLed, LOW);
}

void displayTimer() {
gameTimeRemain = (rangeT_pre - (millis() - gameStartTime) / 1000) ;
if (gameTimeRemain < 0) {
    gameTimeRemain = 0;
}
if (!displayCleared) {
    return;
}
timerPoint = !timerPoint;
tm1637.point(timerPoint);
tm1637.display(0, 21);
tm1637.display(1, gameTimeRemain / 60);
tmp_second = gameTimeRemain - 60 * (gameTimeRemain / 60);
tm1637.display(2, tmp_second / 10);
tm1637.display(3, tmp_second % 10);
}
void tasks() {
if (millis() - lastCheckTime >= 500) {
    lastCheckTime = millis();
    displayTimer();
}
}

void delay2(int delayMs) {
int loops = delayMs / heartBeat;
for (int i = 0; i <= loops; i++) {
    tasks();
    delay(heartBeat);
}
}


joker96 发表于 2019-4-30 09:47

厉害厉害,膜拜大佬

syl312 发表于 2019-4-30 13:06

社区有在送舵机的活动,了解下:https://www.arduino.cn/thread-85565-1-1.html

jpolo 发表于 2019-4-30 17:49

看楼主头像,想必是给自家二哈准备的吧:lol

softice 发表于 2019-5-5 12:06

syl312 发表于 2019-4-30 13:06
社区有在送舵机的活动,了解下:https://www.arduino.cn/thread-85565-1-1.html

多谢提醒~ 很早就在群里看到这个活动了,一时还没啥想法哈哈……

softice 发表于 2019-5-5 12:06

jpolo 发表于 2019-4-30 17:49
看楼主头像,想必是给自家二哈准备的吧

自家是只智障拉布拉多 感觉闹起来跟二哈没区别。。

wangyirun 发表于 2019-8-6 20:37

厉害厉害,顶!!!!

白羊羊罐头 发表于 2019-8-7 23:22

神乎其神,不得不服!

brucewoo 发表于 2019-8-8 23:11

想看智障狗子:lol
页: [1] 2
查看完整版本: 给狗子和猫咪的福利:激光逗狗/逗猫玩具