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   1000

IRrecv irrecv( 11 ); // Receive on pin 11

decode_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");
} // setup

void 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 );  } // output public:  // 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  } // output public:  // 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 );    } // output public:  // 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 );     } // output public:  // 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!

Ċ
Gert (TxAdmin) Muller,
Oct 2, 2016, 8:01 PM
ċ
TxCar005_20160811.ino
(22k)
Gert (TxAdmin) Muller,
Aug 11, 2016, 7:57 PM
ċ
TxCarIR002.ino
(1k)
Gert (TxAdmin) Muller,
May 11, 2016, 9:39 PM
Comments