void TimerClass::start()
{
timeValue_.tv_sec = 0;
timeValue_.tv_nsec = PERIOD;
timeToSet_.it_value = timeValue_;
timer_settime(timerId, 0, &timeToSet_, NULL);
started = true;
}
TimerClass::TimerClass(){ /* Intialize sigaction struct */
signalAction.sa_handler = &sig_handler_; /* Connect a signal handler routine to the SIGALRM signal */
sigaction(SIGALRM, &signalAction, NULL); /* Allocate a timer */
timer_create(CLOCK_REALTIME, NULL, &timerId);
started = false;} |
void TimerClass::sig_handler_(int signum){
pthread_mutex_lock(&TimerMutex_);
PICInterface.getRX();
Timer.calcdt_();
AHRS.update();
Control.update();
LogMan.update();
Timer.compensate_();
pthread_mutex_unlock(&TimerMutex_);
}
每次都timer 啟動時...會執行上述的function
1. pthread_mutex_lock(&TimerMutex_); 打開 mutex -> 不讓中斷切走
2. PICInterface.getRX(); 3. Timer.calcdt_(); 4. AHRS.update(); 5. Control.update(); 6. LogMan.update(); 7. Timer.compensate_(); 8. pthread_mutex_unlock(&TimerMutex_); , 關閉 mutex...讓中斷可以啟動 |
void PICInterfaceClass::getRX() {
uint8_t widthsChar[12] = {0};
//Appears to generate read errors above ~5 bytes, returning only 1's
// I2CInterface.readRegister(PIC_ADDRESS, REG_RX1H, widthsChar, sizeof(widthsChar));
I2CInterface.readRegister(PIC_ADDRESS, REG_RX1H, &widthsChar[0], 2);
I2CInterface.readRegister(PIC_ADDRESS, REG_RX2H, &widthsChar[2], 2);
I2CInterface.readRegister(PIC_ADDRESS, REG_RX3H, &widthsChar[4], 2);
I2CInterface.readRegister(PIC_ADDRESS, REG_RX4H, &widthsChar[6], 2);
I2CInterface.readRegister(PIC_ADDRESS, REG_RX5H, &widthsChar[8], 2);
I2CInterface.readRegister(PIC_ADDRESS, REG_RX6H, &widthsChar[10], 2);
rxWidths.roll = make16_(widthsChar[0], widthsChar[1]);
rxWidths.pitch = make16_(widthsChar[2], widthsChar[3]);
rxWidths.throttle = make16_(widthsChar[4], widthsChar[5]);
rxWidths.yaw = make16_(widthsChar[6], widthsChar[7]);
rxWidths.sw1 = make16_(widthsChar[8], widthsChar[9]);
rxWidths.sw2 = make16_(widthsChar[10], widthsChar[11]);
static int i = 0;
rxWidthsHist[i] = rxWidths;
i++;
if(i == FILTER_LEN) {
i = 0;
}
rxWidths = averageRX_(rxWidthsHist, FILTER_LEN, i);
calibrateRX_();
}
inline void PICInterfaceClass::calibrateRX_() {
rx.pitchDem = PITCH_RANGE * (static_cast<float> (rxWidths.pitch - ((RX_MAX - RX_MIN) / 2) - RX_MIN) / (RX_MAX - RX_MIN));
rx.rollDem = ROLL_RANGE * (static_cast<float> (rxWidths.roll - ((RX_MAX - RX_MIN) / 2) - RX_MIN) / (RX_MAX - RX_MIN));
rx.yawRateDem = YAW_RATE_RANGE * (static_cast<float> (rxWidths.yaw - ((RX_MAX - RX_MIN) / 2) - RX_MIN) / (RX_MAX - RX_MIN));
rx.throttleDem = static_cast<float> (rxWidths.throttle - RX_MIN) / (RX_MAX - RX_MIN);
rx.sw1 = (rxWidths.sw1 > 15000);
rx.sw2 = (rxWidths.sw2 > 15000);
rx.pitchRateDem = PITCH_RATE_RANGE * (static_cast<float> (rxWidths.pitch - ((RX_MAX - RX_MIN) / 2) - RX_MIN) / (RX_MAX - RX_MIN));;
rx.rollRateDem = ROLL_RATE_RANGE * (static_cast<float> (rxWidths.roll - ((RX_MAX - RX_MIN) / 2) - RX_MIN) / (RX_MAX - RX_MIN));
rx.yawRateDem = -rx.yawRateDem;
}
3.
/// 計算時間的間隔
inline void TimerClass::calcdt_(){
oldtime_ = time_;
clock_gettime(CLOCK_MONOTONIC, &time_);
Timer.dt = ((static_cast<int64_t>(time_.tv_sec) * 1000000000 + static_cast<int64_t>(time_.tv_nsec)) - (static_cast<int64_t>(oldtime_.tv_sec) * 1000000000 + static_cast<int64_t>(oldtime_.tv_nsec))) / 1000000000.0;
} |
4.
void AHRSClass::update() {
getSensors_();
calibrateData_();
temperatureCompensate_();
fuse_();
} |
void AHRSClass::getSensors_() {
MPU6050.getSensors(&rawData_);
HMC5883L.getField(&rawData_);
MS5611.getPressure(&rawData_.pressure);
}
bool MPU6050Class::getSensors(s_rawData* rawData)
{
uint8_t buf[14];
I2CInterface.readRegister(MPU6050_ADDRESS, MPU6050_RA_ACCEL_XOUT_H, buf, 14);
rawData->x = static_cast<int16_t>((buf[0]<<8)|buf[1]);
rawData->y = static_cast<int16_t>((buf[2]<<8)|buf[3]);
rawData->z = static_cast<int16_t>((buf[4]<<8)|buf[5]);
rawData->temp = static_cast<int16_t>((buf[6]<<8)|buf[7]);
rawData->p = static_cast<int16_t>((buf[8]<<8)|buf[9]);
rawData->q = static_cast<int16_t>((buf[10]<<8)|buf[11]);
rawData->r = static_cast<int16_t>((buf[12]<<8)|buf[13]);
}
void HMC5883LClass::getField(s_rawData* rawData)
{
uint8_t buf[6];
I2CInterface.readRegister(HMC5883L_ADDRESS, HMC5883L_RA_X_H, buf, 6);
rawData->mag_x = static_cast<int16_t>((buf[0] << 8) | buf[1]);
rawData->mag_z = static_cast<int16_t>((buf[2] << 8) | buf[3]);
rawData->mag_y = static_cast<int16_t>((buf[4] << 8) | buf[5]);
}
void MS5611Class::getPressure(int32_t *pressure) {
static int i = 0;
if(i == 3)
{ //Pressure is only updated every 4 cycles to keep conversion rate at 100Hz
if(lastConv_ == Pressure) { // 兩個會change
getRawPressure_();
startTempConversion_();
calculatePressure_(pressure);
lastConv_ = Temperature;
} else if(lastConv_ == Temperature) {
getRawTemperature_();
startPressureConversion_();
*pressure = P_;
lastConv_ = Pressure;
}
i = 0;
} else { // i= 0, 1 ,2
i++;
*pressure = P_;
}
}
// g = 9.81
void AHRSClass::calibrateData_() {
calibratedData.x = (rawData_.x * (9.81 / 4096.0));
calibratedData.y = (rawData_.y * (9.81 / 4096.0));
calibratedData.z = (rawData_.z * (9.81 / 4096.0));
calibratedData.temp = (rawData_.temp + 12412) / 340.0;
calibratedData.p = (rawData_.p / 65.5);
calibratedData.q = (rawData_.q / 65.5);
calibratedData.r = (rawData_.r / 65.5);
calibratedData.magx = rawData_.mag_x / 1090.0;
calibratedData.magy = rawData_.mag_y / 1090.0;
calibratedData.magz = rawData_.mag_z / 1090.0;
calibratedData.pressure = rawData_.pressure; //Pascals
calibratedData.altitude = ((-8.31447 * 288.15) / (9.80665 * 0.0289644)) * log(calibratedData.pressure / 101325);
calibratedData.q = -calibratedData.q;
//Accelerometer scale and bias correction
static double acceltemp[3];
acceltemp[0] = calibratedData.x - accelZeroX;
acceltemp[1] = calibratedData.y - accelZeroY;
acceltemp[2] = calibratedData.z - accelZeroZ;
calibratedData.x = accelEllipsoid00_ * acceltemp[0] + accelEllipsoid01_ * acceltemp[1] + accelEllipsoid02_ * acceltemp[2];
calibratedData.y = accelEllipsoid11_ * acceltemp[1] + accelEllipsoid12_ * acceltemp[2];
calibratedData.z = accelEllipsoid22_ * acceltemp[2];
//Magnetometer scale and bias correction
static double magtemp[3];
magtemp[0] = calibratedData.magx - magZeroX;
magtemp[1] = calibratedData.magy - magZeroY;
magtemp[2] = calibratedData.magz - magZeroZ;
calibratedData.magx = magEllipsoid00_ * magtemp[0] + magEllipsoid01_ * magtemp[1] + magEllipsoid02_ * magtemp[2];
calibratedData.magy = magEllipsoid11_ * magtemp[1] + magEllipsoid12_ * magtemp[2];
calibratedData.magz = magEllipsoid22_ * magtemp[2];
//Altitude LPF
#define LENGTH 20
static int i = 0;
static double mvAvg[LENGTH] = {0};
mvAvg[i] = calibratedData.altitude;
calibratedData.altitude = 0;
for(int k = 0; k < LENGTH; k++) {
calibratedData.altitude += mvAvg[k];
}
calibratedData.altitude /= LENGTH;
i++;
if(i == LENGTH) {
i = 0;
}
//End Altitude LPF
}
//Values calculated from matlab script MgnCalibration
const double accelZeroX = 0.2238;
const double accelZeroY = 0.1543;
const double accelZeroZ = -0.3633;
const double accelEllipsoid00_ = 0.1007;
const double accelEllipsoid01_ = -0.0007;
const double accelEllipsoid02_ = 0.0002;
const double accelEllipsoid11_ = 0.1020;
const double accelEllipsoid12_ = 0.0005;
const double accelEllipsoid22_ = 0.1003;
//Values calculated from matlab script MgnCalibration
const double magZeroX = 0.0576;
const double magZeroY = -0.0929;
const double magZeroZ = -0.0092;
const double magEllipsoid00_ = 1.8925;
const double magEllipsoid01_ = 0.0399;
const double magEllipsoid02_ = 0.0132;
const double magEllipsoid11_ = 1.8375;
const double magEllipsoid12_ = 0.0474;
const double magEllipsoid22_ = 2.1528;
void AHRSClass::temperatureCompensate_() {
static double tempPow1 = calibratedData.temp;
static double tempPow2 = pow(calibratedData.temp, 2);
static double tempPow3 = pow(calibratedData.temp, 3);
static double tempPow4 = pow(calibratedData.temp, 4);
//Coefficients calculated from freezetest4, 4th degree polynomial
calibratedData.p -= 8.4877e-9 * tempPow4 + 6.4219e-6 * tempPow3 + 2.5782e-4 * tempPow2 - 0.0041145 * tempPow1 - 1.2974;
calibratedData.q -= 5.863e-8 * tempPow4 - 5.9746e-6 * tempPow3 + 5.1324e-5 * tempPow2 + 0.0079355 * tempPow1 + 0.59859;
calibratedData.r -= 4.4929e-8 * tempPow4 - 1.6137e-7 * tempPow3 + 4.8876e-5 * tempPow2 + 0.021246 * tempPow1 - 2.9723;
//calibratedData.x -= -2.8664e-6 * tempPow2 + 4.9565e-4 * tempPow1; - 0.0011611;
//calibratedData.y -= 1.2728e-6 * tempPow2 + 6.5989e-6 * tempPow1; + 0.025702;
//calibratedData.z -= 1.6966e-5 * tempPow2 - 0.0035421 * tempPow1; + 0.056; //Z axis accel shows huge temperature drift (15% over 40 degrees)
}
void AHRSClass::fuse_() {
if(Timer.dt < 0.03)
{
quaternion = EKF.predict(&calibratedData, Timer.dt);
}
quaternion = EKF.update(&calibratedData, Timer.dt);
quaternionToYPR_(&quaternion, &orientation);
}
void AHRSClass::quaternionToYPR_(QuaternionClass* q, s_euler* orientation) {
orientation->pitch = -(180/pi) * atan2(2*(q->w*q->x + q->y*q->z), 1 - 2*(pow(q->x,2)+pow(q->y,2)));
orientation->roll = (180/pi) * asin(2*(q->w*q->y - q->z*q->x));
orientation->yaw = (180/pi) * atan2(2*(q->w*q->z + q->x*q->y), 1 - 2*(pow(q->y,2)+pow(q->z,2)));
}
5. Control.update();
void ControlClass::update() {
if(motorTesting_ == false) {
if(PICInterface.rx.sw2 == false) {//in rate mode
rateControl_(&PICInterface.rx.pitchRateDem, &PICInterface.rx.rollRateDem, &PICInterface.rx.yawRateDem); }
else if(PICInterface.rx.sw2 == true) { //in attitude mode
attitudeControl_(&PICInterface.rx.pitchDem, &PICInterface.rx.rollDem,
&PICInterface.rx.yawRateDem);
}
} else
{
incrementMotorTest_();
} // evaluateAltitudeControl_(); //Checks to see if altitude control if required, and performs //if necessary
} |
|
|
|
|
void ControlClass::rateControl_(float* pitchrate, float* rollrate, float* yawrate) {
ratePitchPID.calculate(&AHRS.calibratedData.p, pitchrate, &Timer.dt);
rateRollPID.calculate(&AHRS.calibratedData.q, rollrate, &Timer.dt);
rateYawPID.calculate(&AHRS.calibratedData.r, yawrate, &Timer.dt);
updatePWM_(&PICInterface.rx.throttleDem, &ratePitchPID.output, &rateRollPID.output, &rateYawPID.output);
}
void ControlClass::attitudeControl_(float* targetPitch, float* targetRoll, float* targetYawRate) {
attitudePitchPID.calculate(&AHRS.orientation.pitch, targetPitch, &Timer.dt);
attitudeRollPID.calculate(&AHRS.orientation.roll, targetRoll, &Timer.dt);
rateControl_(&attitudePitchPID.output, &attitudeRollPID.output, targetYawRate);
}
s_altitudePID altitudePID;
PIDClass ratePitchPID, rateRollPID, rateYawPID;
PIDClass attitudePitchPID, attitudeRollPID;
inline void ControlClass::updatePWM_(float* throttle, float* pitch, float* roll, float* yaw) {
四軸 : 1 -> frontleft... 2-> frontright... 3-> rearright.... 4-> rearleft
PICInterface.pwmwidths.frontleft = ((*throttle * (MOTOR_MAX - MOTOR_MIN)) + MOTOR_MIN) - *pitch + *roll - *yaw + altitudePID.output;
PICInterface.pwmwidths.frontright = ((*throttle * (MOTOR_MAX - MOTOR_MIN)) + MOTOR_MIN) - *pitch - *roll + *yaw + altitudePID.output;
PICInterface.pwmwidths.rearright = ((*throttle * (MOTOR_MAX - MOTOR_MIN)) + MOTOR_MIN) + *pitch - *roll - *yaw + altitudePID.output;
PICInterface.pwmwidths.rearleft = ((*throttle * (MOTOR_MAX - MOTOR_MIN)) + MOTOR_MIN) + *pitch + *roll + *yaw + altitudePID.output;
PICInterface.setPWM();
}
void PICInterfaceClass::setPWM() {
uint8_t widthsChar[13]; //+1 for pwm_fire bit
make8_(&pwmwidths.frontright, &widthsChar[0]);
make8_(&pwmwidths.rearright, &widthsChar[2]);
make8_(&pwmwidths.rearleft, &widthsChar[4]);
make8_(&pwmwidths.frontleft, &widthsChar[6]);
make8_(&pwmwidths.aux1, &widthsChar[8]);
make8_(&pwmwidths.aux2, &widthsChar[10]);
I2CInterface.writeRegister(PIC_ADDRESS, REG_PWM1H, widthsChar, 13);} |
6. LogMan.update(); // 紀錄log
void LoggerClass::update() {
if(logging) {
sampleno++;
log << sampleno << ", "
<< Timer.dt * 1000 << ", "
<< AHRS.calibratedData.x << ", "
<< AHRS.calibratedData.y << ", "
<< AHRS.calibratedData.z << ", "
<< AHRS.calibratedData.p << ", "
<< AHRS.calibratedData.q << ", "
<< AHRS.calibratedData.r << ", "
<< AHRS.calibratedData.temp << ", "
<< AHRS.calibratedData.magx << ", "
<< AHRS.calibratedData.magy << ", "
<< AHRS.calibratedData.magz << ", "
<< AHRS.calibratedData.pressure << ", "
<< AHRS.calibratedData.altitude << ", "
<< AHRS.orientation.pitch << ", "
<< AHRS.orientation.roll << ", "
<< AHRS.orientation.yaw << ", "
<< PICInterface.rx.pitchDem << ", "
<< PICInterface.rx.pitchRateDem << ", "
<< PICInterface.rx.rollDem << ", "
<< PICInterface.rx.rollRateDem << ", "
<< PICInterface.rx.throttleDem << ", "
<< PICInterface.rx.yawRateDem << ", "
<< PICInterface.rx.sw1 << ", "
<< PICInterface.rx.sw2 << ", "
<< PICInterface.pwmwidths.frontleft << ", "
<< PICInterface.pwmwidths.frontright << ", "
<< PICInterface.pwmwidths.rearleft << ", "
<< PICInterface.pwmwidths.rearright << ", "
<< Control.ratePitchPID.output << ", "
<< Control.rateRollPID.output << ", "
<< Control.rateYawPID.output << ", "
<< Control.attitudePitchPID.output << ", "
<< Control.attitudeRollPID.output << ", "
<< AHRS.quaternion.w << ", "
<< AHRS.quaternion.x << ", "
<< AHRS.quaternion.y << ", "
<< AHRS.quaternion.z //Add additional logs below
<< std::endl;
if(PICInterface.rx.sw1 == false) { doWeNeedToFlush(); }
}
} |
7. Timer.compensate_(); // 盡量讓某 400Hz 啟動timer 一次
inline void TimerClass::compensate_(){
//Timer aims to get as close to 400Hz as possible, mostly limited by the I2C bandwidth clock_gettime(CLOCK_MONOTONIC, &iterationtime_);
// iterationtime_ -> now time
// time_ -> old time
// ((iterationtime_.tv_sec * 1000000000 + iterationtime_.tv_nsec) - (time_.tv_sec * 1000000000 + time_.tv_nsec))
// -> processing time
long inttime = PERIOD - ((iterationtime_.tv_sec * 1000000000 + iterationtime_.tv_nsec) -
(time_.tv_sec * 1000000000 + time_.tv_nsec));
if (inttime < 0)
Timer.timeValue_.tv_nsec = 1;
else
Timer.timeValue_.tv_nsec = inttime;
Timer.timeToSet_.it_value = Timer.timeValue_;
timer_settime(timerId, 0, &timeToSet_, NULL);} |
8. pthread_mutex_unlock(&TimerMutex_); , 關閉 mutex...讓中斷可以啟動
|
沒有留言:
張貼留言