/*************************************************
* _ _ _ _ _ _
* | | | | |_ ___ ___| |_|___
* | | | | | -_| -_| | | -_|
* |_____|_|_|___|___|_|_|___|
*
**************************************************/
#ifndef F_CPU
#define F_CPU 16000000
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/eeprom.h>
#include "fifo.h"
#include "adc.h"
#include "ars.h"
#include "uart.h"
#include "i2cmaster.h"
//ADC Inputs
#define Ad_kanal_batt 0
#define Ad_kanal_zgyro 1
#define Ad_kanal_adxl 3
#define Ad_kanal_gyro 5
#define Ad_kanal_fuss 7
#define Ad_kanal_rocker 6
#define Ad_kanal_roll_adxl 2
#define Ad_kanal_roll_gyro 4
//maximum Power, limit to 20 for first Tests, then you don't destroy your furniture
#define max_PWM 180
//limit the I-Part of the PID-Control
#define Drivesumlimit 39000
//Calculate Wheel_const = circumference of the wheel in cm * 93,75 (f.e. 126 cm * 93,75 = 11812,5) for correct speed
#define Wheel_const 11812
//Status of the Wheelie
#define m_standby 1
#define m_run 2
#define m_down 3 //power down the wheels
//footswitch is pressed under this level
#define Sw_down 50
int drive_r = 0;
int drive_l = 0;
signed long Anglecorrection=0;
float Angle_Rate=0;
float Roll_Angle_Rate=0;
float Balance_moment=0;
float Drive_sum=0;
int Drivespeed=0;
int Rockersq=0;
int Rockerold=0;
int Rocker_zero=0;
int Rocker_diff=0;
int Speed_sum=0;
int Rocker_sensivity=0;
int Rocker_position=0;
int Speed_error=0;
int Speed_diff=0;
int Speed_correction=0;
int Steeringsignal=0;
//the I²C-Values are stored in this Array (Speed, Current L and R)
uint8_t Speed_array[8]={ 0,0,0,0,0,0,0,0} ;
uint16_t* Speed_array16 = (uint16_t*)Speed_array;
#define Speed_left Speed_array16[0]
#define Speed_right Speed_array16[1]
#define Curr_left Speed_array16[2]
#define Curr_right Speed_array16[3]
int Speed_left_out;
int Speed_right_out;
uint8_t cw_r;
uint8_t cw_l;
//This 6 values can controlled from the displayunit to improove PID and steering
int Parameter1=15; //Steering depends on speed higher Value, lower Steeringsignal
uint16_t P1 = 0x10;
int Parameter2=27; //Speederror from the Geartooths higher Value, lower Correction
uint16_t P2 = 0x20;
int Parameter3=210;
uint16_t P3 = 0x30;
int Parameter4=50; //Gain P-Part
uint16_t P4 = 0x40;
int Parameter5=215; //Gain I-Part
uint16_t P5 = 0x50;
int Parameter6=155; //Gain D-Part higher Value, lower Gain
uint16_t P6 = 0x60;
uint8_t Mmode = m_standby;
uint8_t Errno = 0;
uint8_t Zaehler = 0;
uint16_t spl = 0;
uint16_t Ad_gyro = 0;
uint16_t Ad_adxl = 0;
uint16_t Ad_batt = 0;
uint16_t Ad_adxl_roll = 0;
uint16_t Ad_gyro_roll = 0;
uint16_t Ad_rocker = 0;
uint16_t Ad_z = 0;
uint16_t Z_zero = 0;
int Z_diff = 0;
int Z_error = 0;
long Adxl_zero = 0;
long Roll_adxl_zero = 0;
long Gyro_zero = 0;
long Roll_gyro_zero = 0;
uint16_t Ad_swi = 0;
char Text[40];
char Inputstring[40];
uint8_t StringCounter = 0;
float roll_adxl_sensor = 0;
float adxl_sensor = 0;
float tilt_angle = 0.0;
float roll_angle = 0.0;
char s[20];
char t[20];
float dt;
struct Gyro1DKalman filter;
struct Gyro1DKalman filterX;
int x_error;
void Init(void);
void startup(void);
void set_pwm(void);
void uart_puts (const char *s);
int main(void);
void algo(void);
void Err_value(void);
void Steering(void);
void Process(void);
void Gear(void);
void Parser(void);
void saveData(void);
/******************************************************************
* Init:
*
* set the Registers
******************************************************************/
void Init(void)
{
DDRA = 0B00000000; // PA0..PA7: ADC // PA7 unbelegt
PORTA = 0; // no Pull-ups
DDRB = 0B00011100;
PORTB = 0B11100011;
DDRC = 0B00001100;
PORTC = 0B11111111;
DDRD = 0B11111010;
PORTD = 0B00000101;
TCCR0 |= (1<<WGM01);
OCR0 = 156; // 10ms Period
TCCR1A = 0xb1; //
TCCR1B = 0x01; //
OCR1AL = 255;
OCR1BL = 0;
Adc_init();
int i = 0;
for(i = 0;i<10;i++)
{
Ad_swi += ReadChannel(Ad_kanal_fuss);
_delay_ms(1);
}
Ad_swi /= 10;
if (Ad_swi < 100)
{
Errno = 4;
uart_puts ("2:11=14");
//Err_value();
}
i2c_init();
eeprom_read_block(&Parameter1,(uint8_t *)P1,sizeof(int));
if (Parameter1 == -1) //no Data in EEPROM
{
Parameter1 = 14; // write the Standardvalues to EEPROM
saveData();
}
else
{
eeprom_read_block(&Parameter2,(uint8_t *)P2,sizeof(int));
eeprom_read_block(&Parameter3,(uint8_t *)P3,sizeof(int));
eeprom_read_block(&Parameter4,(uint8_t *)P4,sizeof(int));
eeprom_read_block(&Parameter5,(uint8_t *)P5,sizeof(int));
eeprom_read_block(&Parameter6,(uint8_t *)P6,sizeof(int));
}
}
/*********************************************************************
* startup:
*
* calculate the zeropoints from the ADCs
*********************************************************************/
void startup(void)
{
int i = 0;
/*
Ad_rocker = 0;
Rocker_zero = 0;
for (i = 0; i<10; i++)
{
Rocker_zero += ReadChannel(Ad_kanal_rocker);
_delay_ms(3);
}
Rocker_zero /= 10;
*/
Rocker_zero = 434; //the rocker is exact vertical to ground
Ad_gyro = 0;
Gyro_zero = 0;
for (i = 0;i < 100;i++)
{
Gyro_zero += ReadChannel(Ad_kanal_gyro);
_delay_ms(3);
}
Gyro_zero /= i;
Ad_adxl = 0;
Adxl_zero = 0;
for (i = 0;i < 100;i++)
{
Adxl_zero += ReadChannel(Ad_kanal_adxl);
_delay_ms(3);
}
Adxl_zero /= i;
Ad_z = 0;
Z_zero = 0;
for (i = 0;i < 100;i++)
{
Z_zero += 1024 - ReadChannel(Ad_kanal_zgyro);
_delay_ms(3);
}
Z_zero /= i;
/*Ad_gyro_roll = 0;
Roll_gyro_zero = 0;
for (i = 0;i < 100;i++)
{
Roll_gyro_zero += (1024 - ReadChannel(Ad_kanal_roll_gyro));
_delay_ms(3);
}
Roll_gyro_zero /= i;
*/
Roll_gyro_zero = 505; //the platform is exact horizontal to ground
/*
Ad_adxl_roll = 0;
Roll_adxl_zero = 0;
for (i = 0;i < 100;i++)
{
Roll_adxl_zero += ReadChannel(Ad_kanal_roll_adxl);
_delay_ms(3);
}
Roll_adxl_zero /= i;
*/
Roll_adxl_zero = 513; //the platform is exact horizontal to ground
}
/************************************************************************
* main:
*
* Mainloop
************************************************************************/
int main(void)
{
Init();
startup();
PORTD &= ~(1 << PD3); //turn on 15V
uart_init();
init_Gyro1DKalman(&filter, 0.0001, 0.0003, 0.3);
init_Gyro1DKalman(&filterX, 0.0001, 0.0003, 0.3);
dt = 0.0157; // time passed in s since last call
sei();
while (1)
{
if ( Mmode != m_standby){
sprintf( Text, "2:1=%i\r\n", (int)Z_error );
uart_puts (Text);
_delay_ms(6);
sprintf( Text, "2:2=%i\r\n", (int)Steeringsignal);
uart_puts (Text);
_delay_ms(6);
sprintf( Text, "2:3=%i\r\n", (int)Drivespeed);
uart_puts (Text);
_delay_ms(6);
/* sprintf( Text, "2:4=%i\r\n", (int)roll_angle);
uart_puts (Text);
_delay_ms(6);
sprintf( Text, "2:5=%i\r\n", (int)x_error);
uart_puts (Text);
_delay_ms(6);
sprintf( Text, "2:6=%i\r\n", (int)Steeringsignal);
uart_puts (Text);
_delay_ms(6);*/
sprintf( Text, "2:7=%i\r\n", (int)drive_r);
uart_puts (Text);
_delay_ms(6);
sprintf( Text, "2:8=%i\r\n", (int)drive_l);
uart_puts (Text);
_delay_ms(6);
/*//sprintf( Text, "2:9=%i\r\n", (int)Speed_left_out);
//uart_puts (Text);
//_delay_ms(6);
//sprintf( Text, "2:10=%i\r\n", (int)Speed_right_out);
//uart_puts (Text);
//_delay_ms(6);
//sprintf( Text, "2:15=%i\r\n", (int)Curr_left);
//uart_puts (Text);
//_delay_ms(6);
//sprintf( Text, "2:16=%i\r\n", (int)Curr_right);
//uart_puts (Text);
_delay_ms(6);
}
else
{
/* sprintf( Text, "2:17=%i\r\n", (int)Parameter1);
uart_puts (Text);
_delay_ms(6);
sprintf( Text, "2:18=%i\r\n", (int)Parameter2);
uart_puts (Text);
_delay_ms(6);
sprintf( Text, "2:19=%i\r\n", (int)Parameter3);
uart_puts (Text);
_delay_ms(6);
sprintf( Text, "2:20=%i\r\n", (int)Parameter4);
uart_puts (Text);
_delay_ms(6);
sprintf( Text, "2:21=%i\r\n", (int)Parameter5);
uart_puts (Text);
_delay_ms(6);
sprintf( Text, "2:22=%i\r\n", (int)Parameter6);
uart_puts (Text);
Parser();
_delay_ms(6);*/
}
Process();
sprintf( Text, "2:12=%i\r\n", (int)Ad_batt);
//uart_puts (Text);
_delay_ms(6);
}
}
/***************************************************************
* ISR:
*
* Interrupt all 10ms
***************************************************************/
ISR(TIMER0_COMP_vect)
{
//get all values from the ADCs
Ad_gyro = ReadChannel(Ad_kanal_gyro);
Ad_adxl = ReadChannel(Ad_kanal_adxl);
Ad_z = 1024 - ReadChannel(Ad_kanal_zgyro);
Ad_adxl_roll = ReadChannel(Ad_kanal_roll_adxl);
Ad_gyro_roll = 1024 - ReadChannel(Ad_kanal_roll_gyro);
Ad_rocker = ReadChannel(Ad_kanal_rocker);
Ad_swi = 1024 - ReadChannel(Ad_kanal_fuss);
Ad_batt = ReadChannel(Ad_kanal_batt);
//kill the offset and calculate the Gains, so that all values are ° or °/s
// 3.0V/1025/0.002V for IDG300
Angle_Rate = (float)(Ad_gyro-Gyro_zero)* 1.4634135;
Roll_Angle_Rate = (float)(Ad_gyro_roll-Roll_gyro_zero)* 1.4634135;
// 3.0V/1025/0.0019333V 0,348V for 180° = 1,9333mV per ° for ADXL320
// 3.0V/1025/0.0046666V 0,840V for 180° = 4,6666mV per ° for ADXL322
adxl_sensor = ((float)(Ad_adxl-Adxl_zero))* 1.5139;
roll_adxl_sensor = ((float)(Ad_adxl_roll-Roll_adxl_zero))* 1.5139;
//the two Kalman steps: predict and update
ars_predict(&filter, Angle_Rate, dt); // Kalman predict *0.62719;
ars_predict(&filterX, Roll_Angle_Rate, dt); // Kalman predict *0.62719;
tilt_angle = ars_update(&filter, adxl_sensor);
roll_angle = ars_update(&filterX, roll_adxl_sensor) * 2.6; //Anpassung ans Lenkerpoti
//Z-Axis
Z_diff = Ad_z - Z_zero ;
Z_error = Ad_z - Z_zero ;
algo();
Gear();
Steering();
set_pwm();
}
/**************************************************************************
* algo:
*
* PID-Controller
***************************************************************************/
void algo(void)
{
Balance_moment = Angle_Rate * Parameter5 / 100 + tilt_angle; //Angle_Rate is D-Part, tilt_angle is P-Part of the PID-Controller
Balance_moment = Balance_moment * 29;
//The I-Part of the PID-Controller
Drive_sum += Balance_moment;
if(Drive_sum > Drivesumlimit)Drive_sum = Drivesumlimit; //you have to limit the I-Controller
if(Drive_sum <- Drivesumlimit)Drive_sum =-Drivesumlimit; //Drive_sum max = 255*150
Drivespeed = Drive_sum / Parameter6 + Balance_moment / 165;
}
/**************************************************************************
* Gear:
*
* get Speed from the Geartoothsensors
**************************************************************************/
void Gear(void)
{
uint8_t i = 0;
i2c_start_wait(0x41);
for (i=0;i<7;i++) // get the 8 Bytes from the I2C-Slave
{
Speed_array[i] = i2c_readAck();
}
Speed_array[i] = i2c_readNak();
i2c_stop();
//calculate Speed*10
Speed_left = Wheel_const / Speed_left;
Speed_right = Wheel_const / Speed_right;
//so eine Kacke! Ich muß unbedingt die Drehrichtung der Räder messen!!
if (Speed_left < 250) //value over 25km/h must be wrong, so ignore it
{
if ( cw_l == 1 ) Speed_left_out = Speed_left * -1;
else Speed_left_out = Speed_left;
}
if (Speed_right < 250)
{
if ( cw_r == 1 ) Speed_right_out = Speed_right * -1;
else Speed_right_out = Speed_right;
}
Speed_sum -= Speed_sum / 5;
Speed_sum += Speed_right_out + Speed_left_out;
Speed_diff -= Speed_diff / 5;
Speed_diff += Speed_left_out - Speed_right_out;
Speed_correction = Speed_diff / Parameter2;
}
/****************************************************************************
* Steering:
*
* calculate the steering
****************************************************************************/
void Steering(void)
{
int Buf1;
Rockersq = Rocker_zero - Ad_rocker + (int)roll_angle;
x_error = Rockersq;
Buf1 = abs(Speed_sum / 70);
if (Buf1 > 20) Buf1 = 20;
Rocker_sensivity = 22 - Buf1;
Rocker_sensivity = Rocker_sensivity / 2;
if (Rockersq > 45) Rockersq = 45;
if (Rockersq < -45) Rockersq = -45;
Rocker_position = Rockersq;
Rockersq = Rockersq * Rocker_sensivity;
Rockersq = Rockersq / Parameter1;
Speed_error = Rockersq - Speed_correction;
if (Speed_error > 40) Speed_error = 40;
if (Speed_error < -40) Speed_error = -40;
Steeringsignal = Rockersq + Speed_error + Z_error;
drive_r = Drivespeed - Steeringsignal;
drive_l = Drivespeed + Steeringsignal;
}
/********************************************************************************
* Process:
*
* get and set the Status
********************************************************************************/
void Process(void)
{
int i;
switch(Mmode)
{
case m_standby:
drive_l = 0;
drive_r = 0;
Drivespeed = 0;
Drive_sum = 0;
set_pwm();
sprintf( Text, "2:11=Standby\r\n");
uart_puts (Text);
Ad_swi = 1024 - ReadChannel(Ad_kanal_fuss);
Ad_batt = ReadChannel(Ad_kanal_batt);
if (Ad_swi > Sw_down){
startup();
TCNT0 = 0;
TCCR0 |= (1<<CS00)|(1<<CS02)|(1<<WGM01); //Timer0 starten
TIMSK |= (1<<OCIE0); // enable Interrupt
Mmode = m_run;
sprintf( Text, "2:11=Drive!\r\n");
uart_puts (Text);
}
break;
case m_run:
if (Ad_swi < Sw_down) {Mmode = m_down;}
break;
case m_down:
TCCR0 &= ~(1<<CS00)|(1<<CS02)|(1<<WGM01); //Timer0 ausschalten
TIMSK &= ~(1<<OCIE0); // enable Interrupt
for(i = 0; i < 255; i++)
{
if (drive_l == 0 && drive_r == 0) {goto Shutdown;}
if (drive_l > 0) { drive_l--;}
if (drive_l < 0) { drive_l++;}
if (drive_r > 0) { drive_r--;}
if (drive_r < 0) { drive_r++;}
_delay_ms(25);
set_pwm();
}
Shutdown:
Mmode = m_standby;
break;
default:
Mmode = m_down;
}
}
/**********************************************************************************
* set_pwm:
*
* set the PWMs and the Directionbits
***********************************************************************************/
void set_pwm(void)
{
int l = 0;
int r = 0;
//drive_l = 0;
//drive_r = 0;
if(drive_l > max_PWM)drive_l = max_PWM;
if(drive_l < -max_PWM)drive_l = -max_PWM;
if(drive_r > max_PWM)drive_r = max_PWM;
if(drive_r < -max_PWM)drive_r = -max_PWM;
r = abs(drive_r);
l = abs(drive_l);
if(drive_r < 0) // Check direction
{
PORTD |= (1<<PD6);
cw_r = 1;
}
else
{
PORTD &= ~(1<<PD6);
cw_r = 0;
}
if(drive_l < 0) // Check direction
{
PORTD |= (1<<PD7);
cw_l = 1;
}
else
{
PORTD &= ~(1<<PD7);
cw_l = 0;
}
OCR1AL = 255 - r;
OCR1BL = l;
}
/********************************************************************************
* Err_value:
*
* throw the program in an black whole
********************************************************************************/
void Err_value(void)
{
while(1) { _delay_ms(2000);}
}
/********************************************************************************
* Parser:
*
* get Commands from USART
********************************************************************************/
void Parser(void)
{
char *ptr;
char delimiter[] = ":=";
uint8_t Channel;
int Wert;
int NextChar;
NextChar = uart_getc_nowait();
while(NextChar != 10 && NextChar !=-1 && StringCounter < 40)
{
if (NextChar != '\0' && NextChar != 13) {Inputstring[StringCounter++] = (unsigned char)NextChar;}
NextChar = uart_getc_nowait();
}
if (NextChar == 10)
{
if (Inputstring[1] != 58 || StringCounter > 39) {goto Ausgang;}
Inputstring[StringCounter++] = '\0';
ptr = strtok(Inputstring, delimiter);
if(ptr != NULL)
{
if (atoi(ptr)==0)
{
ptr = strtok(NULL, delimiter);
Channel = atoi(ptr);
ptr = strtok(NULL, delimiter);
Wert = atoi(ptr);
if (Channel == 17) Parameter1 = Wert;
if (Channel == 18) Parameter2 = Wert;
if (Channel == 19) Parameter3 = Wert;
if (Channel == 20) Parameter4 = Wert;
if (Channel == 21) Parameter5 = Wert;
if (Channel == 22) Parameter6 = Wert;
if (Channel == 16)
{
saveData();
sprintf( Text, "2:11=STORED!\r\n");
uart_puts (Text);
_delay_ms(500);
Zaehler =0;
}
}
}
Ausgang:
Inputstring[0] = '\0';
StringCounter = 0;
}
}
/***************************************************************************************
* saveData:
*
* store all Parameters in EEPROM
***************************************************************************************/
void saveData(void)
{
eeprom_write_block(&Parameter1,(uint8_t *)P1,sizeof(int));
eeprom_write_block(&Parameter2,(uint8_t *)P2,sizeof(int));
eeprom_write_block(&Parameter3,(uint8_t *)P3,sizeof(int));
eeprom_write_block(&Parameter4,(uint8_t *)P4,sizeof(int));
eeprom_write_block(&Parameter5,(uint8_t *)P5,sizeof(int));
eeprom_write_block(&Parameter6,(uint8_t *)P6,sizeof(int));
}