#include #define PROP_CONTROL #define INTEGRAL_CONTROL #define DIFF_CONTROL #define ULTRASOUND_CONTROL #define X_AXIS #define Y_AXIS //#define XPROP 0.0012 //#define YPROP 0.0012 /* #define XPROP 0.003 #define YPROP 0.003 #define MAX_PROP 13333 #define XINTEGRAL 0.0001 #define YINTEGRAL 0.0001 #define XDIFF 0.0011 #define YDIFF 0.0011 */ #define XPROP 0.0002 #define YPROP 0.0002 #define MAX_PROP 13333 #define XINTEGRAL 0.00001 #define YINTEGRAL 0.00001 #define XDIFF 0.0007 #define YDIFF 0.0007 #define ULTRASOUND_TARGET 13 #define ULTRASOUND_P 1 #define ULTRASOUND_ERROR_MAX 13 // minimum for speed controller is about 4% #define INIT_SPEED 200 #define ABSOLUTE_MIN 215 #define ABSOLUTE_MAX 625 //#define XTARGET -150 #define XTARGET -150 #define YTARGET -1750 //363 #define IDLE_THROTTLE 355 #define MOTOR1_OFFSET 0 #define MOTOR2_OFFSET 0 #define MOTOR3_OFFSET 0 #define MOTOR4_OFFSET 0 #define MOTOR1_IDLE (IDLE_THROTTLE + MOTOR1_OFFSET) #define MOTOR2_IDLE (IDLE_THROTTLE + MOTOR2_OFFSET) #define MOTOR3_IDLE (IDLE_THROTTLE + MOTOR3_OFFSET) #define MOTOR4_IDLE (IDLE_THROTTLE + MOTOR4_OFFSET) //#define SPEAKER_ENABLE #ifdef SPEAKER_ENABLE #define SPK_ON T2CON|=0x04; #define SPK_OFF T2CON&=(-0x04); #define SPK_TOG T2CON^=0x04; #endif code char __at __CONFIG1L conf1l = 0x30; code char __at __CONFIG1H conf1h = 0x02; code char __at __CONFIG2L conf2l = 0x3F; code char __at __CONFIG2H conf2h = 0x1E; code char __at __CONFIG3H conf3h = 0x81; code char __at __CONFIG4L conf4l = 0x81; code char __at __CONFIG5L conf5l = 0x0F; code char __at __CONFIG5H conf5h = 0xC8; code char __at __CONFIG6L conf6l = 0x0F; code char __at __CONFIG6H conf6h = 0xE0; code char __at __CONFIG7L conf7h = 0x0F; int MOTOR_DELTA; unsigned int TEMP_UNSIGNED; int XACCEL; int YACCEL; int LAST_XERROR; int LAST_YERROR; int INTEGRAL_YACCEL; int INTEGRAL_XACCEL; int XERROR; int YERROR; unsigned char ULTRASOUND; int ULTRASOUND_ERROR; int MOTOR1; int MOTOR2; int MOTOR3; int MOTOR4; unsigned char XPROP_P_FLAG; unsigned char XPROP_N_FLAG; unsigned char INIT_NUM; // these are changed inside and interupt and therefore must be declared volatile volatile unsigned char ESTOP; volatile unsigned char FLAG_NUM; volatile unsigned char FLAG_NUM2; int i; void Delay_ms(long ms); void Delay_4us(long us); /* * PORTA * RA0: X accel input * RA1: Y accel input * RA2: Ultrasound input * RA3: ESTOP LED output * * PORTB * RB0: Motor1 output * RB1: Motor2 output * RB2: Motor3 output * RB3: Motor4 output * RB4: R/C kill switch input * * */ //void high_isr(void) shadowregs interrupt; void main(void) { TRISA = 0x07; // set up RA0/AN0, RA1/AN1, and RA2/AN2 as inputs TRISB = 0x10; // set all of PORTB to be outputs, except for RB4 which reads the PWM kill switch input #ifdef SPEAKER_ENABLE PORTC = 0x00; TRISC = 0x00; PR2 = 0x80; CCPR1L = 0x40; CCP1CON = 0x0c; T2CON = 0x03; #endif ADCON0 = 0x01; // select AN0, enable A/D module ADCON1 = 0x0C; // set up RA0/AN0, RA1/AN1, and RA2/AN2 as an analog input and set up RA3..RA5 as digital I/Os ADCON2 = 0x2E; // configure A/D module result to left justified, acquisition time to 32 us, and clock period to 2.67 us INTCON = 0xC8; // Enable interupts and enable PORTB interupts INTCON2 = 0xD1; // INTEDG0 interupts on a PORTB rising edge, INTEDG1 interupts on a falling egde, interupt // is high priority T0CON = 0x88; // initialize Timer0 with no prescaler // Disable interrupts for init INTCONbits.RBIE = 0; ESTOP = 0; XERROR = 0; YERROR = 0; LAST_XERROR = 0; INTEGRAL_XACCEL = 0; LAST_YERROR = 0; INTEGRAL_YACCEL = 0; XPROP_P_FLAG = 0; XPROP_N_FLAG = 0; FLAG_NUM = 0; FLAG_NUM2 = 3; INIT_NUM = 0; ULTRASOUND = 0; ULTRASOUND_ERROR = 0; /* while (1) { // altitude: do A to D conversion on the ultrasound sensor ADCON0 = 0x0B; while (ADCON0bits.GO); // ULTRASOUND is an unsigned character ULTRASOUND = ADRESH; if (ULTRASOUND > 25) { PORTAbits.RA3 = 0; } else { PORTAbits.RA3 = 1; } } */ // controller init for (i=0;i<500;i++) { //send minimum throttle #ifdef X_AXIS // pulse for motor1 PORTBbits.RB0 = 1; Delay_4us(INIT_SPEED); PORTBbits.RB0 = 0; // pulse for motor2 PORTBbits.RB1 = 1; Delay_4us(INIT_SPEED); PORTBbits.RB1 = 0; #endif #ifdef Y_AXIS // pulse for motor3 PORTBbits.RB2 = 1; Delay_4us(INIT_SPEED); PORTBbits.RB2 = 0; // pulse for motor4 PORTBbits.RB3 = 1; Delay_4us(INIT_SPEED); PORTBbits.RB3 = 0; #endif //wait for the next pulse Delay_ms(11); //i = 501; } //ok, PIC and controller init is done while (1) { //now start up PID //first, do A to D conversion of the X axis (AN0) ADCON0 = 0x03; // select AN0 and set GO_DONE bit to start A/D conversion while (ADCON0bits.GO); // do nothing until the A/D conversion is done TEMP_UNSIGNED = ADRESH; TEMP_UNSIGNED = TEMP_UNSIGNED * 256; TEMP_UNSIGNED += ADRESL; XACCEL = TEMP_UNSIGNED - 32768; // A to D conversion on the Y axis ADCON0 = 0x07; while (ADCON0bits.GO); TEMP_UNSIGNED = ADRESH; TEMP_UNSIGNED = TEMP_UNSIGNED * 256; TEMP_UNSIGNED + ADRESL; YACCEL = TEMP_UNSIGNED - 32768; // altitude: do A to D conversion on the ultrasound sensor ADCON0 = 0x0B; while (ADCON0bits.GO); // ULTRASOUND is an unsigned character ULTRASOUND = ADRESH; MOTOR1 = MOTOR1_IDLE; MOTOR2 = MOTOR2_IDLE; MOTOR3 = MOTOR3_IDLE; MOTOR4 = MOTOR4_IDLE; //proprotional control #ifdef PROP_CONTROL XERROR = XACCEL - XTARGET; if (XERROR > MAX_PROP) { XERROR = MAX_PROP; } else if (XERROR < -MAX_PROP) { XERROR = -MAX_PROP; } // If XERROR > 0, we are rolling right MOTOR1 += XPROP * XERROR; MOTOR2 -= XPROP * XERROR; YERROR = YACCEL - YTARGET; // If YERROR > 0, we are pitching down MOTOR3 += YPROP * YERROR; MOTOR4 -= YPROP * YERROR; #endif // integral control #ifdef INTEGRAL_CONTROL INTEGRAL_XACCEL += XTARGET - XACCEL; INTEGRAL_YACCEL += YTARGET - YACCEL; MOTOR1 += XINTEGRAL * INTEGRAL_XACCEL; MOTOR2 -= XINTEGRAL * INTEGRAL_XACCEL; MOTOR3 += YINTEGRAL * INTEGRAL_YACCEL; MOTOR4 -= YINTEGRAL * INTEGRAL_YACCEL; #endif // differential control #ifdef DIFF_CONTROL // MOTOR_DELTA is the change in the error of the accelerometer MOTOR_DELTA = (XACCEL - XTARGET) - LAST_XERROR; MOTOR1 += XDIFF * MOTOR_DELTA; MOTOR2 -= XDIFF * MOTOR_DELTA; MOTOR_DELTA = (YACCEL - YTARGET) - LAST_YERROR; MOTOR3 += YDIFF * MOTOR_DELTA; MOTOR4 -= YDIFF * MOTOR_DELTA; LAST_XERROR = XACCEL - XTARGET; LAST_YERROR = YACCEL - YTARGET; #endif #ifdef ULTRASOUND_CONTROL ULTRASOUND_ERROR = ULTRASOUND - ULTRASOUND_TARGET; // Altitude PID control if (ULTRASOUND_ERROR > ULTRASOUND_ERROR_MAX) { ULTRASOUND_ERROR = ULTRASOUND_ERROR_MAX; } // Check to make sure that the craft is not tilted too much making the // altitude value unreliable if (XACCEL > 8000 || XACCEL < -8000 || YACCEL > 8000 || YACCEL < -8000) { // unreliable PORTAbits.RA3 = 1; } else { MOTOR1 -= ULTRASOUND_P * ULTRASOUND_ERROR; MOTOR2 -= ULTRASOUND_P * ULTRASOUND_ERROR; MOTOR3 -= ULTRASOUND_P * ULTRASOUND_ERROR; MOTOR4 -= ULTRASOUND_P * ULTRASOUND_ERROR; PORTAbits.RA3 = 0; } #endif // -------------------------- DO NOT SET MOTOR[1-4] BELOW THIS LINE -------------------------- // PID is done. Now convert those values into a signal that the speed controller can recieves // RB0 -- Motor 1 // RB1 -- Motor 2 // RB2 -- Motor 3 // RB3 -- Motor 4 // bounds checking if (MOTOR1 > ABSOLUTE_MAX) { MOTOR1 = ABSOLUTE_MAX; } else if (MOTOR1 < ABSOLUTE_MIN) { MOTOR1 = ABSOLUTE_MIN; } if (MOTOR2 > ABSOLUTE_MAX) { MOTOR2 = ABSOLUTE_MAX; } else if (MOTOR2 < ABSOLUTE_MIN) { MOTOR2 = ABSOLUTE_MIN; } if (MOTOR3 > ABSOLUTE_MAX) { MOTOR3 = ABSOLUTE_MAX; } else if (MOTOR3 < ABSOLUTE_MIN) { MOTOR3 = ABSOLUTE_MIN; } if (MOTOR4 > ABSOLUTE_MAX) { MOTOR4 = ABSOLUTE_MAX; } else if (MOTOR4 < ABSOLUTE_MIN) { MOTOR4 = ABSOLUTE_MIN; } // Check for emergency stop if (ESTOP != 0) { MOTOR1 = INIT_SPEED; MOTOR2 = INIT_SPEED; MOTOR3 = INIT_SPEED; MOTOR4 = INIT_SPEED; } // Protect the critical delays from interrupts INTCONbits.RBIE = 0; #ifdef X_AXIS // pulse for motor1 PORTBbits.RB0 = 1; Delay_4us(MOTOR1); PORTBbits.RB0 = 0; // pulse for motor2 PORTBbits.RB1 = 1; Delay_4us(MOTOR2); PORTBbits.RB1 = 0; #endif #ifdef Y_AXIS // pulse for motor3 PORTBbits.RB2 = 1; Delay_4us(MOTOR3); PORTBbits.RB2 = 0; // pulse for motor4 PORTBbits.RB3 = 1; Delay_4us(MOTOR4); PORTBbits.RB3 = 0; if (INIT_NUM > 15) { // reenable PORTB interrupts INTCONbits.RBIE = 1; } else { INIT_NUM ++; } //wait for the next pulse Delay_ms(13); #endif } } void isr_high (void) __interrupt(1) { unsigned char LOWER; unsigned char HIGHER; //check to see if it went high or low if (PORTBbits.RB4 == 0) { //we just went low //check the timer LOWER = TMR0L; HIGHER = TMR0H; if (HIGHER > 40 && HIGHER < 48) { if (FLAG_NUM >= 10) { // SHUTDOWN CONDITION ESTOP = 1; } else { FLAG_NUM ++; } } else { if (FLAG_NUM2 <= 0) { FLAG_NUM --; FLAG_NUM2 = 1; } else { FLAG_NUM2 --; } } TMR0L = 0x00; TMR0H = 0x00; } else { //we just went high //set the timer TMR0L = 0x00; TMR0H = 0x00; } //clear the PORTB interrupt bit INTCON = 0xC8; } void Delay_ms(long ms) { long i; while (ms--) for (i=0; i < 398; i++) ; } void Delay_4us(long us) { while (us--) ; }