Lesson 97-2: Controlling a Servo Motor Using a Rotary Encoder
In this tutorial, we will learn how to control the position of a servo motor using a rotary encoder. This setup will allow us to detect both the rotation of the encoder as well as when the switch is pushed, providing a practical way to manipulate the servo's position. Additionally, we will display the current angle of the servo on an LCD screen, enhancing user feedback and interaction.
Throughout this guide, we will be using an Arduino board along with a rotary encoder and a servo motor. The rotary encoder will provide continuous rotation, allowing for precise control over the servo's position without the limitations of a potentiometer. This is particularly useful in applications where durability and longevity are required since rotary encoders can withstand many more cycles than traditional potentiometers.
For further clarification on the setup and programming, be sure to check the associated video at (in video at 00:00).
Hardware Explained
The primary components in this project include a rotary encoder, a servo motor, and an LCD display. The rotary encoder detects the direction and amount of rotation, sending this information to the Arduino. It typically has three pins: two for rotation detection (often labeled as A and B) and one for a push-button switch.
The servo motor receives signals from the Arduino to adjust its position based on the encoder's input. The LCD display provides visual feedback, showing the current angle of the servo. Each component plays a crucial role in ensuring the system works smoothly and accurately.
Datasheet Details
| Manufacturer | Various |
|---|---|
| Part number | Rotary Encoder |
| Logic/IO voltage | 3.3 V / 5 V |
| Supply voltage | 5 V |
| Output current (per channel) | … |
| Peak current (per channel) | … |
| PWM frequency guidance | … |
| Input logic thresholds | 0.3 * Vcc to 0.7 * Vcc |
| Voltage drop / RDS(on) / saturation | … |
| Thermal limits | … |
| Package | … |
| Notes / variants | … |
- Ensure proper voltage levels (3.3 V for the encoder, 5 V for the servo).
- Use pull-up resistors for the encoder switch if necessary.
- Be cautious of the power supply to avoid overloading the Arduino.
- Test connections before powering up to prevent damage.
- Keep wires organized to avoid confusion and potential shorts.
Wiring Instructions
Begin by connecting the power and ground for all components. Connect the ground from your Arduino to the negative rail of your breadboard. Then, connect a power supply of 3.3 V to the positive rail for the rotary encoder and 5 V for the servo and LCD.
Next, wire the rotary encoder: connect pin A to digital pin 2 on the Arduino and pin B to digital pin 3. Connect the switch pin to digital pin 4. Make sure to connect the ground pin of the encoder to the common ground.
For the servo motor, connect the signal wire (usually yellow or orange) to digital pin 9, the ground wire to the common ground, and the power wire (red) to the 5 V supply. Finally, connect the LCD to the Arduino, ensuring the SDA and SCL pins are connected to A4 and A5 respectively.
Code Examples & Walkthrough
Let’s take a look at some key identifiers and code snippets used in the project. The first part of the code initializes the pins for the rotary encoder and the switch:
const int SW_PIN = 4;
const int PIN_A = 2;
const int PIN_B = 3;
Here, SW_PIN is assigned to the switch, while PIN_A and PIN_B are used for the encoder's rotation detection. This setup allows the Arduino to read the encoder's position and the state of the switch.
Next, the setup function initializes the serial communication:
void setup() {
Serial.begin(9600);
pinMode(SW_PIN, INPUT);
Serial.println("Basic Encoder Test:");
}
The Serial.begin(9600) command sets up the serial monitor for output, and pinMode(SW_PIN, INPUT) configures the switch pin as an input.
In the loop function, we read the encoder's position and check if the switch is pressed:
void loop() {
long newPosition = myEnc.read();
if (newPosition != oldPosition) {
oldPosition = newPosition;
Serial.println(newPosition);
}
if (digitalRead(SW_PIN) == LOW) {
Serial.println("Switch Pressed");
}
delay(200);
}
Here, myEnc.read() retrieves the current position of the encoder, and if it differs from the last recorded position, it updates and prints the new value. The switch state is checked, and if pressed, it outputs "Switch Pressed" to the serial monitor.
For further details and the complete code, please refer to the full program loaded below the article.
Demonstration / What to Expect
Once the wiring is complete and the code is uploaded, you should be able to rotate the encoder and see the position change in the serial monitor. If you press the switch, it should display "Switch Pressed". Ensure the servo responds correctly to the encoder's position changes without any unexpected behavior, such as reversing direction or not moving at all (in video at 12:30).
Common pitfalls include incorrect wiring, such as connecting the encoder to the wrong pins, or not providing adequate power to the servo. Be sure to double-check connections and test the setup incrementally.
Video Timestamps
- 00:00 Introduction
- 01:29 Project is explained
- 03:04 Wiring Diagram and Wiring Explained
- 5:33 wiring diagram
- 10:36 Library Basic encoder Code Explained
- 14:13 Demo: Basic Encoder
- 15:21 Code: Encoder with switch explained
- 16:44 Demo: Encoder with switch
- 17:44 Code: Encoder with Servo and LCD
- 27:25 Demo: Encoder with Servo and LCD
/*
* Lesson 97-2: Controlling Servo Motor using Rotary Encoder
*
* Watch full details video: https://youtu.be/6xVLbNlmK-g
This video is part of the Arduino Step by Step Course, which starts here: https://youtu.be/-6qSrDUA5a8
If you found this tutorial helpful, please support me so I can continue creating
content like this. Make a donation using PayPal or a credit card: https://bit.ly/donate-robojax
* This code is "AS IS" without warranty or liability. Free to be used as long as you keep this note intact.*
* This code has been downloaded from Robojax.com
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
* Updated by Ahmad Shamshiri on Jan 23, 2022
* Encoder Library - Basic Example
* http://www.pjrc.com/teensy/td_libs_Encoder.html
*
* This example code is in the public domain.
*/
const int SW_PIN = 4;
const int PIN_A =2;
const int PIN_B =3;
#include <Encoder.h>
// Change these two numbers to the pins connected to your encoder.
// Best Performance: both pins have interrupt capability
// Good Performance: only the first pin has interrupt capability
// Low Performance: neither pin has interrupt capability
Encoder myEnc(PIN_A, PIN_B);
// avoid using pins with LEDs attached
const int homePosition = 90; //initial position
const int stepValue = 5;
const int servoPin = 9;//must be a pin that that is labeled with ~
#include <Servo.h>
Servo myservo; // create servo object to control a servo
int servoAngle =homePosition;
void setup() {
Serial.begin(9600);
pinMode(SW_PIN, INPUT);
Serial.println("Basic Encoder Test:");
myservo.attach(servoPin); // attaches the servo on pin
myservo.write(servoAngle);//move servo to initial position
}
long oldPosition = -999;
void loop() {
long newPosition = myEnc.read();
if (newPosition != oldPosition) {
if(newPosition > oldPosition)
{
int newStep = abs(newPosition - oldPosition);
Serial.print("Angle ");
Serial.println(servoAngle);
servoAngle -= stepValue;
if(servoAngle <0)
servoAngle =0;
myservo.write(servoAngle);
}
if(newPosition < oldPosition )
{
int newStep = abs(newPosition - oldPosition);
Serial.print("Angle ");
Serial.println(servoAngle);
servoAngle += stepValue;
if(servoAngle >180)
servoAngle =180;
myservo.write(servoAngle);
}
oldPosition = newPosition;//remember the new position
}
if( digitalRead(SW_PIN) == LOW)
{
Serial.print("Home: ");
Serial.println(homePosition);
servoAngle =homePosition;
myservo.write(servoAngle);
}
//Watch full details video: https://youtu.be/6xVLbNlmK-g
//delay(200);
}
Things you might need
-
Amazon
-
Amazon
-
Amazon
-
eBay
-
eBay
-
AliExpressPurchase an LCD1602 from AliExpresss.click.aliexpress.com
Resources & references
-
ExternalPurchase an LCD1602 from AliExpresss.click.aliexpress.com
-
External
-
External
-
ExternalPurchase ZK-5DA from Amazon UKamzn.to
Files📁
No files available.