Quadrotor Autonomous Control

Quadrotor autonomously holding its x and y position, thrust is being controlled

The video above is a demonstration of the quadrotor attempting to maintain its x and y position (the x-y plane is the ground). The amount of thrust being generated by the motors (prior to adjustments made during the feedback loop) is being controlled by an Xbox controller for safety reasons. I was flying the quadrotor indoors and needed a way to kill all the motors when it became unstable. Being able to control the thrust allowed the quadrotor to lift off the ground slowly and for me to observe whether the feedback control was working properly before increasing the thrust to bring it to greater heights. As shown, I was not great at controlling the thrust precisely, causing the quadrotor to rise and drop rather abruptly. The video above does not show my best result. This was taken prior to additional fine-tuning I had performed. Unfortunately, I didn’t take a video of the best run, but the quadrotor was able to hold its position autonomously in, roughly, a 30 cm cube.


Introduction

The goal of this project is to construct a quadrotor and develop a control algorithm for maintaining its x-y position while it is in the air. The quadrotor should also be able to receive teleoperation commands from an Xbox controller, so its flight can be controlled by an operator. However, when teleoperation control ceases, the quadrotor should return to holding its position in the air, with only the thrust needed to be controlled.

Components

  • Raspberry Pi Zero

  • WIFI module

  • PWM module

  • IMU (Inertial Measurement Unit) sensor

  • 4 DC motors

  • 4 propellers

  • Lithium-ion battery

  • 3D printed chassis

  • Xbox controller

Quadrotor Close-up


Closed-Loop Feedback Control

Roll, Pitch, and Yaw Rate

I used the accelerometer readings from the IMU in the x-y-z axes to calculate the roll and pitch of the quadrotor. The yaw rate is equal to the gyroscope reading in the z-axis, also taken from the IMU. In the code below, imu_data is a global array of 6 floats storing the x-y-z acceleration and x-y-z angular velocity. read_raw takes in the address of the measured value and returns an analog value. The addition of the calibration terms comes from a calibration process that is performed when the quadrotor is stationary and on a level surface (i.e. the ground or a tabletop). 1000 samples are taken during the calibration process and then averaged to surmise and adjust for the IMU bias.

void read_imu()
{
  int vw;
  float ax, ay, az;

  vw = read_raw(59); // accel x    
  imu_data[3]=vw/32767.0*2; 
  
  vw = read_raw(61); // accel y 
  imu_data[4]=vw/32767.0*2;
  
  vw = read_raw(63); // accel z
  imu_data[5]=accel_z_calibration+vw/32767.0*2; 
  
  ax = imu_data[3];
  ay = imu_data[4];
  az = imu_data[5];
  roll_accel = roll_calibration+atan2(ax, -az)/M_PI*180;
  pitch_accel = pitch_calibration+atan2(ay, -az)/M_PI*180;

  vw = read_raw(71); // gyro z            
  imu_data[2]=z_gyro_calibration+vw/32767.0*500; 
}

Controller Input

The controller inputs are stored in an object called Keyboard, which has attributes for the pitch and roll value read from the joystick. This value is ranges from 0 to 224, in which the default value (when the joystick is centered) is equal to 112. I defined a linear function that converts this value to a pitch and roll angle. The variables in all caps are macros defined at the top of the file, since they are parameters that are constantly being tuned. For instance, I_PITCH represents the pitch integral gain. Pitch is integrated by adding pitch error multiplied by the gain to the current sum. Similarly, the same is done for roll. The desired thrust and yaw are not part of the closed feedback loop, and consequently, are mapped from controller inputs to the appropriate unit.

Proportional-Integral-Derivative (PID) Controller

The desired values for the pitch and roll are then calculated from the standard PID control function.

PID Control Function

void get_joystick()
{
  Keyboard keyboard=*shared_memory;

  float joy_input_pitch = keyboard.pitch/224.0*JOY_PITCH-0.57143*JOY_PITCH;
  float joy_input_roll = -keyboard.roll/224.0*JOY_ROLL+0.57143*JOY_ROLL;
  float pitch_error = pitch_angle-joy_input_pitch;
  float roll_error = roll_angle-joy_input_roll;
  
  intg_pitch += pitch_error*I_PITCH;
  intg_roll += roll_error*I_ROLL;
  // apply upper and lower limits on integrated pitch and roll
  // omitted for brevity
  
  desired_pitch = pitch_error*P_PITCH+intg_pitch*I_PITCH+imu_data[0]*D_PITCH;
  desired_roll = roll_error*P_ROLL+intg_roll*I_ROLL+imu_data[1]*D_ROLL;
  desired_thrust = NTRL_THRUST + (keyboard.thrust/128.0-1.0)*(NTRL_THRUST-JOY_THRUST_MIN);
  desired_yaw = keyboard.yaw/224.0*JOY_YAW-0.57143*JOY_YAW;
}

Motor PWM

Labelled Motors

Each of the four motors starts off with the baseline desired_thrust. Then, depending on the location of the motor on the quadrotor, the desired_pitch and the desired_roll is either added or subtracted from the baseline. For instance, if the desired pitch is positive, then motors 0 and 3 should have their thrusts increased while motors 1 and 2, decreased. If the desired roll is positive, then motors 2 and 3 should have their thrusts increased while motors 0 and 1, decreased. A proportional controller is also added for the yaw rate to prevent the quadrotor from rotating about the z-axis. The thrust values are then sent to a function that converts them to the proper duty cycles, which, at last, are relayed to the motors.

void pid_update()
{
  float yaw_error = imu_data[2]-desired_yaw;
  
  motor_cntrl0 = desired_thrust+desired_pitch-desired_roll_joy-yaw_error*P_YAW;
  motor_cntrl1 = desired_thrust-desired_pitch-desired_roll_joyL+yaw_error*P_YAW;
  motor_cntrl2 = desired_thrust-desired_pitch+desired_roll_joy-yaw_error*P_YAW;
  motor_cntrl3 = desired_thrust+desired_pitch+desired_roll_joy+yaw_error*P_YAW
  
  set_PWM(0, motor_cntrl0); 
  set_PWM(1, motor_cntrl1); 
  set_PWM(2, motor_cntrl2); 
  set_PWM(3, motor_cntrl3); 
}
Previous
Previous

Speedy Motion Detection

Next
Next

Module Assembly Report Automation