Hello!
I have made my own all PCB quadcopter, of which I have attached an image, and I am wondering what exactly I need to do to get the Ardupilot working with my device. In terms of hardware, there are not very many variations, other than the fact that:
- It does not use an ESC, just a PWM signal to a MOSFET.
- There is no RC, it, for now, must just hover level.
Basically I want to solely stabilise the platform. Here is my arduino code so far, I started off writing from scratch:
[code]
// ================================================================
// === Referenc Material ===
// ================================================================
// http://theboredengineers.com/2012/05/the-quadcopter-basics/
// http://blog.oscarliang.net/quadcopter-pid-explained-tuning/
// https://github.com/grantmd/QuadCopter
// http://www.pdx.edu/nanogroup/sites/www.pdx.edu.nanogroup/files/2013_Arduino%20PID%20Lab_0.pdf
// http://www.maelabs.ucsd.edu/mae156alib/control/PID-Control-Ardunio.pdf
// ================================================================
// === LIBRARY INCLUSIONS ===
// ================================================================
#include <Wire.h> // I2C Library
#include “I2Cdev.h” // Advanced I2C Functions
#include “MPU9150Lib.h” // MPU-9150 Motion Processing Fuctions
#include “CalLib.h” // MPU-9150 Calibration Algorithms
#include <dmpKey.h> // MPU-9150 DMP Register Keys
#include <dmpmap.h> // MPU-9150 DMP Register Map
#include <inv_mpu.h> // MPU-9150 Low Level Motion Processing Algorithms
#include <inv_mpu_dmp_motion_driver.h> // MPU-9150 DMP Algorithms
#include <EEPROM.h> // EEPROM Controller
#include <PID_v1.h>
// ================================================================
// === MOTOR DEFINITIONS ===
// ================================================================
#define MOTOR_FL 4 // Front left CCW
#define MOTOR_FR 5 // Front right CW
#define MOTOR_BL 8 // back left CW
#define MOTOR_BR 3 // back right CCW
// ================================================================
// === CLASS DECLARATIONS ===
// ================================================================
MPU9150Lib MPU;
// ================================================================
// === CONSTANT DECLARATIONS ===
// ================================================================
float gRes = 2000.0/32768.0; // Gyro Scale Resolution
// ================================================================
// === MPU1950 VARIABLE DECLARATIONS ===
// ================================================================
#define DEVICE_TO_USE 0 // 0 = 0x68, 1 = 0x69
#define MPU_UPDATE_RATE (20) // MPU_UPDATE_RATE defines the rate (in Hz) at which the MPU updates the sensor data and DMP output
#define MAG_UPDATE_RATE (15) // MAG_UPDATE_RATE defines the rate (in Hz) at which the MPU updates the magnetometer data, should be less than or equal to MPU_UPDATE_RATE
#define MPU_MAG_MIX_GYRO_AND_SOME_MAG 10 // MPU_MAG_MIX defines the influence that the magnetometer has on the yaw output (0 = Only Gyro, 1 = Only Mag, 50 = Mainly Gyros with Mag)
#define MPU_LPF_RATE 40 // MPU_LPF_RATE is the low pas filter rate and can be between 5 and 188Hz
// ================================================================
// === KINEMATICS ===
// ================================================================
// Current Orientation Data
double currentRoll = 0.0;
double currentPitch = 0.0;
double currentHeading = 0.0;
// Current Gyro Data
double gyroRateX;
double gyroRateY;
double gyroRateZ;
// Target Gyro Data - Generated by PID
double targetgyroRateX;
double targetgyroRateY;
double targetgyroRateZ;
// Target Orientation - Assuming We Want to be Level
double targetPitch = 0.0;
double targetRoll = 0.0;
double targetHeading = 0.0;
// Initial Throttle Value
float biasThrottle = 220;
// Throttle Adjust Values
double pitchAdjust;
double rollAdjust;
// PID Objects
PID pitchStabPID(¤tPitch, &targetgyroRateX, &targetPitch,(double)1,(double)0,(double)0, DIRECT);
PID pitchRatePID(&gyroRateX, &pitchAdjust, &targetgyroRateX,(double)0.15,(double)0,(double)0, DIRECT);
PID rollStabPID(¤tRoll, &targetgyroRateY, &targetRoll,(double)1,(double)0,(double)0, DIRECT);
PID rollRatePID(&gyroRateY, &rollAdjust, &targetgyroRateY,(double)0.15,(double)0,(double)0, DIRECT);
// ================================================================
// === INITIAL SETUP ===
// ================================================================
void setup() {
// Pin Mode Declarations
pinMode(MOTOR_FL, OUTPUT);
pinMode(MOTOR_FR, OUTPUT);
pinMode(MOTOR_BL, OUTPUT);
pinMode(MOTOR_BR, OUTPUT);
// Pour a Bowl of Serial
Serial.begin(115200);
Serial.println(“Serial link established…”);
// Initialize I2C bus
Wire.begin();
// Select IMU address & Initialise IMU with Calibration Data & DMP Functionality
MPU.selectDevice(DEVICE_TO_USE);
MPU.init(MPU_UPDATE_RATE, MPU_MAG_MIX_GYRO_AND_SOME_MAG, MAG_UPDATE_RATE, MPU_LPF_RATE);
// Setup PID Controllers
PIDInit();
// Start Motors at Idle Speed ~ 20%
engineStart();
}
// ================================================================
// === MAIN LOOP ===
// ================================================================
void loop() {
// DMP Complete
if (MPU.read()){
// Calculate Orientation in Degrees
currentPitch = MPU.m_fusedEulerPose[VEC3_X] * RAD_TO_DEGREE;
currentRoll = MPU.m_fusedEulerPose[VEC3_Y] * RAD_TO_DEGREE;
currentHeading = MPU.m_fusedEulerPose[VEC3_Z] * RAD_TO_DEGREE;
// Calculate Rotationial Rate in Degrees per Sec
gyroRateX= MPU.m_rawGyro[VEC3_X] * gRes; // Pitch Rate
gyroRateY= MPU.m_rawGyro[VEC3_Y] * -gRes; // Roll Rate
gyroRateZ= MPU.m_rawGyro[VEC3_Z] * gRes;
/*Serial.print("Pitch: ");
Serial.print(currentHeading);
Serial.print(" Rate: ");
Serial.println(gyroRateZ);*/
}
// ================================================================
// === PID Algorithm Here! ===
// ================================================================
// This is where the Black Magic happens....
pitchStabPID.Compute();
rollStabPID.Compute();
pitchRatePID.Compute();
rollRatePID.Compute();
// Debug!
/*Serial.print("Pitch: ");
Serial.print(currentPitch);
Serial.print(" ");
Serial.print("Target Rate: ");
Serial.print(targetgyroRateX);
Serial.print(" ");
Serial.print("Actual Rate: ");
Serial.print(gyroRateX);
Serial.print(" ");
Serial.print("Adjust: ");
Serial.println(pitchAdjust);
Serial.println();*/
Serial.print("Pitch: " );
Serial.print(pitchAdjust);
Serial.print(" Roll: " );
Serial.println(rollAdjust);
// Motor Offset Fusion
/*analogWrite(MOTOR_FL, biasThrottle + pitchAdjust);
analogWrite(MOTOR_FR, biasThrottle + pitchAdjust);
analogWrite(MOTOR_BL, biasThrottle - pitchAdjust);
analogWrite(MOTOR_BR, biasThrottle - pitchAdjust);*/
pitchAdjust = (1.5 * pitchAdjust);
rollAdjust = (1.5 * rollAdjust);
analogWrite(MOTOR_FL, biasThrottle + pitchAdjust - rollAdjust);
analogWrite(MOTOR_FR, biasThrottle + pitchAdjust + rollAdjust);
analogWrite(MOTOR_BL, biasThrottle - pitchAdjust - rollAdjust);
analogWrite(MOTOR_BR, biasThrottle - pitchAdjust + rollAdjust);
}
// ================================================================
// === PID Initilisation ===
// ================================================================
void PIDInit(){
pitchStabPID.SetSampleTime(15);
pitchStabPID.SetMode(AUTOMATIC);
pitchStabPID.SetOutputLimits(-50, 50);
pitchRatePID.SetSampleTime(15);
pitchRatePID.SetMode(AUTOMATIC);
pitchRatePID.SetOutputLimits(-75, 75);
rollStabPID.SetSampleTime(15);
rollStabPID.SetMode(AUTOMATIC);
rollStabPID.SetOutputLimits(-50, 50);
rollRatePID.SetSampleTime(15);
rollRatePID.SetMode(AUTOMATIC);
rollRatePID.SetOutputLimits(-75, 75);
}
// ================================================================
// === MOTOR CONTROL ROUTINES ===
// ================================================================
void engineStart(){
Serial.print("Begin Engine Startup… ");
// Idle Motors at 20%
analogWrite(MOTOR_FL, 55);
delay (800);
analogWrite(MOTOR_FR, 55);
delay (800);
analogWrite(MOTOR_BL, 55);
delay (800);
analogWrite(MOTOR_BR, 55);
delay(800);
// All Good If Were Here!
Serial.println(“Engines Active”);
}
void engineKill(){
Serial.println(“Engine Cutout…”);
// Kill all Motors
analogWrite(MOTOR_FL, 1);
analogWrite(MOTOR_FR, 1);
analogWrite(MOTOR_BL, 1);
analogWrite(MOTOR_BR, 1);
}[/code]