Você está na página 1de 31

Self Balancing Scooter

Overview The BTWS is an electric driven scooter with an electronic for controlling and driving the system. The signal processing is done by an Atmel Atmega32 microcontroller. It shows how powerful, flexible and secure a so fast signal processing can be done with an AVR device.

1. Operating 2. Mechanics 3. System Control 4. Electronic 5. Schematics 6. Software 7. Part list 8. Flowcharts 9. Listing 10. Sources / References

1. Operating After switching on the unit, the electronics is in stand by mode. Through shift the handle into the verticality position, driving mode will be activated. The engines are powered and the equipment is balanced. Now you can ascend and drive off.

Pavner

2. Mechanics The basic construction exists of wood. You stand on the base plate firmly with a straight stick is connected. At the upper end of the stick a potentiometer - rocker is appropriate for the left / right steering. In the middle between the feet the lead acid batteries are stowed. Under the base plate a stiff axis is fastened on that the ball bearing wheels are fastened. The engines are fastened from below to the base plate and transferred her strength about a chain drive on the wheels. Sprockets with 72 teeth are screwed at the side onto the wheels. In midst the base plate the electronics is fastened.

Figure 1: mechanical construction

Photo 1: Motor Chain

Photo 2: Motor , Wheel

Pavner

Photo 3: Wheel

Photo 4: Bottom View

Photo 5: Complete

Pavner

3. System Control Control of the BTWS functions after the principle of the " dynamic stabilization ". This means that itself the vehicle balances independently. The functional way is as the human balance sense. Instead of inner ear, eyes, muscles and brain works a Gyro (Sensor for the angle rate) and an acceleration Sensor, a microprocessor ATMEGA32 and high power electric motors together to stabilize the balance. Forward and regression is reached by leaning forward and leaning back. A rocker that is placed at the upper end of the stick generates the Signal for the left right control.

Figure 2: BTWS System Block Diagram

Pavner

4. Electronic The electronics is placed on approx. 100 cm single layer printed circuit board. All signal processing and control is done by an ATMEGA32. The ATMEGA use his internal oscillator and his Brown-Out-Detection for the sure operation. For the power supply are two voltage regulators on the PCB. A voltage of 12 V is generated to supply the half bridges drivers. The second voltage regulator generates a voltage of 5 V with which the MCU and the sensors are supplied. The Gyro is placed in a rubber case and it is mounted on the PCB. The Gyro axis of rotation is parallel with the axis of the BTWS. The analog output of the Gyro has a normal voltage of approx. 2.5 V. With rotation the voltage changes according to the angle rate (25mV / deg / sec). The Signal is measured from an analog input of the MCU.

Photo 6: PCB Photo 7: PCB top side

Photo 8: PCB bottom side

Pavner

The acceleration Sensor ADXL311 is an SMD-component witch is soldered at the underside of the PCB. His normal voltage is likewise approx. 2.5 V. Only one axes of the two axis of the Sensor is used for the balance stabilization (acceleration in direction of the traffic). The source signal according to the acceleration matters not really. For the stabilization, the changing source signal is necessarily which is proportionally to the tilt angle change to the earth (approx. 5mV / degree). The signal is led on an analog input of the MCU and is measured. The benefit signal is won there by digital filtering.

Analog Devices ADXL311 Acceleration Sensor The ADXL311 is a low cost, low power, complete dual-axis accelerometer with signal conditioned voltage outputs, all on a single monolithic IC. The ADXL311 will measure acceleration with a full-scale range of 2 g. The ADXL311 can measure both dynamic acceleration (e.g., vibration) and static acceleration (e.g., gravity). The outputs are analog voltages proportional to acceleration. The typical noise floor is 300 g/Hz allowing signals below 2 mg (0.1 of inclination) to be resolved in tilt sensing applications using narrow bandwidths (10 Hz). The user selects the bandwidth of the accelerometer using capacitors CX and CY at the XFILT and YFILT pins. Bandwidths of 1 Hz to 2 kHz may be selected to suit the application. Product Information
1 2 3 4 5 2 Axis of Acceleration Sensing on a Single IC Chip 5 milli-g Resolution Low power > 0.5mA (ADXL311) BW Adjustment with a Single Capacitor +2.7V to +5.25V Single Supply Operation

Pavner

Panasonic EWTS4 Compact Angular Rate Sensor


This angular rate sensor utilizes Coriolis force generated by a vibrating tuning fork. This Sensor consists of sensing and driving elements, tuning fork driving circuit and the signal processing circuit. The tuning fork is composed of two metal pieces, a connecting block and four piezo-electric elements. A compact and reliable angular rate sensor has been realized. Operating Temperature Range -30 to 80 Supply Voltage Range 50.25 V Zero Point Voltage 2.50.4 V Sensitivity 25 mV/deg/s Output Voltage Range 0.3 to 4.7 V

Output Noise < 10 m Vp-p Figure 3: Gyro EWTS4 For steering the system, the potentiometer rocker is measured by an analog input. In normal position a voltage of 2.5 V will be here. With activity on the left, a voltage of approx. 0.5 V, and with activity on the right a voltage of approx. 4.5 V will be generated.

Photo 9: Rocker

Photo 10: Gyro EWTS4

The MCU generates two PWM, and two rotation direction signals for both electric motors. To reduce the peak current there is a phase shift from 180 between the PWM signals. The basic frequency of the PWM Signal was chosen with 15.5 kHz to have a low noise level for the environment. These signals are tied together by logic circuit and are given to the half bridge MOSFET driver. Two of these build a full bridge for any motor. The MOSFETS of the type IRF3205 (110 A / 8 mOhm) are strange enough to power the drive motors. A piezo sound generator is on the PCB to give warnings and weak batteries can be signaled.
Pavner

5. Schematics

Pavner

Pavner

10

6. Software Project is developed with the CodeVision AVR C-Compiler. The hole regulation is done in a interrupt routine. This function is called every 10 m Sec. The program works only with char, int and long integer variables and no floats to have best cycle time. The cycle time is approx. 1,3 mSec. The signal capture is very critical. To reach a good stabilization it is inevitably any time the correct tilt angle to earth is available. The signal of the acceleration Sensor must be integrated in addition for a long period to smooth the signal variations by accelerations. To this signal, the signal of the Gyro is added up. A quick and exact tilt angle measurement could be realized thus by adaptation of the factors by attempts.

Figure 4: Filter

Pavner

11

Balancement: The balancement is relatively easy, the hold stick bends after In front, the engines both are powered in the direction of forward. The feet are pushed by the feed again under the main focus of the body and a balance is reached. Moreover the necessary strength and speed can be determined only in the attempt and strongly hang together with the mechanically quality of the vehicle. If the teamwork of the forces is not properly it is able to oscillating and instabilities. Speed control: With every inclination of the hold stick the balance is produced and at the same time the basic speed a small part is changed in the direction of the inclination.

Speed limit: If the basic speed had reached too high, it would not be sometime any more possibly to balancement, because the voltage of electric motors already reached the highest value. To counteract against that, the basic speed is limited to 2/3 of the source voltage. With reach to the speed 2/3 a stronger feed impulse is generated in direction of the traffic, which generates then a light inclination to the back and reduces thus the driving speed. A good balancement is always given.

Steering: To steering the system the engines are driven with different voltages. The size of the differences is determined by the rocker signal and is depending on the driving speed. With high speeds only a small different steering control is allowed, because the curve radius then can be only very big.

Pavner

12

7. Part list Quantity 3 7 21 4 4 1 4 1 1 1 2 2 10 1 1 1 2 1 8 1 1 8 1 1 1 1 2 1 4 1 1 2 1 2 2 1 1 Price Price / EUR Pol. cap 0,20 0,60 Pol. cap 0,05 0,35 Ceramic C 0,01 0,21 Ceramic C 0,03 0,12 Diode 0,03 0,12 Gyro 25,00 25,00 IC 1,50 6,00 IC 0,30 0,30 IC 0,30 0,30 MCU 2,00 2,00 IC 0,20 0,40 LED 0,03 0,06 Resistor 0,01 0,10 Resistor 0,01 0,01 Resistor 0,01 0,01 Resistor 0,01 0,01 Resistor 0,01 0,02 Resistor 0,01 0,01 Resistor 0,01 0,08 Sensor 4,20 4,20 BUZZER 1,20 1,20 MOSFET 0,90 7,20 Connector 0,15 0,15 Connector 0,20 0,20 Connector 0,30 0,30 PCB 1,80 1,80 0,00 Motors MY-1016 250W / 14A /24V Unite 15,50 31,00 Motors Taiwan Rocker JC030 Peny & Giles 16,50 16,50 Battery 12V / 7,2Ah Panasonic Lead Acid 11,50 46,00 Fuse 40 Amps 1,00 1,00 0,00 Switch 1,50 1,50 Wheel 8,50 17,00 Axle 2,50 2,50 Sprockets 6,20 12,40 Chain 3,80 7,60 Wood 8,00 8,00 Small Parts 5,00 5,00 Total: 199,25 Value 470uF / 35V 4,7u / 35V 100n 470n SA158 Panasonic EWTS4 IR2184 MC7812 MC7805 MEGA32-A CD4001 LED3MM 4,7K 200k 10k 68K 330R 15R 4,7R ADXL311 F/TMB05 IRF3205 X-LPHS-10 AK500/2 AK500/3

Pavner

13

8. Flowcharts

Pavner

14

Pavner

15

Pavner

16

Pavner

17

Pavner

18

Pavner

19

Pavner

20

Pavner

21

9. Listing
/***************************************************** CodeVision AVR V1.24.1e Standard Copyright 1998-2004 Pavel Haiduc, HP InfoTech s.r.l. http://www.hpinfotech.ro e-mail:office@hpinfotech.ro Project : BTWS Version : 1.00 Date : 01.08.2006 Author : xxxxxx Comments: Chip type : ATmega32 Program type : Application Clock frequency : 8,000000 MHz Memory model : Small External SRAM size : 0 Data Stack size : 256 *****************************************************/ // includes #include <mega32.h> #include <delay.h> #include <math.h> #include <stdio.h>

// definitions #define FIRST_ADC_INPUT #define LAST_ADC_INPUT #define ADC_VREF_TYPE #define Drivesumlimit #define Overspeedlimit 0 6 0x40 // 2/3 of max drive speed

65000 40000

#define total_looptime 2000 // Looptime for filters #define ADXL_offset -5; // Stick Angle offset #define ADXL_ZERO 521 #define GYRO_ZERO 510 #define ROCKER_ZERO 512 #define ROCKER_DEADBAND 30 #define ON 1 #define OFF 0 #define Run 1 #define Standby 0 #define Batt25 #define Batt_low #define max_PWM #define PWM_A #define PWM_B #define AD_GYRO #define AD_ADXL #define AD_ROCKER #define AD_Batt #define CW_CCW_A 664 235 // AD Value at 25 Volts // 23,5 Volt

250 // The MOSFET Driver must have a little pulse for Operation OCR1AL OCR1BL adc_data[2] adc_data[0] adc_data[5] adc_data[6] PORTD.6

Pavner

22

#define CW_CCW_B #define LED1 #define LED2 #define BUZZER // global variables

PORTD.7 PORTC.2 PORTC.3 PORTC.1

unsigned int Voltage=0; unsigned char MODE=0; signed long total_ADXL_GYRO=0; signed long Average_Gyro=0; signed int DriveA=0; signed int DriveB=0; signed long buf1=0; signed int buf=0; signed int buf2=0; signed long Average_Batt=total_looptime*Batt25; signed int Tilt_ANGLE=0; signed int Drive_A=0; signed int Drive_B=0; signed int Drivespeed=0; signed int Steeringsignal=0; signed long Anglecorrection=0; signed int Angle_Rate=0; signed long Balance_moment=0; signed long Drive_sum=0; signed long Overspeed=0; signed long Overspeed_integral=0; bit bit Overspeed_flag=0; Batt_low_flag=0;

unsigned char intervalz=0; unsigned char interval=0; unsigned int adc_data[LAST_ADC_INPUT-FIRST_ADC_INPUT+1];

interrupt [ADC_INT] /* ----------------------------------------------------------------------------Function : adc_isr() ADC interrupt service routine with auto input scanning Date : 01.08.2006 ----------------------------------------------------------------------------*/ void adc_isr(void) { static unsigned char input_index=0; // Read the AD conversion result adc_data[input_index] = ADCW; // Select next ADC input if (++input_index > (LAST_ADC_INPUT - FIRST_ADC_INPUT))input_index = 0; ADMUX=(FIRST_ADC_INPUT | ADC_VREF_TYPE) + input_index; // Start the AD conversion ADCSRA |= 0x40; }

Pavner

23

/* ----------------------------------------------------------------------------Function : Get_Batt_Volt() calculate the Battery Voltage Date : 01.08.2006 ----------------------------------------------------------------------------*/ void Get_Batt_Volt() { buf = Average_Batt / total_looptime; Average_Batt -= buf; Average_Batt+=AD_Batt; Voltage=(Average_Batt*10)/80/Batt25; }

/* ----------------------------------------------------------------------------Function : Get_Tiltangle() calculate the Tilt Angle with a hand made Filter loop, calculate the Angle Rate Date : 01.08.2006

----------------------------------------------------------------------------*/ void Get_Tiltangle() { buf = total_ADXL_GYRO / total_looptime; total_ADXL_GYRO -= buf; // ADXL part buf = AD_ADXL-ADXL_ZERO + ADXL_offset; total_ADXL_GYRO += buf; // Gyro part buf1 = Average_Gyro / total_looptime; Average_Gyro -= buf1; Average_Gyro += AD_GYRO; buf1 = Average_Gyro / (total_looptime / 10); // calculate the Angle Rate buf1 = buf1 - AD_GYRO * 10; buf1 *= 35; buf1 /= 100; Angle_Rate = buf1; // calculate the Tilt Angle total_ADXL_GYRO += Angle_Rate; Tilt_ANGLE = total_ADXL_GYRO / (total_looptime / 10); }

Pavner

24

/* ----------------------------------------------------------------------------Function : Set_PWM() limiting and Setting the PWM Signals, and Set the Direction Pins Date : 01.08.2006 ----------------------------------------------------------------------------*/ void Set_PWM() { if(Drive_A > max_PWM)Drive_A = max_PWM; // limiting PWM Signal A if(Drive_A < -max_PWM)Drive_A = -max_PWM; // limiting PWM Signal A if(Drive_A < 0) { DriveA = Drive_A * -1; CW_CCW_A = 1; } else { DriveA = Drive_A; CW_CCW_A = 0; } PWM_A = 255 - DriveA; // Check direction // only positive // CW

// CCW // inverse Signal to have a Phase shift from 180 to Signal PWM B

if(Drive_B > max_PWM)Drive_B = max_PWM; // limiting PWM Signal B if(Drive_B < -max_PWM)Drive_B = -max_PWM; // limiting PWM Signal B if(Drive_B < 0) // Check direction { DriveB = Drive_B * -1; // only positive CW_CCW_B = 1; // CW } else { DriveB = Drive_B; CW_CCW_B = 0; // CCW } PWM_B = DriveB; // Set PWM }

Pavner

25

/* ----------------------------------------------------------------------------Function : Algorythmus() Limit top speed by tilting back, Calculate the Driving speed Date : 01.08.2006 ----------------------------------------------------------------------------*/ void Algorythmus() { Balance_moment = Angle_Rate*4 + 5 * (Tilt_ANGLE + Anglecorrection); Overspeed = lmax(0, Drive_sum - Overspeedlimit); if (Overspeed > 0) { if(MODE == Run)Overspeed_flag = 1; Overspeed_integral = lmin(1000, Overspeed_integral + min(500, Overspeed + 125)); // calculate over speed integral } else { Overspeed_flag = 0; Overspeed_integral = lmax(0, Overspeed_integral - 100); // calculate over speed integral } Anglecorrection = Overspeed / 200 + Overspeed_integral / 125; Drive_sum += Balance_moment; // limitting if(Drive_sum > Drivesumlimit)Drive_sum = Drivesumlimit; if(Drive_sum <- Drivesumlimit)Drive_sum =-Drivesumlimit; Drivespeed = Drive_sum / 250 + Balance_moment / 40; } // calculate Drive speed // calculate Angle correction // calculate balance moment // get over speed

// calculate Drive_sum

Pavner

26

/* ----------------------------------------------------------------------------Function : Signal_Processing() Generate Start condition, calculate the left / right steering signal Date : 01.08.2006 ----------------------------------------------------------------------------*/ void Signal_Processing() { if(MODE == Standby) // Standby Mode { Drive_A = 0; Drive_B = 0; Drivespeed=0; Anglecorrection=0; Overspeed=0; Overspeed_integral = 0; Drive_sum = 0; total_ADXL_GYRO = 0; Tilt_ANGLE = 0; Average_Gyro = total_looptime * GYRO_ZERO; buf2 = AD_ADXL - ADXL_ZERO + ADXL_offset; if(buf2 == 0) // The Stick is in Start position initial the System to run { MODE = Run; } } else // Run operation { Steeringsignal = ROCKER_ZERO - AD_ROCKER; // check Dead band if(Steeringsignal <- ROCKER_DEADBAND) { Steeringsignal += ROCKER_DEADBAND; } else { if(Steeringsignal > ROCKER_DEADBAND) { Steeringsignal -= ROCKER_DEADBAND; } else { Steeringsignal = 0; } } // calculate the signal to reduce the differential steering at higher Drive speed Steeringsignal *= 7; buf2 = Drivespeed; if(buf2 < 0)buf2 *= -1; buf2 /= 2; Steeringsignal /= (buf2 + 30); Drive_A = Drivespeed + Steeringsignal; Drive_B = Drivespeed - Steeringsignal; } } // differential Steering // differential Steering

// get the Steering Signal

Pavner

27

interrupt [TIM0_OVF] /* ----------------------------------------------------------------------------Function : timer0_ovf_isr() Timer loop every 10mSec Date : 01.08.2006 ----------------------------------------------------------------------------*/ void timer0_ovf_isr(void) { // RONitialize Timer 0 value TCNT0 = 0xB2; // 10mS Get_Batt_Volt(); Get_Tiltangle(); Algorythmus(); Signal_Processing(); Set_PWM(); intervalz++; if(intervalz>=20) // generate 200mSec. interval { intervalz=0; interval=~interval; } } /* ----------------------------------------------------------------------------Function : init() Initial the MCU Hardware Date : 01.08.2006 ----------------------------------------------------------------------------*/ void init() { // Input/Output Ports initialization // Port A initialization // Func7=In Func6=In Func5=In Func4=In Func3=In Func2=In Func1=In Func0=In // State7=T State6=T State5=T State4=T State3=T State2=T State1=T State0=T PORTA=0x00; DDRA=0x00; // Port B initialization // Func7=Out Func6=Out Func5=Out Func4=In Func3=In Func2=In Func1=Out Func0=Out // State7=1 State6=1 State5=1 State4=T State3=T State2=T State1=1 State0=0 PORTB=0xE2; DDRB=0xE3; // Port C initialization // Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out // State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0 PORTC=0x00; DDRC=0xFF; // Port D initialization // Func7=Out Func6=Out Func5=Out Func4=Out Func3=Out Func2=Out Func1=Out Func0=Out // State7=0 State6=0 State5=0 State4=0 State3=0 State2=0 State1=0 State0=0 PORTD=0x30; DDRD=0xFF; // Timer/Counter 0 initialization // Clock source: System Clock // Clock value: 7,813 kHz // Mode: Normal top=FFh // OC0 output: Disconnected

Pavner

28

TCCR0=0x05; TCNT0=0xB2; OCR0=0x00;

// Timer/Counter 1 initialization // Clock source: System Clock // Clock value: 8000,000 kHz // Mode: Ph. correct PWM top=00FFh // OC1A output: Non-Inv. // OC1B output: Inverted // Noise Canceler: Off // Input Capture on Falling Edge // Timer 1 Overflow Interrupt: Off // Input Capture Interrupt: Off // Compare A Match Interrupt: Off // Compare B Match Interrupt: Off TCCR1A=0xB1; TCCR1B=0x01; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0xff; OCR1BH=0x00; OCR1BL=0x00; // Timer/Counter 2 initialization // Clock source: System Clock // Clock value: Timer 2 Stopped // Mode: Normal top=FFh // OC2 output: Disconnected ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; // External Interrupt(s) initialization // INT0: Off // INT1: Off // INT2: Off MCUCR=0x00; MCUCSR=0x00; // Timer(s)/Counter(s) Interrupt(s) initialization TIMSK=0x01; // Analog Comparator initialization // Analog Comparator: Off // Analog Comparator Input Capture by Timer/Counter 1: Off // Analog Comparator Output: Off ACSR=0x80; SFIOR=0x00; // ADC initialization // ADC Clock frequency: 62,500 kHz // ADC Voltage Reference: AVCC pin // ADC High Speed Mode: Off // ADC Auto Trigger Source: None ADMUX=FIRST_ADC_INPUT|ADC_VREF_TYPE; ADCSRA=0xCF; SFIOR&=0xEF; }

Pavner

29

/* ----------------------------------------------------------------------------Function : main() Date : 01.08.2006 ----------------------------------------------------------------------------*/ void main(void) { init(); #asm("sei") delay_ms(500); while (1) { // Set debug LED's if(Drivespeed>240 || Drivespeed<-240) { LED1 = ON; } else { LED1 = OFF; } if(Drivespeed>180 || Drivespeed<-180) { LED2 = ON; } else { LED2 = OFF; } if(Voltage < Batt_low) { Batt_low_flag = interval; } else { Batt_low_flag = 0; } BUZZER = Overspeed_flag || Batt_low_flag; }; } // Global enable interrupts

Pavner

30

10. Sources / References

The MCU http://www.atmel.com Thanks to Trevor Blackwell for good ideas http://www.tlb.org/scooter.html Acceleration Sensors and Gyro Sensors http://www.analog.com/ The perfect system http://www.segway.com/ Balancing basics http://www.tedlarson.com/robots/balancingbot.htm Balancing one Wheel http://fhznet.fh-bielefeld.de/fb2/labor-le/le3einrad.html C-Compiler http://www.hpinfotech.ro Eagle Layout CAD http://www.cadsoft.de/

Pavner

31

Você também pode gostar