Arduino UNO Controlled Self-Balancing Robot with MPU-6050 and L298N Motor Driver
View and Edit Project In Cirkit Designer
Circuit Documentation
Summary
This circuit is designed to control a pair of hobby gearmotors using an Arduino UNO microcontroller and an L298N DC motor driver. The system is powered by two 18650 Li-ion batteries connected through a rocker switch. An MPU-6050 sensor is included to provide gyroscope and accelerometer data to the Arduino, which uses this data to adjust the motor speeds through a PID control loop. The purpose of this circuit is likely to create a self-balancing or position-controlled mechanism, such as a robot or a vehicle.
Component List
Arduino UNO
- Microcontroller board based on the ATmega328P
- Provides I/O pins for interfacing with various sensors and actuators
L298N DC Motor Driver
- Dual H-bridge motor driver
- Capable of driving two DC motors or one stepper motor
Rocker Switch
- Simple on/off switch
- Used to control the power supply to the circuit
Hobby Gearmotor with 48:1 Gearbox (x2)
- DC motor with a gearbox to increase torque
- Used for movement in robotics and mechanical projects
18650 Li-ion Battery x 2
- Rechargeable battery cells
- Provides power to the circuit
MPU-6050
- Motion tracking device with a 3-axis gyroscope and a 3-axis accelerometer
- Provides data for motion control and stabilization
Wiring Details
Arduino UNO
GNDconnected to the common ground net5Vconnected to the 5V net, providing power to the MPU-6050 and L298NA4 (SDA)connected to the MPU-6050 SDA pin for I2C communicationA5 (SCL)connected to the MPU-6050 SCL pin for I2C communicationD13connected to L298NIN2for motor controlD12connected to L298NIN1for motor controlD11connected to L298NIN4for motor controlD10connected to L298NIN3for motor controlD6connected to L298NENBfor motor speed controlD5connected to L298NENAfor motor speed control
L298N DC Motor Driver
GNDconnected to the common ground net5Vconnected to the 5V net, receiving power from the Arduino UNO12Vconnected to the rocker switch output for motor powerENAandENBconnected to Arduino pins D5 and D6 for speed controlIN1,IN2,IN3, andIN4connected to Arduino pins D12, D13, D10, and D11 for direction controlOUT1andOUT2connected to one gearmotorOUT3andOUT4connected to the other gearmotor
Rocker Switch
inputconnected to the positive terminal of the 18650 Li-ion battery packoutputconnected to the L298N12Vinput for motor power
Hobby Gearmotor with 48:1 Gearbox
- One motor's
pin 1connected to L298NOUT1 - One motor's
pin 2connected to L298NOUT2 - The other motor's
pin 1connected to L298NOUT4 - The other motor's
pin 2connected to L298NOUT3
18650 Li-ion Battery x 2
+connected to the rocker switch input-connected to the common ground net
MPU-6050
VCCconnected to the 5V netGNDconnected to the common ground netSDAconnected to ArduinoA4for I2C communicationSCLconnected to ArduinoA5for I2C communication
Documented Code
#include <Arduino.h>
#include "Wire.h"
#include <MPU6050_light.h>
// Motor A control pins
#define MOTOR_A_IN1 4
#define MOTOR_A_IN2 5
#define MOTOR_A_ENA 10
// Motor B control pins
#define MOTOR_B_IN1 6
#define MOTOR_B_IN2 7
#define MOTOR_B_ENA 9
// Initialize MPU6050 sensor
MPU6050 mpu(Wire);
unsigned long timer = 0;
// Gyroscope readings
float angle_x, angle_y, angle_z;
// PID controller variables
float Kp = 40.0; // Proportional gain
float Kd = 1.0; // Derivative gain
float Ki = 0.2; // Integral gain
float target = 0.0; // Desired angle
float error, integral, derivative, last_error;
float prev_steer;
// Function prototypes
float steerPid(float error);
void steerToMotorsSpeed(float steer, float &l_wheel_speed, float &r_wheel_speed);
void move(int val_l, int val_r);
// Speed variables
float min_speed = 80.0;
float max_speed = 150.0;
float mid_speed = (max_speed - min_speed) / 2.0;
float l_wheel_speed = 150.0, r_wheel_speed = 150.0;
float p_l, p_r;
float max_steer_pid_output = 2000.0;
void setup() {
// Initialize serial communication
Serial.begin(9600);
// Initialize I2C communication for MPU6050
Wire.begin();
// Start MPU6050 sensor
byte status = mpu.begin();
Serial.print(F("MPU6050 status: "));
Serial.println(status);
// Wait if MPU6050 is not connected
while (status != 0) {
// Stop everything if unable to connect to MPU6050
}
Serial.println(F("Calculating offsets, do not move MPU6050"));
delay(1000);
// Calculate gyro and accelerometer offsets
mpu.calcOffsets();
Serial.println("Done!\n");
// Gradually increase speed to start moving smoothly
float cur_speed = 100.0;
while (cur_speed < max_speed) {
String log = "Moving with " + String(cur_speed) + " speed.";
Serial.println(log);
move(cur_speed, cur_speed);
cur_speed += 20.0;
delay(1000);
}
}
void loop() {
// Update sensor readings
mpu.update();
// Execute every 10 milliseconds
if ((millis() - timer) > 10) {
// Get current angles from MPU6050
angle_x = mpu.getAngleX();
angle_y = mpu.getAngleY();
angle_z = mpu.getAngleZ();
// Log current angles
String log = "Angles - X: " + String(angle_x) + ", Y: " + String(angle_y) + ", Z: " + String(angle_z);
Serial.println(log);
// Calculate steering adjustment using PID controller
float new_steer = steerPid(angle_z - target);
// Adjust motor speeds based on steering value
steerToMotorsSpeed(new_steer, l_wheel_speed, r_wheel_speed);
// Move motors with adjusted speeds
move(l_wheel_speed, r_wheel_speed);
// Log previous and current steering values
String log1 = "Prev Steer value: " + String(prev_steer) + " New Steer value: " + String(new_steer);
Serial.println(log1);
// Log previous and current motor speeds
String log3 = "Prev Speed value: L" + String(p_l) + ", R " + String(p_r) +
" New Speed value: L" + String(l_wheel_speed) + ", R " + String(r_wheel_speed);
Serial.println(log3);
// Update timer and previous values
timer = millis();
prev_steer = new_steer;
p_l = l_wheel_speed;
p_r = r_wheel_speed;
}
}
// PID controller function
// Calculates the steering adjustment based on error
float steerPid(float error) {
derivative = error - last_error; // Calculate derivative
last_error = error; // Update last error
integral += error; // Accumulate integral
// Return PID output
return (error * Kp) + (derivative * Kd) + (integral * Ki);
}
float speed_adjust;
float normalized_steer;
// Maps the steering value from PID to motor speeds
void steerToMotorsSpeed(float steer, float &l_wheel_speed, float &r_wheel_speed) {
// Normalize steer value to range between 0 and 1
normalized_steer = abs(steer) / max_steer_pid_output;
speed_adjust = mid_speed * normalized_steer;
if (steer > 0) {
// Steering to the left
l_wheel_speed = constrain(l_wheel_speed + speed_adjust, min_speed, max_speed);
r_wheel_speed = constrain(r_wheel_speed - speed_adjust, min_speed, max_speed);