给狗子和猫咪的福利:激光逗狗/逗猫玩具
以前是直接拿一个激光笔和狗子玩的,后来感觉挺累的,所以做了个这个,放在高处,只需要按一下,就能让狗嗨几分钟,太省心了……
因为是要放在高的地方,所以里面用了一个18650电池。用一个充电管理的模块,给电池充电,同时供电给Arduino Nano。背面是开关,和一个充电口。
红外遥控的,以免狗子发现是我在弄。。。在远处哪怕隔着玻璃都能开起来玩。这个外壳原来是白色的,用手喷漆喷成了黑色。
打开看看,没有意外的很乱,线也接的很随缘。推荐按照:VCC=红,GND=黑,IO=黄 这样接线的话,以后坏了也方便查找问题。
舵机可能是价格太便宜了还是怎么,空载的时候会抖。所以随缘给它加了一个104电容(手边只有这个了),就不抖了。。。
然后重点是那颗电解,没有它的话,舵机一启动,一下会拉低很多电压,单片机就复位。有了它,就没问题了。用的是 3300μF 的(手边只有这个了)。
感觉自带了点忧郁的气质。
合影来一张。遥控器的方向键可以设置横向、纵向的范围,也就是狗子嗨的幅度,数字1-9是设置运行的时长的。
OK 是开始嗨。嗨到设置的时长为止。不然狗容易累到打人。
**** Hidden Message *****
视频在此:https://www.bilibili.com/video/av50884184/
注:因为狗嗨的太智障所以只有机器的运行视频因此并没有狗出镜。
源码在此:
#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);
}
}
厉害厉害,膜拜大佬 社区有在送舵机的活动,了解下:https://www.arduino.cn/thread-85565-1-1.html 看楼主头像,想必是给自家二哈准备的吧:lol syl312 发表于 2019-4-30 13:06
社区有在送舵机的活动,了解下:https://www.arduino.cn/thread-85565-1-1.html
多谢提醒~ 很早就在群里看到这个活动了,一时还没啥想法哈哈…… jpolo 发表于 2019-4-30 17:49
看楼主头像,想必是给自家二哈准备的吧
自家是只智障拉布拉多 感觉闹起来跟二哈没区别。。 厉害厉害,顶!!!! 神乎其神,不得不服! 想看智障狗子:lol
页:
[1]
2