Servo motor control with Raspberry Pi and ADS1115 ADC module

 In this Raspberry Pi 4 tutorial, I will show how to control a servo motor with Raspberry Pi and ADS1115 ADC module. The servo motor is controlled using a potentiometer, that is, the position of servo motor is controlled using 10kOhm potentiometer. However, unlike an Arduino Uno or an ATmega328p chip, which have built-in analog-to-digital converters (ADCs), the broadcom processor on the Raspberry Pi 4 is a purely digital computer. Its GPIO pins can only understand two states: HIGH (3.3V) or LOW (0V). So in order to use potentiometer for servo control we will use the ADS1115 ADC module. The ADS1115 is a high-precision Analog-to-Digital Converter (ADC) breakthrough chip created by Texas Instruments. In the maker and electronics world, it is the absolute go-to module when you need to read analog sensors using microcontrollers or single-board computers (like the Raspberry Pi) that don't have built-in analog inputs.

Hardware and Schematic

The circuit diagram below shows how to connect servo meter to ADS1115 module which is then connected to Raspberry Pi.

Servo control ADS1115 and Raspberry Pi

Here is a complete, detailed breakdown of how the circuit wiring functions.

1. Power Supply and Ground Rails

Every component in this circuit needs a common voltage reference and power source to communicate safely.

  • The $+3.3\text{V}$ Power Rail: The Raspberry Pi 4 outputs a regulated $+3.3\text{V}$ from its physical header (Pin 1 or 17). This rail acts as the main power source for the entire analog side of your circuit. It powers the VDD pin of the ADS1115 and the left pin of your potentiometer (RV1).

  • The Ground ($\text{GND}$) Rail: The GND pin of the ADS1115, the ADDR pin (to set the default address), and the right pin of the potentiometer are all tied together back to a $\text{GND}$ pin on the Raspberry Pi. This creates a complete loop for the current to flow.

2. The Potentiometer Input Wiring (Analog Input)

The potentiometer acts as our physical control knob.

  • Voltage Divider Action: With the left pin tied to $+3.3\text{V}$ and the right pin tied to $\text{GND}$, the internal resistive track of the potentiometer drops the full $3.3\text{V}$.

  • The Wiper Pin: The middle pin (the wiper) physically moves along this track as you turn the knob. It acts as a variable voltage divider, outputting a smooth analog voltage anywhere between $0\text{V}$ (turned all the way to the right) and $3.3\text{V}$ (turned all the way to the left).

  • Connection to ADC: This changing analog voltage is routed directly into the A0 input pin of the ADS1115, where it will be sampled and converted into a digital number.

  • See also How to control a servo with a potentiometer?

3. The I2C Communication Lines (The Data Bus)

Instead of using lots of pins, the ADS1115 uses the Inter-Integrated Circuit (I2C) protocol to talk to the Raspberry Pi using just two wires.

  • SDA (Serial Data Line): Connected directly from the SDA pin of the ADS1115 to GPIO2 (Pin 3) on the Raspberry Pi. This line carries the actual digital conversion data (the measurement of your knob position) back to the Pi.

  • SCL (Serial Clock Line): Connected directly from the SCL pin of the ADS1115 to GPIO3 (Pin 5) on the Raspberry Pi. This line carries a continuous clock signal generated by the Pi to keep the data transmission perfectly synchronized.

  • The ADDR Pin: Wired directly to GND. This hardwires the internal logic of the ADS1115 to look for the specific binary address 0x48 whenever the Raspberry Pi calls it on the bus.

4. The Servo Motor Control Line (Digital Output)

This is the final stage of the circuit, where the Raspberry Pi commands the motor based on what it learned from the ADC.

  • PWM Generation: GPIO18 (Pin 12) on the Raspberry Pi is wired directly to the control line of your servo motor. GPIO18 is a hardware Pulse Width Modulation (PWM) pin.

  • How it works: The Python script changes the "On-Time" (Duty Cycle) of a $50\text{ Hz}$ square wave sent over this wire. A pulse width of $1\text{ ms}$ tells the servo to move to $0^\circ$, while a pulse width of $2\text{ ms}$ tells it to move to $180^\circ$.

Program Code/Python Script

Below is the Python script for Raspberry Pi for servo motor control:
import time
import RPi.GPIO as GPIO
import ADS1x15 

# --- Hardware Setup ---
SERVO_PIN = 18
GPIO.setmode(GPIO.BCM)
GPIO.setup(SERVO_PIN, GPIO.OUT)

pwm = GPIO.PWM(SERVO_PIN, 50)
pwm.start(2.5) 

# Initialize the internal ADS1115 driver (Default I2C address 0x48)
adc = ADS1x15.ADS1115(address=0x48, busnum=1)

print("Reading from internal Proteus ADS1115 library...")

try:
    while True:
        # Read Gain 1 (+/-4.096V), Channel 0
        # The internal library usually returns the raw 16-bit value
        raw_val = adc.read_adc(0, gain=1)
        
        # Convert raw bits to approximate voltage (3.3V max input)
        voltage = (raw_val * 4.096) / 32768.0
        if voltage > 3.3: voltage = 3.3
        if voltage < 0.0: voltage = 0.0
        
        # Map to Servo Duty Cycle (2.5% to 12.5%)
        duty_cycle = 2.5 + (voltage / 3.3) * 10.0
        pwm.ChangeDutyCycle(duty_cycle)
        
        print(f"Raw: {raw_val} | Volt: {voltage:.2f}V | Servo Duty: {duty_cycle:.2f}%")
        time.sleep(0.1)

except KeyboardInterrupt:
    pwm.stop()
    GPIO.cleanup()
This script establishes communication between a Raspberry Pi, an external analog-to-digital converter, and a servo motor to translate physical knob adjustments into motor movements.

Initially, the program imports necessary timing, pin control, and converter modules. It configures a hardware pin on the Raspberry Pi to send a specialized fifty-hertz control signal required by motors, initializing it at its starting position. Concurrently, it connects to the converter chip using its standard digital address.

Once configured, the script enters a continuous loop that performs three core tasks. First, it grabs a precise raw numerical measurement from the first input channel where the control knob is attached. Second, it converts this raw data into an accurate voltage value, placing strict boundaries on the number to keep it within safe operating limits. Third, it applies a math formula to translate that voltage into a specific signal duration that standard servo motors understand, actively updating the motor's physical position.

The loop pauses slightly on every repetition to prevent system lag and print real-time updates. If a user manually terminates the program, the script safely shuts down the motor signals and resets the hardware pins to protect the circuit.

Video demonstration

Watch the following video to learn how the servo is controlled using the potentiometer and Raspberry Pi.



If you want to control multiple servo motors for robotics or other works, see Interfacing PCA9685 with Arduino Nano for Robotics | 3 Servo Motor Control.

Download Proteus Library/Model

Related tutorials

Post a Comment

Previous Post Next Post