← All experience

Controller Design for a Differential-Drive Robot

Python, NumPy, SciPy, Quanser QBot, Dept. of Electrical Engineering, IIT (BHU) Varanasi
summer research internship after my second year · 2 June – 2 July 2025 · supervisor: Dr. Shyam Kamal
report

A one-month research internship on linear control for autonomous ground robots. I modelled a differential-drive robot, wrote PID and LQR controllers in Python, and ran them on the Quanser QBot hardware to track parabolic, sinusoidal and free-form paths. At the end I formulated an MPC controller for constrained motion and explored first ideas in nonlinear control.

Platform
Quanser QBot

The QBot Platform is an open-architecture ground robot on a differential-drive base: two driven wheels, one on each side. My first task was to learn the hardware and to send velocity commands to it from Python.

Quanser QBot Platform, a black and red hexagonal ground robot with a LiDAR on top
Model
Differential-drive kinematics

I wrote the forward and inverse kinematics. The wheel speeds give the robot's linear speed v = (vR + vL)/2 and turn rate ω = (vR − vL)/L. Odometry integrates ẋ = v cos θ, ẏ = v sin θ, θ̇ = ω at each time step. Angle normalisation keeps θ in range, so the heading does not drift.

Diagram of a differential-drive robot: wheels, wheel speeds, heading angle, turn radius and instantaneous centre of curvature
PID
PID path tracking

I wrote one PID controller for position and one for heading. Their outputs are velocity commands in the world frame. The code transforms them into the robot frame and limits them for safety. After several rounds of debugging the command structure and tuning the gains on the hardware, the robot tracked parabolic, sinusoidal and free-form paths closely.

Three plots of required path (red dashed) and actual path (blue): a parabola, a sine wave and a custom curve
PID tracking: required path (red, dashed) and actual path (blue) for a parabola, a sine wave and a custom path.
LQR
Optimal control with LQR

I linearised the model around a nominal forward speed v0 and a small heading angle (cos θ ≈ 1, sin θ ≈ θ). This gives ẋ = Ax + Bu, with state [x, y, θ] and input [v, ω]. SciPy's continuous algebraic Riccati solver gives P, and the gain is K = R−1BTP. The control law is u = −K(x − xref), with velocity saturation for the real robot. I tuned the weights Q (tracking error) and R (control effort). LQR did better than PID, mainly in dynamic conditions.

MPC
First steps with MPC

In the last part I formulated model predictive control: over a horizon of N steps, minimise the tracking error and control effort, subject to the linear model and limits on states and inputs, then apply only the first input (receding horizon). The plan was a quadratic-programming solver with velocity and acceleration limits. This part was a start for constrained motion planning, not a finished result.

My part

I did all of the work on this page: the kinematic model, the PID and LQR code, the hardware tests and the tuning.

Challenges

  • Wheel slip: slip made the odometry wrong over time, so the estimated pose moved away from the real pose.
  • Command structure: PID outputs are in the world frame, but the robot takes commands in its own frame. It took several iterations to get the transform and the limits right.
  • Tuning on hardware: gains that worked in simulation needed changes on the real robot.

What I learnt

  • Differential-drive kinematics and odometry, from equations to working code.
  • Controller design from start to end: model, design, implementation and tuning.
  • How to linearise a nonlinear model, set up LQR and solve the Riccati equation.
  • How to move a controller from theory to a real robot.

I thank Dr. Shyam Kamal for his supervision and Mrs. Priyanka for her guidance during the internship.

Full internship report (PDF)