Servo
August 3, 2018
The objective is to control a servo motor using an infrared controller.
It is based on Controlling a Servo with IR and How to Set Up an IR Remote and Receiver on an Arduino.
Phases
-
Decode the controller: obtain the code corresponding to each of the buttons so that the microcontroller knows which one is being pressed.
-
Send instructions to the servo, depending on which button is pressed:
- Adjust the speed at which the motor will move.
- Make the motor rotate to positions previously defined.
The work presented will not bring any major difficulties, as both the assembly and the code are easy to follow. Perhaps the decoding part is the most laborious, as we have to register about 28 codes (depending on the controller), which can become repetitive.
Material
- Servo motor
- Remote controller
- IR receiver
- Microcontroller (used: Arduino Uno)
- Breadboard (mini is enough)
- Jumper Wires
Remote Decoding
Start by decoding the remote controller buttons. Each remote has a different set of codes. I used the remote below.
Assembly
Download the Fritzing assembly sketch: 💾
Be careful about the receiver pin, they change depending on its model:
Code
Below is the code used in the decoding phase. Install the IRremote library before compiling.
/* Adapted from Examples -> IRremote -> IRrecvDemo
by josegneto.github.io */
#include <IRremote.h>
const int RECV_PIN = 7; // Receiver Pin
IRrecv irrecv(RECV_PIN);
decode_results results;
void setup()
{
Serial.begin(9600);
irrecv.enableIRIn();
irrecv.blink13(true);
}
void loop()
{
if (irrecv.decode(&results))
{
Serial.println(results.value, HEX);
// Prints the HEX code in the Serial Monitor
irrecv.resume();
}
}
Interpretation of the results
When a button is pressed, the correspoding HEX code is printed in the IDE’s Serial Monitor. In the example below, buttons 1-4 were pressed.
The following table shows the codes for each of the buttons:
Botão |
Código |
Botão |
Código |
Botão |
Código |
CH- |
0x1FE48B7 |
CH |
0x1FE58A7 |
CH+ |
0x1FE7887 |
⏪ |
0x1FE807F |
⏩ |
0x1FE40BF |
⏯️ |
0x1FEC03F |
Vol - |
0x1FE20DF |
Vol + |
0x1FEA05F |
EQ |
0x1FE609F |
0 |
0x1FEE01F |
100+ |
0x1FE10EF |
200+ |
0x1FE906F |
1 |
0x1FE50AF |
2 |
0x1FED827 |
3 |
0x1FEF807 |
4 |
0x1FE30CF |
5 |
0x1FEB04F |
6 |
0x1FE708F |
7 |
0x1FE00FF |
8 |
0x1FEF00F |
9 |
0x1FE9867 |
The process is similar with any other controller. I tried it with the TV controller and the result was similar, only the button codes are different (as expected).
The difference between controllers appears in the next step, as there are different protocols depending on their manufacturer. The most common protocol in remotes that come with Arduino beginner kits is NEC, while the TV remote I tried uses SAMSUNG.
Controlling the servo
The next step is to give commands to the servo: rotate certain degrees, defined by the user, or permanently rotate at a speed (number of degrees) indicated by us.
For this, we have to adapt the previous assembly to accommodate the servo and give it instructions.
Assembly
Download the Fritzing assembly sketch: 💾
If the image is not clear, the assembling is identical to the previous one.
We just need to connect the servo. Mine has three cables: brown, red and orange. Brown must be connected to GND (Ground), red to VCC (+5V) and orange to pin (9) defined further down in the code.
Code
Below is the code used in the servo controlling phase. Install the IRLib2 library before compiling.
/* Adapted from Examples -> IRLib2 -> servo
by josegneto.github.io */
#include <IRLibAll.h>
#include <Servo.h>
// You will have to set these values depending on the protocol
// and remote codes that you are using
#define MY_PROTOCOL NEC
#define CH- 0x1FE48B7
#define CH 0x1FE58A7
#define CH+ 0x1FE7887
#define FAST_BACKWARD 0x1FE807F // Move the servo counterclockwise
#define FAST_FORWARD 0x1FE40BF // Move the servo clockwise
#define PLAY_PAUSE 0x1FEC03F // Center the servo
#define VOLDEC 0x1FE20DF // Decrease the speed
#define VOLINC 0x1FEA05F // Increase the speed
#define EQ 0x1FE609F
#define BUTTON_0 0x1FEE01F // Rotates key * 20 degrees at a time
#define BUTTON_1 0x1FE50AF // User defined position
#define BUTTON_2 0x1FED827
#define BUTTON_3 0x1FEF807
#define BUTTON_4 0x1FE30CF
#define BUTTON_5 0x1FEB04F
#define BUTTON_6 0x1FE708F
#define BUTTON_7 0x1FE00FF
#define BUTTON_8 0x1FEF00F
#define BUTTON_9 0x1FE9867
IRrecv myReceiver(11); // Receiver pin
IRdecode myDecoder;
Servo myServo; // Create servo object to control a servo
int16_t pos; // Variable to store the servo position
int16_t Speed; // Degrees to move when a left/right button is pressed
uint32_t Previous; // Handles NEC repeat codes
void setup()
{
myServo.attach(9); // Attaches the servo on pin 9 to its object
pos = 90; // Start at midpoint 90 degrees
Speed = 3; // Moves 3 degrees when left/right is pushed
myServo.write(pos); // Set initial position
myReceiver.enableIRIn(); // Start the receiver
}
void loop()
{
if (myReceiver.getResults()) {
myDecoder.decode();
if(myDecoder.protocolNum==MY_PROTOCOL) {
if(myDecoder.value==0xFFFFFFFF)
myDecoder.value=Previous;
switch(myDecoder.value) {
case FAST_BACKWARD: pos=min(180,pos+Speed); break;
case FAST_FORWARD: pos=max(0,pos-Speed); break;
case PLAY_PAUSE: pos=90; break;
case VOLDEC: Speed=min(10, Speed+1); break;
case VOLINC: Speed=max(1, Speed-1); break;
case BUTTON_0: pos=0*20; break;
case BUTTON_1: pos=1*20; break;
case BUTTON_2: pos=2*20; break;
case BUTTON_3: pos=3*20; break;
case BUTTON_4: pos=4*20; break;
case BUTTON_5: pos=5*20; break;
case BUTTON_6: pos=6*20; break;
case BUTTON_7: pos=7*20; break;
case BUTTON_8: pos=8*20; break;
case BUTTON_9: pos=9*20; break;
}
myServo.write(pos); // Servo goes to position in variable 'pos'
Previous=myDecoder.value;
}
myReceiver.enableIRIn();
}
}
Demo
In the demonstration below the servo is moving when the buttons ⏪ and ⏩ are pressed.