sam7fc/src/flightctrl.c

265 lines
9.1 KiB
C
Raw Permalink Normal View History

2008-06-23 15:33:07 +02:00
/***************************************************************************
* sam7fc - Flight Control *
* *
* Copyright (C) 03/2008 by Olaf Rempel *
* razzor@kopf-tisch.de *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; version 2 of the License *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
***************************************************************************/
#include <stdio.h>
#include <stdlib.h> /* abs() */
#include "AT91SAM7S256.h"
#include "board.h"
#include <at91_adc.h>
#include <at91_pitc.h>
#include <at91_tc1.h>
#include <at91_twi.h>
#include <telemetrie.h>
#include <pidctrl.h>
static uint32_t global_state;
#define MOTOR_RUNNING 0x0001
#define MOTOR_MIXER_ENABLE 0x0002
#define STICK_CALIBRATION 0x0004
#define STICK_CALIBRATION_COMPLETE 0x0008
static struct pid_data pid_nick = {
.kp = 1,
.ki = 0,
.err_sum_max = +1024,
.err_sum_min = -1024,
.out_max = +256,
.out_min = -256,
};
TDC_PTR(pid_nick_ki, &pid_nick.ki, "flctrl: pid nick ki", int32_t, TDC_SIGNED);
TDC_PTR(pid_nick_errsum, &pid_nick.err_sum, "flctrl: pid nick errsum", int32_t, TDC_SIGNED | TDC_READONLY);
static struct pid_data pid_roll = {
.kp = 1,
.ki = 0,
.err_sum_max = +1024,
.err_sum_min = -1024,
.out_max = +256,
.out_min = -256,
};
TDC_PTR(pid_roll_ki, &pid_roll.ki, "flctrl: pid roll ki", int32_t, TDC_SIGNED);
TDC_PTR(pid_roll_errsum, &pid_roll.err_sum, "flctrl: pid roll errsum", int32_t, TDC_SIGNED | TDC_READONLY);
static struct pid_data pid_gier = {
.kp = 1,
.ki = 0,
.err_sum_max = +1024,
.err_sum_min = -1024,
.out_max = +256,
.out_min = -256,
};
TDC_PTR(pid_gier_ki, &pid_gier.ki, "flctrl: pid gier ki", int32_t, TDC_SIGNED);
TDC_PTR(pid_gier_errsum, &pid_gier.err_sum, "flctrl: pid gier errsum", int32_t, TDC_SIGNED | TDC_READONLY);
static void motor_mixer(int32_t gas, int32_t nick, int32_t roll, int32_t gier)
{
static uint8_t pwm[4];
TDC_VALUE(pwm0, pwm[0], "Motor PWM 1", uint8_t, TDC_UNSIGNED | TDC_READONLY);
TDC_VALUE(pwm1, pwm[1], "Motor PWM 2", uint8_t, TDC_UNSIGNED | TDC_READONLY);
TDC_VALUE(pwm2, pwm[2], "Motor PWM 3", uint8_t, TDC_UNSIGNED | TDC_READONLY);
TDC_VALUE(pwm3, pwm[3], "Motor PWM 4", uint8_t, TDC_UNSIGNED | TDC_READONLY);
pwm[0] = LIMIT((gas - nick + gier), 0x0F, 0xFF);
pwm[1] = LIMIT((gas + nick + gier), 0x0F, 0xFF);
pwm[2] = LIMIT((gas + roll - gier), 0x0F, 0xFF);
pwm[3] = LIMIT((gas - roll - gier), 0x0F, 0xFF);
if (!(global_state & MOTOR_RUNNING)) {
pwm[0] = 0x00;
pwm[1] = 0x00;
pwm[2] = 0x00;
pwm[3] = 0x00;
} else if (!(global_state & MOTOR_MIXER_ENABLE)) {
pwm[0] = 0x0F;
pwm[1] = 0x0F;
pwm[2] = 0x0F;
pwm[3] = 0x0F;
}
twi_setpwm(pwm);
}
static uint32_t base_ctrl_cb(struct pitc_timer *timer)
{
if (global_state & STICK_CALIBRATION)
global_state |= STICK_CALIBRATION_COMPLETE;
return PITC_REMOVE_TIMER;
}
static struct pitc_timer base_ctrl_timer = {
.func = base_ctrl_cb,
};
void base_ctrl(void)
{
static int32_t nick_integral, roll_integral, gier_integral;
/* get stick switches & values */
struct rc_values rc_sw;
uint32_t count = rcontrol_getswitches(&rc_sw);
if (count < 4) {
global_state &= ~MOTOR_RUNNING;
} else if (global_state & STICK_CALIBRATION_COMPLETE) {
// rcontrol_calibrate(RC_CAL_END);
// rcontrol_calibrate(RC_CAL_SAVE);
rcontrol_print_cal();
global_state &= ~(STICK_CALIBRATION | STICK_CALIBRATION_COMPLETE);
} else if (global_state & STICK_CALIBRATION) {
/* do nothing during calibration */
} else if (count >= 4) {
/* Motor stop */
if (rc_sw.chan[2] < 0 && rc_sw.chan[3] > 0)
global_state &= ~MOTOR_RUNNING;
/* Motor start */
if (rc_sw.chan[2] < 0 && rc_sw.chan[3] < 0)
global_state |= MOTOR_RUNNING;
/* Gyro calibration */
if (rc_sw.chan[2] > 0 && rc_sw.chan[3] > 0)
adc_calibrate(ADC_CAL_GYRO);
/* ACC + Stick calibration */
if (rc_sw.chan[2] > 0 && rc_sw.chan[3] < 0) {
adc_calibrate(ADC_CAL_ACC);
// rcontrol_calibrate(RC_CAL_START);
global_state |= STICK_CALIBRATION;
base_ctrl_timer.interval = 1000;
pitc_schedule_timer(&base_ctrl_timer);
}
}
struct rc_values rc;
rcontrol_getvalues(&rc);
if (rc.chan[2] < 15) {
global_state &= ~MOTOR_MIXER_ENABLE;
/* reset integrals */
nick_integral = roll_integral = gier_integral = 0;
pid_nick.err_sum = pid_roll.err_sum = pid_gier.err_sum = 0;
} else {
global_state |= MOTOR_MIXER_ENABLE;
}
/* get adc results */
static int16_t adc_result[7];
TDC_PTR(adc_result0, &adc_result[ADC_GYRO_NICK], "ADC_GYRO_NICK", int16_t, TDC_SIGNED | TDC_READONLY);
TDC_PTR(adc_result1, &adc_result[ADC_GYRO_ROLL], "ADC_GYRO_ROLL", int16_t, TDC_SIGNED | TDC_READONLY);
TDC_PTR(adc_result2, &adc_result[ADC_GYRO_GIER], "ADC_GYRO_GIER", int16_t, TDC_SIGNED | TDC_READONLY);
TDC_PTR(adc_result3, &adc_result[ADC_ACC_NICK], "ADC_ACC_NICK", int16_t, TDC_SIGNED | TDC_READONLY);
TDC_PTR(adc_result4, &adc_result[ADC_ACC_ROLL], "ADC_ACC_ROLL", int16_t, TDC_SIGNED | TDC_READONLY);
TDC_PTR(adc_result5, &adc_result[ADC_ACC_GIER], "ADC_ACC_GIER", int16_t, TDC_SIGNED | TDC_READONLY);
TDC_PTR(adc_result6, &adc_result[ADC_VOLTAGE], "ADC_VOLTAGE", int16_t, TDC_SIGNED | TDC_READONLY);
adc_get_results(adc_result);
if (count != 0 && adc_result[ADC_VOLTAGE] > 960)
*AT91C_PIOA_CODR = LED_GREEN;
else
*AT91C_PIOA_SODR = LED_GREEN;
nick_integral += adc_result[ADC_GYRO_NICK];
TDC_INT32(nick_integral, "flctrl: Base Integral Nick");
roll_integral += adc_result[ADC_GYRO_ROLL];
TDC_INT32(roll_integral, "flctrl: Base Integral Roll");
gier_integral += adc_result[ADC_GYRO_GIER];
TDC_INT32(gier_integral, "flctrl: Base Integral Gier");
static int32_t integral_gyro_mix = 1;
TDC_INT32(integral_gyro_mix, "flctrl: Mix Integral/ACC (0-1024)");
static int32_t acc_faktor = 300;
TDC_INT32(acc_faktor, "flctrl: Mix Faktor");
/*
* 90<EFBFBD> -> ADC_ACC_* ~210
* 90<EFBFBD> -> Integral ~60000
*/
int32_t mix_integral = 1024 - integral_gyro_mix;
int32_t mix_acc = integral_gyro_mix * acc_faktor;
nick_integral = ((nick_integral * mix_integral) + (adc_result[ADC_ACC_NICK] * mix_acc)) / 1024;
roll_integral = ((roll_integral * mix_integral) + (adc_result[ADC_ACC_ROLL] * mix_acc)) / 1024;
/*
* hoher gyro_faktor -> bessere stabilit<EFBFBD>t, aber langsames zur<EFBFBD>ckkehren nach vollausschlag
* niedriger integral_faktor -> geringere abweichungbei einseitigem anheben, aber schwingungsanf<EFBFBD>lliger
*/
static int32_t integral_faktor = 256;
static int32_t gyro_faktor = 4;
TDC_INT32(integral_faktor, "flctrl: Integral Divisior");
TDC_INT32(gyro_faktor, "flctrl: Integral Gyro Faktor /16");
static int32_t nick;
static int32_t roll;
static int32_t gier;
nick = (nick_integral / integral_faktor) + (adc_result[ADC_GYRO_NICK] * gyro_faktor) / 16;
roll = (roll_integral / integral_faktor) + (adc_result[ADC_GYRO_ROLL] * gyro_faktor) / 16;
gier = (gier_integral / integral_faktor) + (adc_result[ADC_GYRO_GIER] * gyro_faktor) / 16;
TDC_INT32_RO(nick, "flctrl: Integral + Gyro Nick");
TDC_INT32_RO(roll, "flctrl: Integral + Gyro Roll");
TDC_INT32_RO(gier, "flctrl: Integral + Gyro Gier");
static int32_t stick_kp = 8;
TDC_INT32(stick_kp, "flctrl: Stick-P /16");
static int32_t stick_gas, stick_nick, stick_roll, stick_gier;
stick_gas = rc.chan[2];
stick_nick = (rc.chan[0] * stick_kp) / 16;
stick_roll = (rc.chan[1] * stick_kp) / 16;
stick_gier = rc.chan[3] / 4;
TDC_INT32_RO(stick_gas, "Stick Gas");
TDC_INT32_RO(stick_nick, "Stick Nick");
TDC_INT32_RO(stick_roll, "Stick Roll");
TDC_INT32_RO(stick_gier, "Stick Gier");
static int32_t gier_kp = 32;
TDC_INT32(gier_kp, "flctrl: Gier-P (/256)");
gier_integral -= gier_kp * stick_gier * abs(stick_gier) / 256;
static int32_t mixer_gas, mixer_nick, mixer_roll, mixer_gier;
mixer_gas = stick_gas;
mixer_nick = pid_ctrl(&pid_nick, stick_nick - nick);
mixer_roll = pid_ctrl(&pid_roll, stick_roll - roll);
mixer_gier = pid_ctrl(&pid_gier, stick_gier - gier);
/* mix gas/nick/roll/gier -> 4 motors */
motor_mixer(mixer_gas, mixer_nick, mixer_roll, mixer_gier);
TDC_INT32_RO(mixer_gas, "Mixer Gas");
TDC_INT32_RO(mixer_nick, "Mixer Nick");
TDC_INT32_RO(mixer_roll, "Mixer Roll");
TDC_INT32_RO(mixer_gier, "Mixer Gier");
}