How to Control a Servo Motor Using Arduino

Motors are what enable robots to move and do things. Without motors, robots are just big pieces of metal and plastic that can’t move.

The simplest type of motor is the direct current (DC) motor. This type of motor spins around and around in one direction, rotating 360 degrees. It only stops rotating when it is disconnected from a power source. DC motors are common in wheeled robots.

Another type of motor is known as the servo motor (“servo”). Instead of rotating continuously for 360 degrees in one direction, servo motors move to specific angles, typically anything between 0 and 180 degrees. Servo motors are common in robotics. You will see them in all types of applications where a motor needs to move a part of the robot to a specific position. Examples include robot arms, hands, legs, and humanoid robots. NASA’s Robonaut 2, for example, has a total of 54 servo motors which are used to move the robot’s joints, head, and other body parts.

In this post, I will explain how servos work, and then we will get our hands dirty by powering up our Arduino and using it to control a servo.

How Servos Work

Servos work by receiving electrical signals. The length of this signal controls the angle the motor turns…the longer the signal, the greater the motor will turn. This process is known as pulse-width-modulation because the width (i.e. duration) of the electrical pulse modulates (modifies) the motor’s angle of rotation. Here is what that looks like:

controlling-a-servo-motor-2

Requirements

Here are the requirements:

  • Control a servo motor’s angle of rotation.

You Will Need

controlling-a-servo-motor-1

The following components are used in this project. You will need:

Directions

Control a Servo Using Arduino’s Power Supply

controlling-a-servo-motor-3

Here is the hardware we need to set up:

servo-motor-arduino

Connect the red wire of the servo to the 5V pin of the Arduino Uno.

Connect the black wire of the servo to the GND (ground) pin of the Arduino Uno.

Connect the yellow control wire of the servo to Digital Pin 9 of the Arduino Uno. This yellow wire is the one that will receive commands from the Arduino. Pin 9 is one of Arduino’s Pulse-Width Modulation pins.

Power up your Arduino by plugging in the USB cord to your computer.

Open the Arduino IDE, and in a new sketch, write the following code:

/* Sweep
 by BARRAGAN <http://barraganstudio.com>
 This example code is in the public domain.

 modified 8 Nov 2013
 by Scott Fitzgerald
 http://www.arduino.cc/en/Tutorial/Sweep
*/

#include <Servo.h>

Servo myservo;  // create servo object to control a servo
// twelve servo objects can be created on most boards

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

void setup() {
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop() {
  for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
    // in steps of 1 degree
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
  for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
    myservo.write(pos);              // tell servo to go to position in variable 'pos'
    delay(15);                       // waits 15ms for the servo to reach the position
  }
}

Upload the code to your board. This code will make the shaft of the motor sweep back and forth 180 degrees.

Control a Servo Using Arduino and a Potentiometer

controlling-a-servo-motor-4

In some applications, we might want to control the angle a servo rotates without having to constantly modify the code. One way to do this is to use a potentiometer. Think of a potentiometer as a variable resistor. By turning the knob, you can control the voltage output of the potentiometer.

In this piece of the project, we will set up software that reads the voltage output of the potentiometer. It then converts that number it into an angle for the servo.

A potentiometer has 3 terminals:

  1. Two outer terminals are used for power: one outer pin connects to ground and the other connects to positive voltage. Potentiometers don’t have polarity, so it doesn’t matter which one is ground and which one is connected to positive voltage.
  2. A central control terminal is used for voltage output: turning the knob of the potentiometer increases or decreases the resistance, which lowers or increases the voltage output.

So let’s set all this up. Here is the schematic diagram:

servo-motor-arduino-potentiometer

With your Arduino unplugged, stick the 10k Ohm potentiometer into the solderless breadboard. Make sure each terminal is connected to separate row in the breadboard.

Connect one of the outer terminals to the blue (ground) rail of the breadboard.

Connect the other outer terminal to the red (positive) rail of the breadboard.

Connect the central pin of the potentiometer to Analog Input pin A0 of the Arduino.

Connect the black and red wires of the servo to the blue and red rail of the breadboard, respectively.

Connect the yellow control wire to pin 9 of the Arduino.

Connect a wire from the +5V pin of the Arduino to the positive red rail of the breadboard.

Connect a wire from Ground (GND) of the Arduino to the blue rail of the breadboard.

This completes the hardware setup.

Plug in the Arduino.

controlling-a-servo-motor-5

Open up the IDE. Inside a new sketch, write the following code:

/*
 Controlling a servo position using a potentiometer (variable resistor)
 by Michal Rinott <http://people.interaction-ivrea.it/m.rinott>

 modified on 8 Nov 2013
 by Scott Fitzgerald
 http://www.arduino.cc/en/Tutorial/Knob
*/

#include <Servo.h>

Servo myservo;  // create servo object to control a servo

int potpin = 0;  // analog pin used to connect the potentiometer
int val;    // variable to read the value from the analog pin

void setup() {
  myservo.attach(9);  // attaches the servo on pin 9 to the servo object
}

void loop() {
  val = analogRead(potpin);            // reads the value of the potentiometer (value between 0 and 1023)
  val = map(val, 0, 1023, 0, 180);     // scale it to use it with the servo (value between 0 and 180)
  myservo.write(val);                  // sets the servo position according to the scaled value
  delay(15);                           // waits for the servo to get there
}

Upload the code to your board.

Turn the knob on your potentiometer to move the servo.

Your Arduino microcontroller is reading the voltage that is coming in from the potentiometer on Analog Input pin 0. It is then converting this voltage into a value between 0 and 180. This degree value then gets sent down the yellow control wire to the servo, and the servo moves accordingly. Thus, the higher the voltage output by the potentiometer, the greater the servo’s angle of rotation.

Control a Servo Using an External Power Supply

controlling-a-servo-motor-6

We don’t always want to use the Arduino to power our servos. Sometimes we might want to use an external power supply. Here is a basic schematic (Note: Ignore the AAA on the batteries below. They are actually AA.):

servo-motor-arduino-external-power

The biggest change from the previous implementation is that now the servos are connected to the 4xAA battery holder instead of the Arduino’s power supply.

With your Arduino powered off, move the red and black wires of the servo to the other red and blue rails of your solderless breadboard.

Connect the red wire of the 4xAA battery holder to the red rail of the solderless breadboard (the one electrically connected to the servo).

Connect the black wire of the 4xAA battery holder to the blue rail of the breadboard.

Make sure your external power supply is connected to the same ground as the Arduino. Use a male-to-male jumper wire to connect both ground rails. This is called common ground.

Power up the Arduino, open the IDE, and find the same sketch as the previous section of this blog post.

Upload the sketch to your Arduino.

Turn the knob of the potentiometer, and watch the servo move.

How to Configure Raspberry Pi to Run Programs On Startup

In this post, I’ll show you how to configure your Raspberry Pi so that your programs can run as soon as you plug in your Raspberry Pi to a power source.

Requirements

Here are the requirements:

  • Run a program as soon as the Raspberry Pi is turned on.

Directions

Power up your Raspberry Pi, and open up a terminal window.

Type:

sudo nano /etc/rc.local

Scroll down the file to the area right after fi but before exit 0. Type:

python3 /home/pi/robot/ball_following_yellow.py &

The format is

python3 /your/file/path/here/filename.py &

Press CTRL-X, and save the file.

Restart your Raspberry Pi.

sudo reboot

Your program, ball_following_yellow.py, should run on startup.

How to Make an Object Tracking Robot Using Raspberry Pi

In this tutorial, I will show you how to give your wheeled robot the ability to follow a colored ball. You will get your first taste of computer vision and image processing.

Special shout out to Matt Timmons-Brown for this project idea. He is the author of a really good book on Raspberry Pi robotics: (Learn Robotics with Raspberry Pi). Go check it out!

Video

Here is a video of what we will build in this tutorial.

Requirements

Here are the requirements:

  • Build a wheeled robot powered by Raspberry Pi that must identify and follow a yellow rubber ball using OpenCV, a library of programming functions for real-time computer vision and image processing.

You Will Need

The following components are used in this project. You will need:

Directions

Connecting the Raspberry Pi Camera Module

Make sure the Raspberry Pi is turned OFF.

Open the Camera Serial Interface on the Raspberry Pi. It is located next to the 3.5mm audio jack. Pull it upwards delicately from either side.

Insert the ribbon of the camera module into the Camera Serial Interface. Make sure the silver contacts face away from the 3.5mm audio jack.

2019-06-03-194539

Hold the ribbon in place while pushing down on the Camera Serial Interface port. Make sure it is closed.

2019-06-03-194547

Mount the camera to the front of the robot.

2019-06-03-200735

Power up Raspberry Pi.

Open up a configuration window:

sudo raspi-config

Interfacing Options –> ENTER –> Camera –> ENTER –> Yes

The camera is enabled.

Now, we need to set the resolution.

Advanced Options –> Resolution –> DMT Mode 82 1920×1080 60Hz 16: 9 –> ENTER –> Finish

Restart the Raspberry Pi by typing the following in a terminal window.

sudo reboot

Testing the Raspberry Pi Camera Module.

We need to take a test photo with our newly installed camera module.

Open a terminal window. Type the following command:

raspistill -o test_photo.jpg

Go to your home directory to see if the test photo is there. Here is the photo that mine took (back of my head).

test-camera

Setting Up Object Tracking

Now, we need to configure our system so the robot can track a yellow rubber ball.

Download the dependencies for OpenCV, a library of programming functions for real-time computer vision and image processing.

Type the following command into a terminal window:

sudo apt-get update
sudo apt-get install libblas-dev libatlas-base-dev libjasper-dev libqtgui4 libqt4-test

Y –> ENTER.

Wait a few moments while everything installs.

Install OpenCV using pip.

sudo pip3 install opencv-python
installing-open-cvPNG

Install the PiCamera library.

sudo apt-get install python3-picamera

Determining the HSV Value of the Yellow Ball

We need to select an appropriate HSV (hue, saturation, value) value for the yellow ball. HSV is an alternative color representation that is frequently used instead of the RGB (Red Green Blue) color model I covered in my light and sound wheeled robot post.

Here is the HSV table.

512px-HSV_color_solid_cylinder_saturation_gray

Since the ball is yellow, I’ll choose 60 as my starting number.

Open IDLE in your Raspberry Pi, and create a new file in your robot directory. Name it color_tester.py.

Here is the code for the program:

# Code source (Matt-Timmons Brown): https://github.com/the-raspberry-pi-guy/raspirobots
# import the necessary packages
from picamera.array import PiRGBArray
from picamera import PiCamera
import time
import cv2
import numpy as np


# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (640, 480)
camera.framerate = 32
rawCapture = PiRGBArray(camera, size=(640, 480))

while True:
	while True:
		try:
			hue_value = int(input("Hue value between 10 and 245: "))
			if (hue_value < 10) or (hue_value > 245):
				raise ValueError
		except ValueError:
			print("That isn't an integer between 10 and 245, try again")
		else:
			break

	lower_red = np.array([hue_value-10,100,100])
	upper_red = np.array([hue_value+10, 255, 255])

	for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
		image = frame.array

		hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

		color_mask = cv2.inRange(hsv, lower_red, upper_red)

		result = cv2.bitwise_and(image, image, mask= color_mask)

		cv2.imshow("Camera Output", image)
		cv2.imshow("HSV", hsv)
		cv2.imshow("Color Mask", color_mask)
		cv2.imshow("Final Result", result)

		rawCapture.truncate(0)

		k = cv2.waitKey(5) #& 0xFF
		if "q" == chr(k & 255):
			break

Place your ball about a yard in front of the camera.

2019-06-03-203156

Run the newly created program.

python3 color_tester.py

Choose 60.

You will see four windows.

  • Window 1. RGB representation
  • Window 2: HSV representation
  • Window 3: Show the portions of the frame that match a hue value of 60.
  • Window 4: Entire frame minus all portions that do NOT have a 60 hue value.
open-cv-robot-yellow-ballPNG

To try a different hue value, select any of the four windows above. Press Q to halt the output of the video.

Go to the terminal window, and try a new hue valve. I’ll try 29 this time. It worked!

You keep trying different numbers until Window 4 shows mostly your ball and nothing else. Be patient and try LOTS of numbers.

try-try-againPNG

Write down the hue value you ended up with on a sheet of paper.

Press CTRL-C in the terminal window to stop running color_tester.py.

Coding the Ball-Following Program

Open IDLE. Create a new file in your robot directory named:

ball_following_yellow. py

Here is the code (Credit to Matt Timmons-Brown, the author of a really good book on Raspberry Pi robotics: (Learn Robotics with Raspberry Pi):

# Code source (Matt-Timmons Brown): https://github.com/the-raspberry-pi-guy/raspirobots
from picamera.array import PiRGBArray
from picamera import PiCamera
import cv2
import numpy as np
import gpiozero

camera = PiCamera()
image_width = 640
image_height = 480
camera.resolution = (image_width, image_height)
camera.framerate = 32
rawCapture = PiRGBArray(camera, size=(image_width, image_height))
center_image_x = image_width / 2
center_image_y = image_height / 2
minimum_area = 250
maximum_area = 100000

robot = gpiozero.Robot(left=(22,27), right=(17,18))
forward_speed = 1.0
turn_speed = 0.8

HUE_VAL = 29

lower_color = np.array([HUE_VAL-10,100,100])
upper_color = np.array([HUE_VAL+10, 255, 255])

for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
	image = frame.array

	hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

	color_mask = cv2.inRange(hsv, lower_color, upper_color)

	image2, countours, hierarchy = cv2.findContours(color_mask, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

	object_area = 0
	object_x = 0
	object_y = 0

	for contour in countours:
		x, y, width, height = cv2.boundingRect(contour)
		found_area = width * height
		center_x = x + (width / 2)
		center_y = y + (height / 2)
		if object_area < found_area:
			object_area = found_area
			object_x = center_x
			object_y = center_y
	if object_area > 0:
		ball_location = [object_area, object_x, object_y]
	else:
		ball_location = None

	if ball_location:
		if (ball_location[0] > minimum_area) and (ball_location[0] < maximum_area):
			if ball_location[1] > (center_image_x + (image_width/3)):
				robot.right(turn_speed)
				print("Turning right")
			elif ball_location[1] < (center_image_x - (image_width/3)):
				robot.left(turn_speed)
				print("Turning left")
			else:
				robot.forward(forward_speed)
				print("Forward")
		elif (ball_location[0] < minimum_area):
			robot.left(turn_speed)
			print("Target isn't large enough, searching")
		else:
			robot.stop()
			print("Target large enough, stopping")
	else:
		robot.left(turn_speed)
		print("Target not found, searching")

	rawCapture.truncate(0)

Running the Ball – Following Program

Place your robot in an open space on the floor with the yellow rubber ball.

Run the program.

python3 ball_following_yellow.py

Whenever you want to stop the program, type CTRL-C.