Using Arduino to Control the Speed and Direction of a Micro Servo Motor

How to Connect a Micro Servo Motor to Arduino / Visits:25

In the vibrant world of electronics and robotics, few components are as simultaneously accessible and powerful as the micro servo motor. These tiny, programmable actuators are the beating heart of countless projects, from animatronic props and robotic arms to camera gimbals and automated plant waterers. Their magic lies in their ability to move to a precise angular position on command. But what if you need more than just position control? What if you want to dictate not just where it points, but how fast and in what direction it sweeps? This is where the synergy of a micro servo and an Arduino microcontroller becomes truly transformative. Let's dive into the practical art of harnessing this duo for complete control over speed and direction.

Why the Micro Servo? Understanding the Core of the Component

Before we write a single line of code, it's crucial to understand what makes a micro servo motor special. Unlike standard DC motors that simply spin when power is applied, a servo is an integrated system. Inside its compact plastic casing, you'll find: * A small DC motor * A gear train to reduce speed and increase torque * A control circuit * A potentiometer attached to the output shaft

This potentiometer is the key. It provides real-time feedback to the control circuit about the shaft's current position. When you send a target position signal, the internal circuit compares it to the current position from the potentiometer and drives the motor in the direction needed to match them. This closed-loop system is why servos are so accurate for positional control.

Key Specifications for Your Project: * Operating Voltage: Typically 4.8V to 6V. Never exceed 7V for most standard micro servos. * Stall Torque: The force it can exert when powered but prevented from moving. Measured in kg-cm or oz-in. Micro servos often range from 1.5 to 3 kg-cm. * Speed: Usually listed as the time to move 60 degrees (e.g., "0.12 sec/60°" at 4.8V). This is a fixed characteristic under load.

The critical takeaway? Standard servo control is about setting a position, not a speed. To control speed, we must think differently.

The Hardware Setup: Building the Foundation

For this guide, we'll use the ubiquitous SG90 micro servo and an Arduino Uno. The principles apply to any standard hobby servo.

What You'll Need

  • Arduino Uno (or Nano, Mega, etc.)
  • SG90 Micro Servo Motor
  • Jumper wires (Male-to-Male)
  • A breadboard (optional, but helpful)
  • USB cable for Arduino
  • External 5V power supply (recommended for more than one servo)

Circuit Connections: Getting Wired Up

The wiring is beautifully simple. A standard 3-wire servo has: 1. Brown or Black Wire: GROUND. Connect this to the Arduino's GND pin. 2. Red Wire: POWER (VCC). Connect to the Arduino's 5V pin for testing. Warning: Drawing too much current through the Arduino's regulator can damage it. For robust operation or multiple servos, use an external 5V supply connected to the breadboard's power rail. 3. Orange or Yellow Wire: SIGNAL. This is the control line. Connect it to a Pulse Width Modulation (PWM)-capable pin on the Arduino (marked with a ~ on the Uno, like pins 3, 5, 6, 9, 10, 11).

Pro Tip: Always connect the grounds of the Arduino and any external power supply together. A common ground is non-negotiable for proper signal reference.

The Heart of Control: Demystifying the Servo Signal

Arduino doesn't send a voltage level to a servo; it sends a pulse train. This is the core concept.

  • The servo expects a pulse every ~20 milliseconds (50 Hz frequency).
  • The width of that pulse determines the angle.
  • A 1.5 ms pulse typically centers the servo (e.g., 90°).
  • A 1.0 ms pulse drives it to one extreme (e.g., 0°).
  • A 2.0 ms pulse drives it to the other extreme (e.g., 180°).

These pulse widths can vary slightly between models, which is why calibration is useful. The Arduino's Servo library handles this timing with remarkable precision, freeing us from low-level timer code.

Software Strategies: From Basic Sweep to Controlled Motion

Now, let's translate theory into code. We'll explore three progressive methods.

Method 1: The Built-in Servo.h Library (Position Control)

This is the absolute starting point. It gives us direct position control.

cpp

include <Servo.h>

Servo myServo; // Create a servo object int servoPin = 9; int pos = 0; // Variable to store the servo position

void setup() { myServo.attach(servoPin); // Attaches the servo on pin 9 }

void loop() { // Sweep from 0 to 180 degrees for (pos = 0; pos <= 180; pos += 1) { myServo.write(pos); // Command the position delay(15); // Wait for the servo to reach the position } // Sweep back from 180 to 0 degrees for (pos = 180; pos >= 0; pos -= 1) { myServo.write(pos); delay(15); } } Here, the delay(15) indirectly controls speed. Increasing it slows the sweep; decreasing it speeds it up. However, this method blocks all other code execution during the delay(). It's simple but inefficient for complex projects.

Method 2: Simulating Speed Control with write() and millis()

To gain independent speed control without blocking, we ditch delay() and use time-based movement.

cpp

include <Servo.h>

Servo myServo; int servoPin = 9;

int targetPos = 180; int currentPos = 0; unsigned long previousMillis = 0; int speedDelay = 20; // Lower value = faster speed. Time between each 1-degree step.

void setup() { myServo.attach(servoPin); myServo.write(currentPos); }

void loop() { unsigned long currentMillis = millis();

// Check if it's time to move the servo if (currentMillis - previousMillis >= speedDelay) { previousMillis = currentMillis;

if (currentPos < targetPos) {   currentPos++; } else if (currentPos > targetPos) {   currentPos--; } myServo.write(currentPos); 

}

// Example: Change target and speed based on a condition // The rest of your non-blocking code can run here! if (currentPos == targetPos) { targetPos = (targetPos == 180) ? 0 : 180; speedDelay = (speedDelay == 20) ? 5 : 20; // Change speed dynamically } } This is a major leap forward. The servo moves one degree every speedDelay milliseconds. The loop() continues cycling, allowing you to read sensors, handle serial commands, or control other components simultaneously. You now have programmable speed.

Method 3: Advanced - Direct Pulse Writing with writeMicroseconds()

For ultimate control, especially for calibrating or using servos as continuous rotation drives, we can bypass the angle mapping.

cpp

include <Servo.h>

Servo myServo; int servoPin = 9;

void setup() { myServo.attach(servoPin); // Calibration: Find your servo's true stop pulse for continuous rotation // myServo.writeMicroseconds(1500); // Typical stop for many servos }

void loop() { // Controlled Clockwise Rotation at varying speeds for (int pulse = 1300; pulse >= 700; pulse -= 10) { myServo.writeMicroseconds(pulse); delay(1000); // Run at each "speed" for 1 second }

// Controlled Counter-Clockwise Rotation for (int pulse = 1700; pulse <= 2300; pulse += 10) { myServo.writeMicroseconds(pulse); delay(1000); } } The writeMicroseconds() function sends the raw pulse width. This is essential for converting a standard positional servo into a continuous rotation servo (often done by physically removing the potentiometer's stop and modifying the gear train). In this mode, a pulse near 1500µs stops the motor, smaller pulses command full speed in one direction, and larger pulses command full speed in the other, with variable speed in between.

Project Idea: A Non-Blocking, Sensor-Controlled Servo System

Let's synthesize everything into a practical example: a servo that smoothly follows a potentiometer (as a manual input) but has its speed limited based on the reading from a distance sensor (simulating a safety governor).

cpp

include <Servo.h>

Servo governedServo; const int servoPin = 9; const int potPin = A0; const int trigPin = 10; const int echoPin = 11;

int currentServoPos = 90; int targetServoPos = 90; int maxSpeedStep = 5; // Governor: max degrees to move per cycle unsigned long lastMoveTime = 0; int governorDelay = 50; // Base update time

void setup() { governedServo.attach(servoPin); governedServo.write(currentServoPos); pinMode(trigPin, OUTPUT); pinMode(echoPin, INPUT); Serial.begin(9600); }

long getDistance() { digitalWrite(trigPin, LOW); delayMicroseconds(2); digitalWrite(trigPin, HIGH); delayMicroseconds(10); digitalWrite(trigPin, LOW); long duration = pulseIn(echoPin, HIGH); return duration * 0.034 / 2; // Convert to cm }

void loop() { unsigned long currentMillis = millis();

// 1. Read the target from the potentiometer (0-1023 to 0-180) int potValue = analogRead(potPin); targetServoPos = map(potValue, 0, 1023, 0, 180);

// 2. Read the distance sensor and set the speed governor long distance = getDistance(); if (distance < 10) { // Object very close maxSpeedStep = 1; // Creep very slowly governorDelay = 100; } else if (distance < 30) { maxSpeedStep = 2; // Move slowly governorDelay = 75; } else { maxSpeedStep = 5; // Move at normal speed governorDelay = 50; }

// 3. Non-blocking, governed movement towards the target if (currentMillis - lastMoveTime >= governorDelay) { lastMoveTime = currentMillis;

int error = targetServoPos - currentServoPos; int moveStep = constrain(error, -maxSpeedStep, maxSpeedStep); currentServoPos += moveStep;  currentServoPos = constrain(currentServoPos, 0, 180); governedServo.write(currentServoPos);  // Serial monitoring for debugging Serial.print("Target: "); Serial.print(targetServoPos); Serial.print(" | Current: "); Serial.print(currentServoPos); Serial.print(" | Distance: "); Serial.print(distance); Serial.print(" | Step: "); Serial.println(moveStep); 

} } This project demonstrates professional-grade control: responsive input, sensor-based adaptive behavior, and butter-smooth, non-blocking motion—all with a few dollars worth of components.

Troubleshooting Common Pitfalls

  • Jittering/Jerking Servo: This is often a power issue. The servo draws a surge of current when it starts moving. Use a capacitor (e.g., 100µF electrolytic) across the power and ground rails near the servo. Always use an external power supply for more than one servo.
  • Servo Doesn't Move/Resets Arduino: A classic symptom of insufficient power. The servo is pulling so much current that the Arduino's voltage regulator browns out. Disconnect the servo's power wire from the Arduino's 5V and use a dedicated supply.
  • Limited Range of Motion: Your servo might not be a 180° model. Use writeMicroseconds() to find its actual minimum and maximum pulse widths (often between 500µs and 2500µs). Use myServo.attach(servoPin, 500, 2500); to calibrate the library.
  • Noisy Operation: Ensure your code isn't sending a new position command millions of times a second in a tight loop. The servo expects 50Hz commands. The Servo library manages this, but if you're writing pulses manually, adhere to the 20ms frame.

The journey from making a micro servo sweep back and forth to integrating it as a responsive, intelligently governed component in a larger system is what makes physical computing so rewarding. With your Arduino as the brain and the micro servo as a precise muscle, you are now equipped to build not just gadgets, but truly interactive machines. Grab your components, fire up the IDE, and start turning your ideas into controlled, physical motion.

Copyright Statement:

Author: Micro Servo Motor

Link: https://microservomotor.com/how-to-connect-a-micro-servo-motor-to-arduino/control-micro-servo-speed-direction-arduino.htm

Source: Micro Servo Motor

The copyright of this article belongs to the author. Reproduction is not allowed without permission.

About Us

Lucas Bennett avatar
Lucas Bennett
Welcome to my blog!

Archive

Tags