IR Remote & Servo Motor

Hi all,

Having issues making a servo motor work with the press of a button, the sweep example works fine so I know it's not the servo and I can receive LED feedback using the remote.

The code I currently have is one found online but it's not exactly what I want as I would prefer that when the 0xBA45FF00 button is pressed (IR receiver on pin 2), I want the servo (pin 3) to rotate 100 degrees anti-clockwise, wait 3 seconds and then return to it's default state which I assume would be 0 and stay at this until the same button is pressed again and the sequence repeats.

I have been trying to figure this out for days and I'm not getting anywhere. Any help would be appreciated.

#include <IRremote.hpp>
#include <Servo.h> 

const byte RECV_PIN = 2;

IRrecv irrecv(RECV_PIN);
Servo myservo; 

int pos = 0;    // variable to store the servo position

byte position = 90; // range 0-180
boolean newIRdata = false;
unsigned long IRinput;

decode_results results;

void setup()
{
  Serial.begin(115200);
  myservo.attach(3);
  irrecv.enableIRIn(); // Start the receiver
}

void loop() {
  if (irrecv.decode(&results))
  {
    IRinput = results.value;
    irrecv.resume(); // Receive the next value
    newIRdata = true;
  }
  if(newIRdata == true)
  {
   Serial.println(IRinput, HEX);
      switch(IRinput)
    {
     // go to 200
     case(0xBA45FF00): // off button
     position = 160;
     Serial.println(position);
     break;
     // go to 70
     case(0xB847FF00): // mute button
     position = 75;
     Serial.println(position);
     break;     
    }
     IRinput = 0;
     newIRdata = false;   
  }
  myservo.write(position);
}

you have 4 simple states your system can be into:

  • waiting for a IR command (0xBA45FF00)
  • moving to 100° (it's quite fast with a servo)
  • resting for 3 seconds
  • returning to 0° (it's quite fast too)

The events you need to deal with are obviously the IR code when you are waiting for the command and then just time passing using millis.

This could be either a very sequential code (in pseudo code)

void loop() {
  if (IR signal received) {
    move servo to 100°
    delay 3000ms
    move servo to 0°    
  }
}

or if you want non blocking code (so that you could still do other stuff while waiting for 3s) you might benefit from studying state machines. Here is a small introduction to the topic: Yet another Finite State Machine introduction

Thank you for your reply. I don't need to do other stuff while waiting for the 3s, so the first code seems to be the answer. I am however confused where this fits in with the code in my first post as I can't get that to work at all at the moment.

well - this is the part where you test if an IR signal was received

and this would be the comparison with 0xBA45FF00

if (results.value == 0xBA45FF00) {
  ...
}

so something like this (typed here, fully untested)

void loop() {
  if (irrecv.decode(&results)) {        // we got a command
    if (results.value == 0xBA45FF00) {  // is it the one expected?
      // if yes, perform the expected movement (blocking code, nothing else happens while you are there)
      myservo.write(100);
      delay(3000);
      myservo.write(0);
    }
    irrecv.resume(); // get ready to receive the next IR value
  }
}

Thank you, I've tried adding this on my code but receive the error below, code also below this.

In the serial monitor, it shows that 0xBA45FF00 has been pressed, however the servo doesn't move.

/var/folders/f6/ct6b76g97k1bppnhsz9zgchh0000gn/T//ccIxYInn.ltrans0.ltrans.o: In function `loop':
/private/var/folders/f6/ct6b76g97k1bppnhsz9zgchh0000gn/T/.arduinoIDE-unsaved2024822-31589-2qzgwy.t4y6w/sketch_sep22a/sketch_sep22a.ino:24: undefined reference to `IRrecv::decode(decode_results*)'
collect2: error: ld returned 1 exit status
Multiple libraries were found for "Servo.h"
  Used: /Users/*****/Documents/Arduino/libraries/Servo
  Not used: /Users/*****/Library/Arduino15/libraries/Servo
exit status 1

Compilation error: exit status 1
#include <IRremote.hpp>
#include <Servo.h> 

const byte RECV_PIN = 2;

IRrecv irrecv(RECV_PIN);
Servo myservo; 

int pos = 0;    // variable to store the servo position

byte position = 90; // range 0-180
boolean newIRdata = false;
unsigned long IRinput;

decode_results results;

void setup()
{
  Serial.begin(115200);
  myservo.attach(3);
  irrecv.enableIRIn(); // Start the receiver
}

void loop() {
  if (irrecv.decode(&results)) {        // we got a command
    if (results.value == 0xBA45FF00) {  // is it the one expected?
      // if yes, perform the expected movement (blocking code, nothing else happens while you are there)
      myservo.write(100);
      delay(3000);
      myservo.write(0);
    }
    irrecv.resume(); // get ready to receive the next IR value
  }
}

I changed the top of the code to the below and the error doesn't show, however still no luck moving the servo. When I upload, I can hear the servo 'ticking' and once I hit the button, it stops the tick but still no movement.

It says this in the serial monitor:

It seems, that you are using a old version 2.0 code / example.

This version is no longer supported!

#include <IRremote.h>
#include <Servo.h>

const byte RECV_PIN = 2;

IRrecv irrecv(RECV_PIN);
Servo myservo;

int pos = 0;  // variable to store the servo position

byte position = 90;  // range 0-180
boolean newIRdata = false;
unsigned long IRinput;

decode_results results;

void setup() {
  Serial.begin(115200);
  myservo.attach(3);
  irrecv.enableIRIn();  // Start the receiver
}

void loop() {
  if (irrecv.decode(&results)) {        // we got a command
    if (results.value == 0xBA45FF00) {  // is it the one expected?
      // if yes, perform the expected movement (blocking code, nothing else happens while you are there)
      myservo.write(100);
      delay(3000);
      myservo.write(0);
    }
    irrecv.resume();  // get ready to receive the next IR value
  }
}

The IDE complains you've installed the Servo library multiple times. get rid of one


Otherwise the code structure you use is for an outdated version of the library

see their documentation Converting your 2.x program to the 4.x version

here is an example

compile the code and launch the simulation and then when you press the power button, it will launch the servo animation

click to see the code
/* ============================================
  code is placed under the MIT license
  Copyright (c) 2024 J-M-L
  For the Arduino Forum : https://forum.arduino.cc/u/j-m-l

  Permission is hereby granted, free of charge, to any person obtaining a copy
  of this software and associated documentation files (the "Software"), to deal
  in the Software without restriction, including without limitation the rights
  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  copies of the Software, and to permit persons to whom the Software is
  furnished to do so, subject to the following conditions:

  The above copyright notice and this permission notice shall be included in
  all copies or substantial portions of the Software.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  THE SOFTWARE.
  ===============================================
*/

#include <IRremote.hpp>
#include <Servo.h>

const byte  IR_RECEIVE_PIN = 2;
const byte SERVO_PIN = 3;

Servo servo;

void doNothing() {}

void animation() {
  Serial.println(F("MOVING TO 100°"));
  servo.write(100);
  Serial.println(F("WAITING FOR 3s"));
  delay(3000);
  Serial.println(F("MOVING TO 0°"));
  servo.write(0);
  Serial.println(F("DONE"));
}

void handleCommand() {
  if (IrReceiver.decode()) {
    switch (IrReceiver.decodedIRData.command) {
      case 162: Serial.println("POWER ➜ ANIMATION"); animation(); break;
      case 226: Serial.println("MENU"); doNothing(); break;
      case 34:  Serial.println("TEST"); doNothing(); break;
      case 2:   Serial.println("PLUS"); doNothing(); break;
      case 194: Serial.println("BACK"); doNothing(); break;
      case 224: Serial.println("PREV"); doNothing(); break;
      case 168: Serial.println("PLAY"); doNothing(); break;
      case 144: Serial.println("NEXT");  doNothing(); break;
      case 104: Serial.println("num: 0"); doNothing(); break;
      case 152: Serial.println("MINUS"); doNothing(); break;
      case 176: Serial.println("key: C"); doNothing(); break;
      case 48:  Serial.println("num: 1"); doNothing(); break;
      case 24:  Serial.println("num: 2"); doNothing(); break;
      case 122: Serial.println("num: 3"); doNothing(); break;
      case 16:  Serial.println("num: 4"); doNothing(); break;
      case 56:  Serial.println("num: 5"); doNothing(); break;
      case 90:  Serial.println("num: 6"); doNothing(); break;
      case 66:  Serial.println("num: 7"); doNothing(); break;
      case 74:  Serial.println("num: 8"); doNothing(); break;
      case 82:  Serial.println("num: 9"); doNothing(); break;
      default: break;
    }
    IrReceiver.resume();
  }
}


void setup() {
  Serial.begin(115200);
  servo.write(0);
  servo.attach(SERVO_PIN);
  IrReceiver.begin(IR_RECEIVE_PIN);
  Serial.println(F("PRESS THE POWER BUTTON TO LAUNCH THE SERVO ANIMATION"));
}

void loop() {
  handleCommand();
}

you'll have to adjust the command codes for your remote.

I've given this code a go on the simulator and it works perfectly, but still no luck with my setup after changing the command code. I can't figure out where this is going wrong.

The servo still makes the clicking sound after I upload to the board.

how do you power the servo?
can you show the circuit?

External power, circuit below. Only thing that's changed is the servo is on pin 3 and the ir receiver on pin 2 on the physical circuit.

0 is all the way to one end of servo travel. 180 is all the way to the other. 90 is the midpoint and closest to default, or starting position, which corresponds roughly to 1500 microseconds on a typical servo

You ought not draw that high a current through a breadboard (servos draw potentially more than the traces can tolerate)

Frustratingly the servo doesn't move at all though, only when I use the sweep example.

I do plan on moving the circuit to a protoboard eventually, but want to get it working on the breadboard first.

I'd try moving irrecv.resume(); // get ready to receive the next IR value one curly brace lower.

Still the same outcome unfortunately.

Is there any reason the servo is making a clicking sound as soon as the code gets uploaded?

Do you have both the USB and the jack power plugged in and building the Servo's power from the Arduino ?

image

what's the voltage on the jack ?

Yeah at the moment both are plugged in as I'm forever uploading edited code trying to get it work. :sweat_smile:

How would I work out the voltage on the jack? The power adaptor is the one below if that helps, could this be a problem then? The sweep example code works with no issue as does the IR decoding, just can't seem to get them to function together.

Is this "Servo.h" the version which once used the return "&result" but now uses "result"?

Sorry I'm not sure what you mean?