TxCar
Let's get an Arduino to listen to a TV remote first:
I have a Sharp Aquos TV that is also controlled with a Dish Hopper (I guess) remote. Will show testing with both later.
Here is some code, some copied from the examples in the library you need to download from the Arduino-IRremote github. There is a button at the top right, get the zip file on your PC. And then I unzipped all the files into a folder on my borrowed Windows 7 computer into: C:\Users\Speed\Documents\Arduino\libraries\Arduino-IRremote-master
You could also use the menu to Sketch -> Include Library -> Manage Libraries... to download and install IRremote:
On my computer, however, there was some RobotIRremote library (found in C:\Program Files (x86)\Arduino\libraries\RobotIRremote) providing an IRremote.h as needed in our #include <IRremote.h>, which was not the correct file...kept getting a "IRremoteTools.cpp:5:16: error: 'TKD2' was not declared in this scope", so I simply closed the Arduino software and moved the RobotIRremote folder to another temporary safe house. Far far away from the libraries folder.
Here we go:
// A TSOP34438 connected to 5V, GND and its OUT to pin 11 on a Nano.
// The pin 13 LED toggles every second, until a code is received and matched as Volume UP, then the LED toggles faster
// Volume DOWN will slow the toggle down again
#include <IRremote.h>#define LEDPIN 13#define DELAY 1000IRrecv irrecv( 11 ); // Receive on pin 11decode_results results;unsigned long now;unsigned long before;unsigned int delayed = DELAY;void setup() { pinMode( LEDPIN, OUTPUT ); Serial.begin( 115200 ); irrecv.enableIRIn(); // Start the receiver now = millis(); before = now; Serial.println("TxCar 2016.05.12_002");} // setupvoid loop() { now = millis(); if ( now - before > delayed ) { digitalWrite( LEDPIN, !digitalRead( LEDPIN ) ); before = before + delayed; } // if if ( irrecv.decode( &results ) ) { Serial.println( results.value, HEX ); switch ( results.value ) { case 0x1BE8C80D : delayed = delayed / 2; break; case 0x7E16B93A : delayed = 2 * delayed; break; default: break; } // switch irrecv.resume(); // Continue receiving } // if} // loop
And what you see is a millis() calculated delay to turn the LED on pin 13 on and off, where the delay is "delayed" long, starting at 1000 ms, which is 1 second. So, when the TSOP34438 delivers data on pin 11, and the decoding brings news that 0x1BE8C80D or 0x7E16B93A was delivered, the delay is either doubled or cut in half. So, which buttons are those, volume up and volume down, of course! But not so fast, there are a few more codes sent when you press the volume buttons on the Sharp remote, and even more when you use the Dish Hopper remote. Most likely more so the Hopper knows what is happening too, even though I believe the Hopper might be using RF to get its commands.
So, back to the basics, the remote is sending some code for each button, encoded and carried on a 38 kHz infrared signal. Sent over the air to the TSOP34438 sensor, which in turn has its OUTPUT connected to pin 11 on the Nano and the data is then received and decoded to produce a value in results.value. So, now you can press every button, find the unique code it sends, and stuff it in the
switch () { case NewCodeConstant: DoSomething(); break; } to do something useful when it gets that code.
We are heading to use two sensors on the left and right side of the TxCar, so we are either going to AND two sensors together into pin 11, or see if pin 10 can receive data at the same time. The first would be preferred, since we need every pin we can get for all the lights and action we want.
And here is the real code:
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Controlling a TxCar with a TV remote control//// A TSOP34438 connected to 5V, GND and its OUT to pin 11 on an Arduino Atmel ATMEGA328P.// Pin 13 LED flash with every IR command received.// Remote POWER-OFF turns everything off, and VOL-UP and DOWN will increase and decrease the motor speed// Remote buttons, 0-9, will turn the headlights on, high-beam, left or right indicator or break lights.// Hazards on remote 3// Clearance lights on pin 4// // next improvement would be to keep the indicator on after hazards turn off, if it was on before//// Author: Speed aka Gert 'Jim' Muller, 2016.08.11 //
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include <IRremote.h>// version log at the bottom...#define VERSIONSTRING "TxCar controller 2016.08.11 005"// this turns some Serial.println's on to help debug#define DEBUG false #define DEBUG2 false //// pins//#define MOTORPIN 10#define DEBUGLEDPIN 13#define CLEARANCEPIN 4#define TAILBRAKEPIN 5#define HEADLIGHTPIN 6// not enough PWM pins, the next two are pulsed in software#define LTURNPIN 8 #define RTURNPIN 7#define IRPIN 11//// remote codes//#define REMOTE_0 0xEF1008F7#define REMOTE_1 0xEF108877#define REMOTE_2 0xEF1048B7#define REMOTE_3 0xEF10C837#define REMOTE_4 0xEF1028D7#define REMOTE_5 0xEF10A857#define REMOTE_6 0xEF106897#define REMOTE_7 0xEF10E817#define REMOTE_8 0xEF1018E7#define REMOTE_9 0xEF109867#define REMOTE_MUTE 0xEF10906F#define REMOTE_POWER 0xEF1010EF#define REMOTE_CENTER 0xEF1022DD#define REMOTE_MENU 0xEF10C23D#define REMOTE_EXIT 0xEF10DA25#define REMOTE_VOLUP 0xEF1040BF#define REMOTE_VOLDN 0xEF10C03F#define REMOTE_DNARR 0xEF10A05F#define REMOTE_UPARR 0xEF1020DF//// times//#define TURNUPDATE 7#define TURNBLINKRATE 500#define HAZARDBLINKRATE 700//// brightnesses//#define HEADLIGHTLOWBEAM 20#define TAILLIGHTLOWBEAM 70#define INDICATORLOWBEAM 10#define INDICATORHIGHBEAM 200#define HIBEAM 200#define MOTORSPEEDMAX 60
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// PWM pin driving an N-channel FET with a small DC motor above it.class Motor { const bool MOTOR_DEBUG = true; byte pwmPin; byte motorState; unsigned int motorSpeed; unsigned long _now; unsigned long _before; unsigned long _DELAY; void output() { if ( MOTOR_DEBUG ) { Serial.print( "motor out " ); Serial.println( motorSpeed ); } // if analogWrite( pwmPin, motorSpeed ); } // output public: Motor( int motorPwmPin ) { pwmPin = motorPwmPin; motorState = 0; // off motorSpeed = 0; // not flashing _DELAY = 1000; } // Constructor Motor( int ) void powerOff() { motorSpeed = 0; output(); } // powerOff void increaseSpeed() { if ( motorSpeed < ( MOTORSPEEDMAX - 10 ) ) motorSpeed += 10; else motorSpeed = MOTORSPEEDMAX; output(); } // increaseSpeed void decreaseSpeed() { if ( motorSpeed > 10 ) motorSpeed -= 10; else motorSpeed = 0; output(); } // decreaseSpeed void fullSpeed() { motorSpeed = MOTORSPEEDMAX; output(); } // fullSpeed void midSpeed() { motorSpeed = MOTORSPEEDMAX / 2; output(); } // midSpeed void setupPin() { pinMode( pwmPin, OUTPUT ); motorState = 0; // off _now = millis(); _before = _now; } // setupPin void update() { _now = millis(); if ( ( _now - _before ) > _DELAY ) { if ( motorState == 1 ) { Serial.print( "motor at " ); Serial.println( motorSpeed ); } else { Serial.print( "motor off." ); } // if else } // if } // update}; // class motor////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////class RunningTurnSignalManualPWM { // this is on or off, low or high brightness on PWM pin // Class Member Variables // These are initialized at startup int ledPin; // the number of the LED pin int ledState; // 0==off, 1==on int ledFlash; // 0==off, 1==flashing int ledValue; // 0 through 255 int lightsOn; // 0==off, 1==on int lowValue; // value for off (0 for on/off, else for headlights on) byte count = 0; // counting for manual pwm unsigned long _now; unsigned long _before; unsigned long _flashbefore; void output() { if ( DEBUG2 ) { Serial.print( "Output: " ); Serial.print( ledPin ); Serial.print( " " ); Serial.print( ledState ); Serial.print( " " ); Serial.print( ledFlash ); Serial.print( " " ); Serial.print( ledValue ); Serial.print( "cnt " ); Serial.print( count ); Serial.print( " " ); Serial.println( lightsOn ); } // if DEBUG if ( ledState == 0 ) digitalWrite( ledPin, LOW ); if (( ledState == 1 ) && ( lightsOn == 1 ) && ( ledValue == 255 ))
digitalWrite( ledPin, HIGH ); } // outputpublic: // Constructor - creates a Flasher // and initializes the member variables and state RunningTurnSignalManualPWM( int pin ) { ledPin = pin; ledValue = INDICATORLOWBEAM; // above or below 127 lowValue = INDICATORLOWBEAM; ledState = 0; // off ledFlash = 0; // not flashing lightsOn = 0; // lights off be default } // Constructor RunningTurnSignalManualPWM( int ) void setupPin() { pinMode( ledPin, OUTPUT ); ledState = 0; // off _flashbefore = millis(); _now =_flashbefore; _before = _now; } // setupPin void toggleFlash() { if ( ledFlash == 0 ) { if ( DEBUG ) Serial.println( "Flash was off" ); ledFlash = 1; _flashbefore = millis(); ledState = 1; } else { if ( DEBUG ) Serial.println( "Flash was on" ); ledFlash = 0; ledValue = lowValue; // above or below 127 } // if else output(); } // toggleFlash void togglePower() { if ( ledState == 0 ) ledState = 1; else ledState = 0; output(); } // togglePower void toggleBeam() { if ( ledValue == lowValue ) ledValue = INDICATORHIGHBEAM; else ledValue = lowValue; output(); } // toggleBeam void fullOn() { lightsOn = 1; ledState = 1; ledValue = 255; output(); } // fullOn void powerOn() { lightsOn = 1; ledState = 1; ledValue = INDICATORHIGHBEAM; } // powerOn void powerOff() { lightsOn = 0; ledState = 0; // this turns it OFF ledFlash = 0; ledValue = lowValue; output(); } // powerOff void headlightOn() { lowValue = INDICATORLOWBEAM; lightsOn = 1; ledState = 1; // this turns it ON } // headlightOn void headlightOff() { lowValue = 0; lightsOn = 0; if ( ledFlash == 0 ) ledState = 0; // this turns it OFF } // headlightOff void high() { ledValue = INDICATORHIGHBEAM; // when the light is ON, it will have this brightness ledState = 1; output(); } // high void low() { ledValue = lowValue; // when the light is ON, it will have this brightness ledState = 1; output(); } // low bool isFlashing() { return ledFlash == 1; } // isFlashing bool stopFlashing() { ledFlash = 0; if ( lightsOn == 1 ) ledValue = 10; else ledValue = 0; } // stopFlashing void update() { _now = millis(); if ( ledFlash > 0 ) { if ( ( _now - _flashbefore ) > (unsigned long)TURNBLINKRATE ) { _flashbefore = _now; if ( ledValue > 127 ) ledValue = lowValue; else ledValue = 200; } // if time to change state } // if flashing if ( ( _now - _before ) > (unsigned long)TURNUPDATE ) { _before = _now; if ( ledState == 0 ) { // if off digitalWrite( ledPin, LOW ); } else { // you are on if ( ledValue > 127 ) digitalWrite( ledPin, HIGH ); else { if ( lightsOn == 1 ) { count++; if ( count >= 6 ) count = 0; switch (count) { case 0: case 1: digitalWrite( ledPin, LOW ); break; case 2: digitalWrite( ledPin, HIGH ); break; case 3: case 4: digitalWrite( ledPin, LOW ); break; case 5: digitalWrite( ledPin, HIGH ); break; default: break; } // switch } else { digitalWrite( ledPin, LOW ); } // if else } // if else } // if else } // if } // update}; // class RunningTurnSignalManualPWM////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////class Hazards { // this toggle two indicators on and off // Class Member Variables RunningTurnSignalManualPWM *left; RunningTurnSignalManualPWM *rite; int ledState; // 0==off, 1==on int enabled; // 0==off, 1==on unsigned long _now; unsigned long _before; unsigned long _flashbefore; void output() { if ( left == NULL ) return; if ( DEBUG2 ) Serial.println( "haz out" ); if ( ledState == 1 ) { if ( DEBUG2 ) Serial.println( "haz on" ); left->fullOn(); rite->fullOn(); } else { if ( DEBUG2 ) Serial.println( "haz off" ); left->powerOff(); rite->powerOff(); } // if } // outputpublic: // Constructor - creates a Hazards // and initializes the member variables and state Hazards( int ena ) { left = NULL; rite = NULL; enabled = ena; ledState = 0; // off } // Constructor Hazards( RunningTurnSignalManualPWM, RunningTurnSignalManualPWM ) void setupLites(RunningTurnSignalManualPWM *l, RunningTurnSignalManualPWM *r ) { left = l; rite = r; } // setup( RunningTurnSignalManualPWM *, RunningTurnSignalManualPWM * ) bool isEnabled() { return enabled == 1; } // bool isEnabled void togglePower() { if ( enabled == 0 ) enabled = 1; else { enabled = 0; ledState = 0; } // else output(); } // togglePower void toggleState() { if ( ledState == 0 ) ledState = 1; else ledState = 0; output(); } // toggleState void powerOn() { enabled = 1; ledState = 1; output(); } // powerOn void powerOff() { enabled = 0; ledState = 0; output(); } // powerOff void update() { _now = millis(); if ( enabled > 0 ) { if ( ( _now - _flashbefore ) > (unsigned long)HAZARDBLINKRATE ) { _flashbefore = _now; toggleState(); } // if time } // if on } // update}; // class Hazards////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////class HeadLight { // this is on or off, low or high beam on PWM pin // Class Member Variables // These are initialized at startup int ledPin; // the number of the LED pin int ledState; // 0==off, 1==on int ledValue; // 0 through 255 int lowBeamValue; void output() { if ( ledState > 0 ) analogWrite( ledPin, ledValue ); else analogWrite( ledPin, 0 ); } // outputpublic: // Constructor - creates a Flasher // and initializes the member variables and state HeadLight( int pin, int beamVal ) { ledPin = pin; lowBeamValue = beamVal; ledValue = lowBeamValue; ledState = 0; } // Constructor HeadLight( int, int ) void setupPin() { pinMode( ledPin, OUTPUT ); } // setupPin void togglePower() { if ( ledState == 0 ) ledState = 1; else ledState = 0; output(); } // togglePower void toggleFullPower() { if ( ledState == 0 ) { ledState = 1; ledValue = HIBEAM; } else ledState = 0; output(); } // toggleFullPower void powerOn() { ledState = 1; output(); } // powerOn void powerOff() { ledState = 0; output(); } // powerOff void toggleBeam() { if ( ledValue == lowBeamValue ) ledValue = HIBEAM; else ledValue = lowBeamValue; output(); } // toggleBeam void high() { ledValue = HIBEAM; // when the light is ON, it will have this brightness ledState = 2; output(); } // high void low() { ledValue = lowBeamValue; // when the light is ON, it will have this brightness ledState = 1; output(); } // low bool isLow() { return ( ( ledValue == lowBeamValue ) && ( ledState == 1 ) ); } // isLow bool isOn() { return ledState == 1; } // isOn}; // class HeadLight
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////class Light { // this is on or off // Class Member Variables // These are initialized at startup int ledPin; // the number of the LED pin int ledState; // 0==off, 1==on void output() { digitalWrite( ledPin, ledState ); } // outputpublic: // Constructor - creates a Light // and initializes the member variables and state Light( int pin ) { ledPin = pin; ledState = 0; } // Constructor HeadLight( int, int ) void setupPin() { pinMode( ledPin, OUTPUT ); } // setupPin void togglePower() { if ( ledState == 0 ) ledState = 1; else ledState = 0; output(); } // togglePower void powerOn() { ledState = 1; output(); } // powerOn void powerOff() { ledState = 0; output(); } // powerOff bool isOn() { return ledState == 1; } // isOn}; // class Light////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////Light clearance( CLEARANCEPIN );HeadLight headlite( HEADLIGHTPIN, HEADLIGHTLOWBEAM );HeadLight taillite( TAILBRAKEPIN, TAILLIGHTLOWBEAM );RunningTurnSignalManualPWM leftlite( LTURNPIN );RunningTurnSignalManualPWM ritelite( RTURNPIN );Motor motor( MOTORPIN );Hazards hazards( 0 );IRrecv irrecv( IRPIN ); // Receive on IRPIN (like 11)decode_results results;void setup() { pinMode( DEBUGLEDPIN, OUTPUT ); irrecv.enableIRIn(); // Start the receiver (this kills pin 3 PWM!) Serial.begin( 115200 ); leftlite.setupPin(); ritelite.setupPin(); motor.setupPin(); clearance.setupPin(); headlite.setupPin(); taillite.setupPin(); hazards.setupLites( &leftlite, &ritelite ); Serial.println( VERSIONSTRING );} // setup//// loop only updates the indicator lights and act on a command if sent by IR//void loop() { if ( hazards.isEnabled() ) { hazards.update(); } else { leftlite.update(); ritelite.update(); } // if if ( irrecv.decode( &results ) ) { digitalWrite( DEBUGLEDPIN, HIGH ); if ( DEBUG ) Serial.println( results.value, HEX ); switch ( results.value ) { // power off will be code WHICH IS THE POWER BUTTON case REMOTE_POWER: if ( DEBUG ) Serial.println( "Turn off WHAT???" ); motor.powerOff(); // Motor off leftlite.powerOff(); // Left turn signal off ritelite.powerOff(); // Right turn signal off headlite.powerOff(); // Headlight off leftlite.headlightOff(); // Left turn signal ritelite.headlightOff(); // Right turn signal taillite.powerOff(); // Taillight off clearance.powerOff(); // Clearance off hazards.powerOff(); // Hazards off break; case REMOTE_MUTE: if ( DEBUG ) Serial.println( "Motor Mute" ); motor.powerOff(); break; case REMOTE_0: if ( DEBUG ) Serial.println( "Heads" ); headlite.togglePower(); // Headlight on-off clearance.togglePower(); if ( headlite.isOn() ) { leftlite.headlightOn(); //leftlite.powerOn(); // Left turn signal ritelite.headlightOn(); //ritelite.powerOn(); // Right turn signal if ( !taillite.isOn() ) taillite.low(); } else { if ( taillite.isLow() ) taillite.powerOff(); leftlite.headlightOff(); // Left turn signal //leftlite.powerOff(); // Left turn signal off ritelite.headlightOff(); // Right turn signal //ritelite.powerOff(); // Right turn signal off } // if break; case REMOTE_1: if ( DEBUG ) Serial.println( "Remote 1" ); break; case REMOTE_2: if ( DEBUG ) Serial.println( "HI-BEAM" ); headlite.toggleBeam(); // Headlight high-low break; case REMOTE_3: if ( DEBUG ) Serial.println( "Hazards" ); hazards.togglePower(); if ( !hazards.isEnabled() && headlite.isOn() ) { leftlite.headlightOn(); ritelite.headlightOn(); } // if break; case REMOTE_4: if ( DEBUG ) Serial.println( "LEFT" ); if ( hazards.isEnabled() ) { if ( DEBUG ) Serial.println( "Haz still on" ); break; // no action whan hazards are on } // if leftlite.toggleFlash(); // Left turn signal if ( leftlite.isFlashing() ) { ritelite.stopFlashing(); } // if break; case REMOTE_5: if ( DEBUG ) Serial.println( "Remote 5" ); break; case REMOTE_6: if ( DEBUG ) Serial.println( "RIGHT" ); if ( hazards.isEnabled() ) { if ( DEBUG ) Serial.println( "Haz still on" ); break; // no action whan hazards are on } // if ritelite.toggleFlash(); // Right turn signal if ( ritelite.isFlashing() ) { leftlite.stopFlashing(); } // if break; case REMOTE_7: if ( DEBUG ) Serial.println( "Remote 7" ); break; case REMOTE_8: if ( DEBUG ) Serial.println( "Brakes" ); if ( headlite.isOn() ) taillite.toggleBeam(); else taillite.toggleFullPower(); if ( DEBUG ) Serial.println( "Tail light" ); break; case REMOTE_9: if ( DEBUG ) Serial.println( "Remote 9" ); break; case REMOTE_DNARR: if ( DEBUG ) Serial.println( "SPEED1/2" ); motor.midSpeed(); break; case REMOTE_UPARR: if ( DEBUG ) Serial.println( "SPEED!!" ); motor.fullSpeed(); break; case REMOTE_VOLUP: if ( DEBUG ) Serial.println( "SPEED++" ); motor.increaseSpeed(); break; case REMOTE_VOLDN: if ( DEBUG ) Serial.println( "SPEED--" ); motor.decreaseSpeed(); break; default: if ( DEBUG ) Serial.println( "Unknown" ); break; } // switch irrecv.resume(); // Continue receiving digitalWrite( DEBUGLEDPIN, LOW ); } // if} // loop//======================================== END OF CODE ==================================//
You can of course put the classes in their own files to use something like #include <motor.h> which is the whole idea behind reusing code written in C++. But for now, a single file, attached below, keeps it all together.
Enjoy!