Hur man gör en musikal, motordriven glöd-i-the-dark-ghost mobil (16 / 17 steg)
Steg 16: Knyta alla ihop med en Arduino
- Styr stegmotor för att rotera den ghost mobilen
- Roterar i en sinusformad mönster så att de ser mer "autonoma"
- Roterar i 10 sekunder (justerade perfekt med ljud)
- Konverterar IR-koder från den fjärrkontroll som kom med IR remote kit till de rätta IR-koderna för Kenwood CD spelare
- Ger en IR läsa funktionen att fånga och Visa den exakta IR-kod datan från originalfjärrkontrollen
- Innehåller en hårdkodad lista med knappen tryck koder för användning i översätta de avlägsna knapptryckningar
- Skickar en lämplig IR kod baserat på viktiga press på nya fjärrkontrollen
- Skickar koder "Paus" och "Hoppa över" 10 sekunder efter på play-knappen trycks
- Koden skickas även vissa debug-meddelanden till serieporten konsolen om du är intresserad av detaljerna under huven medan den är igång.
Ursprungligen var jag planerar att även styra belysning för att släck lamporna när en rörelsesensor var utlöst. Tyvärr bröt jag hårdvara jag använde och inte hade tid att byta ut den så att systemet kommer att kontrolleras helt av fjärrkontrollen.
Listan nedan kartor Arduino Mego 2560 styrelsen stiften till respektive komponent:
- Status-LED: PWM stift 13
- IR-mottagare Data ingång: PWM stift 11
- IR-sändare till CD-spelare: PWM stift 8
- Stepper Motor Control signaler: PWM stift 4, 5, 6 och 7
- Skäl som cirkuleras till lämplig stift som krävs
Två befintliga delar av koden användes och kraftigt modifierad. Dessa inkluderar IRremote bibliotek som tillhandahålls av Ken Shirriff och stepper motor exempelkoden ingår i Arduino SDK. Och slutligen, här är koden (som belånade och krediteras tidigare verk):
/////////////////////////////////////////////////////////////////////////////////////////
/*
Stepper Motor Control - sinusoidal rotation
This program drives a unipolar or bipolar stepper motor.
The motor is attached to digital pins 4 - 7 of the Arduino.
The motor should revolve one direction
following a sinusoidal rate of rotation.
The program also allows the user to remotely activate and deactivate the
glowing ghost mobile of doom. It sends control signals to the mobile for 10
during which time the audio from the disk in the CD player will play 10
seconds of audio. After 10 seconds the code will send the pause and skip
command to go to the next track.
Created on Nov. 4th, 2012
(Some parts based on Stepper Motor Control program by Tom Igoe
Created 11 Mar. 2007
Modified 30 Nov. 2009)
(Some parts based on IRrecord program by Ken Shirriff
Created September, 2009)
*/
#define PAUSE_PLAY_BUTTON 0x6D92C837
#define REPEAT_BUTTON 0x6D929867
#define SKIP_BUTTON 0x6D92E817
#define POWER 0x00FFA25D
#define BUTTON_MODE 0x00FF629D
#define BUTTON_PAUSE_PLAY 0x00FF22DD
#define BUTTON_SKIP 0x00FFC23D
#define BUTTON_0 0x00FF6897
#define BUTTON_1 0x00FF30CF
#define BUTTON_2 0x00FF18E7
#define BUTTON_3 0x00FF7A85
#define BUTTON_4 0x00FF10EF
#define BUTTON_5 0x00FF38C7
#define BUTTON_6 0x00FF5AA5
#define BUTTON_7 0x00FF42BD
#define BUTTON_8 0x00FF4AB5
#define BUTTON_9 0x00FF52AD
#include <Stepper.h>
#include <IRremote.h>
int RECV_PIN = 11;
int BUTTON_PIN = 12;
int STATUS_PIN = 13;
IRrecv irrecv(RECV_PIN);
IRsend irsend;
decode_results results;
int step_enabled = LOW;
const int stepsPerRevolution = 2048; // change this to fit the number of steps per revolution for your motor
const float max_speed = 10; //sets the maximum rotational speed of the motor
const float resolution = 100; //sets the frequency by which the motor speed will change
float rotational_vel = 0; //holds the current rotational velocity scalar
// initialize the stepper library on pins 8 through 11:
Stepper myStepper(stepsPerRevolution, 4,5,6,7);
void setup() {
// initialize the serial port:
Serial.begin(9600);
irrecv.enableIRIn(); // Start the receiver
pinMode(BUTTON_PIN, INPUT);
pinMode(STATUS_PIN, OUTPUT);
}
// Storage for the recorded code
int codeType = NEC; // The type of code
unsigned long codeValue = 0x6D92C837; // The code value if not raw
int codeLen = 32; // The length of the code
int toggle = 0; // The RC5/6 toggle state
int buttonState = LOW; //virtual button press
// Stores the code for later playback
// Most of this code is just logging
void storeCode(decode_results *results)
{
codeType = results->decode_type;
int count = results->rawlen;
if (results->value == REPEAT)
{
// Don't record a NEC repeat value as that's useless.
Serial.println("repeat; ignoring.");
buttonState = LOW;
return;
}
Serial.print("storing code: ");
Serial.print(results->value, HEX);
codeValue = results->value;
codeLen = results->bits;
Serial.print("; code length: ");
Serial.println(codeLen);
buttonState = HIGH;
}
void sendCode(int repeat) {
if (repeat)
{
irsend.sendNEC(REPEAT, codeLen);
Serial.println("Sent NEC repeat");
buttonState = LOW; //turn off virtual button after sending code
}
else
{
Serial.println("Sending non-repeat code.");
switch (codeValue) {
case POWER:
irsend.sendNEC(PAUSE_PLAY_BUTTON, 32);
codeValue = PAUSE_PLAY_BUTTON;
Serial.print("Sent pause play code: ");
Serial.println(PAUSE_PLAY_BUTTON, HEX);
buttonState = LOW; //turn off virtual button after sending code
break;
case BUTTON_PAUSE_PLAY:
irsend.sendNEC(PAUSE_PLAY_BUTTON, 32);
Serial.print("Sent pause play code: ");
Serial.println(PAUSE_PLAY_BUTTON, HEX);
buttonState = LOW; //turn off virtual button after sending code
break;
case BUTTON_MODE:
irsend.sendNEC(REPEAT_BUTTON, 32);
Serial.print("Sent repeat code: ");
Serial.println(REPEAT_BUTTON, HEX);
buttonState = LOW; //turn off virtual button after sending code
break;
case BUTTON_SKIP:
irsend.sendNEC(SKIP_BUTTON, 32);
Serial.print("Sent skip code: ");
Serial.println(SKIP_BUTTON, HEX);
buttonState = LOW; //turn off virtual button after sending code
break;
}
}
}
int lastButtonState = LOW;
int i = 1;
void loop() {
if (i > resolution)
{
i = 1;
}
// If button pressed, send the code.
//buttonState = digitalRead(BUTTON_PIN);
if (lastButtonState == HIGH && buttonState == LOW) {
Serial.println("Released");
lastButtonState = LOW;
irrecv.enableIRIn(); // Re-enable receiver
}
if (buttonState) {
Serial.println("Sending IR code");
digitalWrite(STATUS_PIN, HIGH);
sendCode(lastButtonState == buttonState);
digitalWrite(STATUS_PIN, LOW);
step_enabled = HIGH;
lastButtonState = HIGH;
//delay(50); // Wait a bit between retransmissions
}
else if (irrecv.decode(&results)) {
Serial.println("Reading IR code");
digitalWrite(STATUS_PIN, HIGH);
storeCode(&results);
irrecv.resume(); // resume receiver
digitalWrite(STATUS_PIN, LOW);
}
//Serial.println("rotate the motor");
rotational_vel = abs(max_speed * sin(float(i)*3.14159/10) + 2); //program a sinusoidal velocity for the stepper motor
myStepper.setSpeed(rotational_vel);
if (abs(rotational_vel) > 0.001 && step_enabled == HIGH) //a velocity of 0 will lock up the stepper.h library.
{
Serial.println("valid stepper function entry");
if (i < resolution && step_enabled == HIGH)
{
Serial.print("iteration: ");
Serial.println(i);
Serial.print("Velocity: ");
Serial.println(rotational_vel);
myStepper.step(10 * rotational_vel);
i++;
}
else
{
step_enabled = LOW;
i = 0;
Serial.println("Pausing Playback and Skipping");
digitalWrite(STATUS_PIN, HIGH);
codeValue = BUTTON_PAUSE_PLAY;
sendCode(1 == 2);
delay(100); //Wait between transmissions
codeValue = BUTTON_SKIP;
sendCode(1 == 2);
digitalWrite(STATUS_PIN, LOW);
lastButtonState = HIGH;
}
}
}