265 lines
9.1 KiB
C
265 lines
9.1 KiB
C
/***************************************************************************
|
||
* 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<39> -> ADC_ACC_* ~210
|
||
* 90<39> -> 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<69>t, aber langsames zur<75>ckkehren nach vollausschlag
|
||
* niedriger integral_faktor -> geringere abweichungbei einseitigem anheben, aber schwingungsanf<6E>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");
|
||
}
|