Microcontroller-Driven Lego Vehicle by Lego Norhalim & Mahadzir
Introduction
For the final project, we designed a Microcontroller-driven Lego Vehicle (MLV). This project makes use of the ATMEL AT90S8535 8-bit RISC microcontroller unit. The microcontroller basically functions to determine the user input through button pushes, drive the DC and stepper motors to provide motion to the MLV as well as to set the speed of the vehicle through the use of the onboard Analog-to-Digital converter.
Our project involves a combination of hardware and software design. The hardware part includes building the mechanical model for the MLV and circuitry to drive the DC and stepper motors by providing the necessary power and voltage level, as well as providing electrical protection for the microcontroller unit. The software part involves designing the state machine for the steering and motion control of the MLV, providing the stepping sequence for the stepper motor and controlling the LED signals.
Features
6-button Input System
Steer Left, Steer Right, Forward, Reverse, Stop, Raise and Lower Tray.
2 Stepper Motors and a DC Motor
DC motor provides the forward and reverse movements while the 2 stepper motors are used to provide steering and raising/lowering camera mount rack respectively.
Speed control
Increase or decrease the speed of the vehicle by adjusting the trim-pot knob.
Light Indicator for different movements of the vehicle
Left and right blinking signal, forward and reverse and park light.
Planetary Gear System
Planetary gear system for forward and reverse movement for higher torque.
Differential Wheel System
High Level Design
The Microcontroller-driven Lego Vehicle (MLV) begins in a 'parking' condition where all of the motors sit idle and the stop lights turn on. It then wait for a user input through a button push. If the Forward button is pushed, the MLV moves forward and the forward headlights turn on. If the Reverse button is pushed, the MLV moves backward and the reverse lights turn on. Note however if the MLV is moving forward and the Reverse button is pushed, nothing will happen. The same goes when the MLV is going in reverse and the Forward button is pushed. This is done as a safety measure to protect the mechanical part of the vehicle. Pushing the left or right steering button makes the front wheel of the vehicle turn in the appropriate direction. Pushing the Raise and Lower button raises and lowers the camera mount. Steer Left or Right and Raise or Lower buttons produce motion when the vehicle is moving forward, backward or in a parking condition.
Software Design
We started our design by first figuring out the state transition diagram for the MLV. There are three states: stop, forward and reverse. We used a branch table to implement the state machine. In each state, the microcontroller sends different signals to the ports. At the same time, it also checks for 'steering' (for turning the front wheel right and left) and 'hand' (for moving the camera mounting up and down) button press if any by calling the appropriate subroutines.
(1) State: Stop
In this state, the MLV is not moving. The microcontroller turns off both the forward and the reverse switch, and lights up two LEDs to indicate this state. It then calls the 'steering' and 'hand' button press. If any of the four buttons (right and left for 'steering', and up and down for 'hand') is pressed, it executes the appropriate subroutine. After that it checks for 'forward' and 'reverse' button press. If any of these two buttons is pressed, it loads the new state before jumping back to the branch table.
(2) State: Forward In this state, the mictrocontroller first gets the ADC reading to determine the speed. Then it turns on the forward switches and lights up two LEDs to indicate that the MLV is in the forward state. Then, it calls the 'steering' and 'hand' subroutines and checks for stop button press. If there is no button press, it jumps in a loop and continously checks the speed specified by the ADC every one second. If the stop button is pressed, it loads the 'stop' state and jumps back to the branch table.
(3) State: Reverse
In this state, the microcontroller does the same thing as in state forward except that it turns on the reverse switch and lights up the reverse LEDs.
Timers
We practically used all the timers/counters available on 8535 chip. More specifically we used Timer2 and Timer0 Overflows, Timer2 and Timer1 Compare Match. The following discusses in more details what each timer does:
Timer2 Overflow and Compare Match
Timer2 is used to vary the speed of the DC motor via PWM. First Timer2 is set to prescaler 2 (clk/8) corresponds to an interrupt of every 512msec. Then the OCR2 register is loaded with the 8 MSB of the 10-bit ADC. When Timer2 Compare Match interrupts, the interrupt subroutine turns off the forward or the reverse switches depending on the state which the MLV is in. However, it does not reset TCNT2, and thus Timer2 will keep counting. When Timer2 Overflow interrupts, it turns the forward or the reverse switches back on. So, both Timer2 Compate Match and Timer2 Overflow are combined to pulse-width-modulate the voltage/current to the DC motor.
Timer1 Compare Match
Timer1 Compare Match is used to sample the ADC every 1 sec. Timer1 is set to prescaler 3 (clk/64) and the Match A register is set 62500. This corresponds to an interrupt every one second (62500*16microsec=1sec). The interrupt subroutine starts the ADC conversion and resets Timer1 counter to zero.
Timer0
Timer0 is used to send the four steps required by the stepper motors ('steering' and 'hand'). For both 'steering' and 'hand', Timer0 is set to prescaler 5. This is to produce very low step frequency so that the stepper motors will turn very slowly. The step sequence for both stepper motors are defined in tables in flash memory. A counter is used to read the step value from the tables.
Debounce
The button press is debounced for 5msec using two counters. This is to avoid spikes from being considered as a button press.
Subroutines
Steering
This subroutine will enable Timer0 and initialize the step counter to 0. It first checks the direction of the steering depending on which button (right or left) is pressed. If it is a right button, it lights up the right LED and loads 'right' to the register 'turn' and vice versa. When Timer0 interrupts, it will check the content of this register and assign the appropriate address of the step sequence table defined in flash.
Hand
This subroutine does exactly the same thing as the 'steering ' subroutine except that it loads the 'turn' register with 'up' or 'down' depending on which button is pressed. There is no LED indicator for 'up' and 'down' however. Timer0 will also check for this buttton and load the appropriate step sequence.
OffSignal
This subroutine simply turns off the turn 'right' or 'left' indicator. It is called when the any of the steering button is released.
Ports
PortA is only used for the ADC. ADMUX is set to 7 to sample from channel 7.
PortB:
PortB0 and Port1: Switches for the ADC motor
PortB3-to-PortB7: LEDs for 'stop', 'forward', 'reverse', 'right' and 'left' indicator.
PortC:
PortC0-to-PortC3: To control the 'steering' stepper motor
PortC4-to-PortC7: To control the 'hand' stepper motor
Hardware Design
Vehicle Chasis
We begin the hardware design part of this project by trying to figure out the best way to efficiently mount the motors. Multiple mechanical models were created and torn apart until an acceptable model was found. At the end, we decided to create the mechanical model using components from Lego Technic™ 'Turbo Command' package. It basically consists of 472 Lego pieces which include the components to build a differential wheel system. Epoxy is used to fix the Lego gear pieces to the drive shafts of two motors. Wires and polystrene is used to provide support and strengthen the mechanical model. Click here to see final mechanical model for the vehicle.
Transistor Switches
Transistor switches are used to provide the proper stepping sequence for the stepper motor. Since the output from the Atmel board is only 5V, transistor switches are used to provide 12V signal which is needed by the stepper motor to operate. Also, A H-bridge transistor switch network is used to enable forward and reverse movement of the DC motor. The circuit diagram for these switches can be found here. The transistor switches also provide electrical protection for the ATMEL microcontroller unit from the voltage spikes produced by the motors. The transistor used is TIP102 (npn).
Stepper Motor
The stepper motor we use has four coils which, when energized in the correct sequence, cause the permanent magnet attached to the shaft to rotate. Reversing the order of the steps in a sequence will reverse the direction of rotation. In our project we used the stepper motor to provide steering and also to move the camera mount rack. Since the mechanical design requires the stepper motor to have a big torque, we used the 'two-coil excitation' stepping sequence. In this stepping sequence, each successive pair of adjacent coils is energized in turn. Click here to see an animated picture of the stepping sequence. This stepping sequence however doesn't provide smooth movements and uses more power compared to the normal stepping sequence but produces greater torque.
DC Motor
We use a 3V DC motor to provide forward and reverse movement for the MLV. We found that this DC motor consumes a lot of power, thus very inefficient.
Planetary Gear System
A planetary gear train is a mechanism consisting of an assembly of meshed gears: the sun gear, the planet carrier, and the ring gear. A planetary gearset is used to reduce the 'weight' of the vehicle seen by the DC motor and increase its efficiency. Click here to see the internal mechanism of a planetary gear system.
Differential Wheel System
Differential wheel system is widely used in modern vehicle due to its safety features. We used the differential wheel system simply because it is included in the Lego package and it looks really cool! Click here to see a picture of the differential wheel system.
Results
The design goals were successfully met. The microcontroller unit appropriately scans for user input and drives the DC and stepper motors to provide motion to the vehicle. It successfully sets the speed of the vehicle from the value obtained from the onboard ADC and controls the signal lights.
The mechanical parts however proves to be quite a big challenge to us. With little mechanical experience, designing the model took a lot of our time. Mounting the motors on the vehicles produces inefficiencies that we didn't anticipated. However, after much tweaking we finally got a working model of the vehicle :)
Measurements
DC Motor
Voltage 4.5V
Current 500 - 800 mA
depending on the load
Stepper Motors
Voltage 12V
Current 200 - 500 mA
depending on the load
Link to Schematics:
http://instruct1.cit.cornell.edu/courses/e.../s1999/mohamed/ Future Improvements
Given more time and resources, we would like to implement the following improvements:
A more robust mechanical model
The mechanical model of the vehicles seems a little bit flimsy since it was made out of Lego pieces. We would also want a higher efficiency gear/lever systems implemented.
Feedback control systems
The steering and camera mount would have a feedback control system that would give feedback if the maximum steering/height is reached. The feedback control system would turn the motor off to avoid damage to the mechanical parts.
LCD to display the current speed or condition of the vehicle.
Link:
http://instruct1.cit.cornell.edu/courses/e.../s1999/mohamed/| CODE |
;-------------------------------------------------------------------------- ;****** FINAL PROJECT ;-------------------------------------------------------------------------- ;***** NOOR M. NORHALIM ;***** MAHADZIR MOHAMED ;***** EE476 Spring 1999 ;***** MICROCONTROLLER DRIVEN LEGO VEHICLE (MLV) ;***** Controls 3 motors, one DC (variable speed) and 2 stepper motors based on ;***** commands sent from 7 buttons ;***** Button 0: STOP 1:FORWARD 2:REVERSE 3:TURN RIGHT 4:TURN LEFT ;***** 5: TURN RIGHT 6: MOVE CAMERA MOUNTING UP 7:MOVE CAMERA MOUNTING DOWN ;***** LEDs are used to indicate which action/state(s) is/are performed/executed ;--------------------------------------------------------------------------
;You will need to CHANGE this path .include "8535def.inc"
.device AT90S8535; specifies to the assembler which chip we are using
.def savREG =r1;SREG temp reg .def temp =r16;temporary register .def itemp =r17;interrupt temporary register .def itemp2 =r18;interrupt temporary register .def AnaLo =r19;A to D results .def AnaHi =r20; .def state =r21;Hold the transition state of the MLV .def debCntL =r22;Hold the low byte of the 16-bit counter .def debCntH =r23;Hold the high byte of the 16-bit counter .def turn =r24;Indicate turning direction .def steerStep=r25;Step Counter for steering and hand
.equ off =0;Signal is off .equ stop =0;State Stop .equ forward =1;State Forward .equ reverse =2;State Reverse .equ NoTurn =0;No Turning .equ right =1;Turn Right .equ left =2;Turn Left .equ up =3;Hand move up .equ down =4;Hand move down .equ TCK2 =2;CLK/8 .equ TCK3 =3;CLK/64
;***** Initialization .cseg .org $0000 rjmp RESET;reset entry vector reti reti rjmp t2match;Timer2 Compare Match Int Routine rjmp t2Ovf;Timer2 Overflow Int Routine reti rjmp t1match;Timer1 Compare Match Int Routine reti reti rjmp t0Ovf;Timer0 Overflow Int Routine reti reti reti reti reti reti reti
;****** Step sequence tables for steering and hand UpSeq: .db 0b00000011, 0b00000110, 0b00001100, 0b00001001 DnSeq: .db 0b00001001, 0b00001100, 0b00000110, 0b00000011 RSeq: .db 0b00110000, 0b01100000, 0b11000000, 0b10010000 LSeq: .db 0b10010000, 0b11000000, 0b01100000, 0b00110000
RESET: ldi temp, LOW(RAMEND);Setup stack pointer out SPL, temp ldi temp, HIGH(RAMEND) out SPH, temp
;Set up ports DATA Direction Here to run LEDS ser temp ; out DDRB,temp;Set PORTB to all outputs out DDRC, temp;Set PORTC to all outputs clr temp out DDRD, temp;Set PORTD to all inputs out PORTC, temp;Set PORTC to all inputs out PORTB, temp
;Set up Timers ;Timer 2 to interrupt on compare match and overflow ;Timer 1 to interrupt on compare A match and set the compare time to 62500 ticks ;Timer 0 to interrupt on overflow ;Stop Timer0 and 2 ldi temp,0b11010001;enable t2, t2 match, t1 matchA & t0 interrupts out TIMSK, temp clr temp out TCCR0, temp;Stop T0 out TCCR2, temp;Stop T2 ldi temp, 0xf4;Set the match A register to out OCR1AH, temp;62500 since 62500*16microsec=1sec ldi temp, 0x24;62500 = 0xf424 out OCR1AL, temp ldi temp,0b00001011;Prescale timer1 by 64 (one tick=16 microsec) out TCCR1B, temp;and clear-on-matchA
;Set up analog converter to read channel seven ldi temp, 7 out ADMUX, temp ldi state, stop;Initialize state with STOP ldi turn, NoTurn;Initialize steering with NoTurn sei ;Enable all interrupts
;-------------------------------------------------------------------------- ;****** Main Program ;-------------------------------------------------------------------------- ;****** Branch Table ;Check which state the MLV is in start: cpi state, stop breq s_stop cpi state, forward breq s_moving cpi state, reverse breq s_moving rjmp start
;****** State STOP s_stop: cbi PORTB, 0;Turn off DC motor cbi PORTB, 1 clr temp out PORTC, temp;Reset stepper motor step sequence cbi PORTB, 2;Turn on brake lights and turn off forward/reverse light cbi PORTB, 3 sbi PORTB, 4 sbi PORTB, 5 sbi PORTB, 6 sbi PORTB, 7 rcall steering;Check if steering button is pressed rcall hand ;Check if hand button is pressed sbic PIND, 1 ;Wait for forward button press rjmp rev_but rcall debounce;Debounce button sbic PIND, 1 rjmp rev_but ldi state, forward;Load state with FORWARD rjmp start ;Jump back to branch table rev_but: sbic PIND, 2 ;Wait for reverse button press rjmp s_stop rcall debounce;Debounce button sbic PIND, 2 rjmp s_stop ldi state, reverse;Load state with Reverse rjmp start ;Jump back to branch table
;****** State FORWARD and REVERSE
s_moving: rcall steering;Check if steering button is pressed rcall hand ;Check if hand button is pressed cpi state, reverse breq mov_rev
;MLV is in Forward state sbi PORTB, 2;Turn off brake lights and/or reverse indicator sbi PORTB, 3;Turn on Forward indicator sbi PORTB, 4 sbi PORTB, 5 cbi PORTB, 6 cbi PORTB, 7
cbi PORTB, 1;Forward switches sbi PORTB, 0;Turn on DC motor rjmp s_mov_done
;MLV is in Reverse state mov_rev: sbi PORTB, 2;Turn off brake lights and/or forward indicator sbi PORTB, 3;Turn on reverse indicator cbi PORTB, 4 cbi PORTB, 5 sbi PORTB, 6 sbi PORTB, 7
cbi PORTB, 0;Turn on DC motor sbi PORTB, 1;Reverse switches
s_mov_done: swait: in temp, ADCSR;Wait for A to D start andi temp, 0b01000000;by checking if ADSC bit is set breq swait ;This bit is set by t1match interrupt
wait: in temp, ADCSR;Wait for A to D done andi temp, 0b01000000;by checking ADSC bit brne wait ;This bit is cleared by the AtoD hardware in AnaLo, ADCL;Read the voltage in AnaHi, ADCH ;Set Timer2 OCR reg appropriately to PWM DC motor ldi temp, 2 out TCCR2, temp;Set Timer2 to prescaler 2 ror Anahi ;Get the 8 MSB of the ADC ror Analo ror Anahi ror Analo out OCR2, AnaLo;Set it to OCR2 rcall steering;Check if steering button is pressed rcall hand ;Check if hand button is pressed
sbic PIND, 0 ;Check if STOP button is pressed rjmp s_moving rcall debounce sbic PIND, 0 rjmp s_moving ldi state, stop;Load state with STOP rjmp start ;Jump to branch table
;-------------------------------------------------------------------------- ;****** Subroutines ;--------------------------------------------------------------------------
;****** Steer the front wheel to the right or left depending on which button is ;****** pressed steering: sbic PIND, 3 ;Check right steer button rjmp steerL rcall debounce;Debounce sbic PIND, 3 rjmp steerL ldi turn, right;Load turn with RIGHT ;Turn steering to Right, using T0 ldi temp, 5 ;Prescale Timer0 by 2 out TCCR0, temp clr steerStep;Reset step counter contStR: sbis PIND, 3 ;Wait for right steer button release rjmp contStR clr temp ldi turn, NoTurn;Load turn with NoTurn out TCCR0, temp;Stop T0 rcall offSig ;Turn off right/left indicator ret steerL: sbic PIND, 4 ;Check left steer button ret rcall debounce;Debounce sbic PIND, 4 ret ldi turn, left;Load turn with LEFT ;Turn steering to Left, using T0 ldi temp, 5 ;Prescale Timer0 by 2 out TCCR0, temp clr steerStep;Reset step counter contStL: sbis PIND, 4 ;Wait for left steer button release rjmp contStL clr temp ldi turn, NoTurn;Load turn with NoTurn out TCCR0, temp;Stop T0 rcall offSig ;Turn off right/left indicator ret
;****** Move the camera mounting up or down depending on which button is pressed hand: sbic PIND, 5 ;Check if up button is pressed rjmp handDOWN rcall debounce;Debounce sbic PIND, 5 rjmp handDOWN ldi turn, up;Load turn with UP ;turn hand up, using T0 ldi temp, 5 ;Prescale Timer0 by 2 out TCCR0, temp clr steerStep;Reset step counter contUP: sbis PIND, 5 ;Check if up button is released rjmp contUP clr temp ldi turn, NoTurn;Load turn with NoTurn out TCCR0, temp;Stop T0 ret handDOWN: sbic PIND, 6 ;Check if down button is pressed ret rcall debounce;Debounce sbic PIND, 6 ret ldi turn, down;Load turn with DOWN ;turn hand down, using T0 ldi temp, 5 ;Prescale Timer0 by 2 out TCCR0, temp clr steerStep;Reset step counter contDOWN: sbis PIND, 6 ;Check if down button is pressed rjmp contDOWN clr temp ldi turn, NoTurn;Load turn with NoTurn out TCCR0, temp;Stop T0 ret
;****** Debounce button press for ~5msec debounce: ;debounce for ~5 msec, 0.25usec/tick x 256 ticks x 78 = ~5 msec ldi debCntH, 78 ldi debCntL, 0xff loop: dec debCntL brne loop ldi debCntL, 0xff dec debCntH brne loop ret
;****** Turn OFF RIGHT/LEFT indicator OffSig: sbi PORTB, 6 ;turn off signals sbi PORTB, 7 ret
;-------------------------------------------------------------------------- ;****** Interrupt Routines ;--------------------------------------------------------------------------
;****** timer 2 Compare Match (PWM --> TURN OFF DC motor) t2match:in savREG, SREG;Save status register
cpi state, forward;Check which state MLV is in breq t2matchfwd cpi state, reverse breq t2matchrev rjmp t2matchdone t2matchfwd: ;MLV is in FORWARD state cbi PORTB, 0;TURN off DC motor cbi PORTB, 1 rjmp t2matchdone t2matchrev: ;MLV is in REVERSE state cbi PORTB, 0;TURN off DC motor cbi PORTB, 1 t2matchdone: out SREG, savREG;Restore status register reti
;****** timer 2 Overflow (PWM --> TURN ON DC motor) t2Ovf: in savREG, SREG;Save status register cpi state, forward;Check which state MLV is in breq t2fwd cpi state, reverse breq t2rev rjmp t2done t2fwd: ;MLV is in FORWARD state cbi PORTB, 0;Turn on FORWARD switches sbi PORTB, 1 rjmp t2done t2rev: ;MLV is in REVERSE state sbi PORTB, 0;Turn on REVERSE state cbi PORTB, 1
t2done: out SREG, savREG;Restore status register reti
;**** timer 1 compare A match 1/sec (Sample ADC every 1 sec) t1match:in savREG, SREG;Save status register ldi itemp, 0b11000101;start A to D conversion out ADCSR, itemp out SREG, savREG;Restore status register reti
;**** timer 0 Overflow (Send step sequence to stepper motors, steering and hand) t0Ovf: in savREG, SREG;Save status register cpi turn, right;Check which direction the stepper motors breq t0right ;should turn (right, left, up and down) cpi turn, left breq t0left cpi turn, up breq t0up cpi turn, down breq t0down rjmp t0done
t0right:ldi ZL, low(RSeq*2) ;Get step sequence for RIGHT from table ldi ZH, high(RSeq*2) in itemp, PINB ;Do right signal ldi itemp2, 0b10000000 eor itemp, itemp2 out PORTB, itemp sbi PORTB, 6 rjmp t0setStep t0left: ldi ZL, low(LSeq*2) ;Get step sequence for LEFT from table ldi ZH, high(LSeq*2) in itemp, PINB ;Do left signal ldi itemp2, 0b01000000 eor itemp, itemp2 out PORTB, itemp sbi PORTB, 7 rjmp t0setStep t0up: ldi ZL, low(UpSeq*2);Get step sequence for UP from table ldi ZH, high(UpSeq*2) rjmp t0setStepUpDn t0down: ldi ZL, low(DnSeq*2);Get step sequence for DOWN from table ldi ZH, high(DnSeq*2) t0setStepUpDn: ;Send step sequence to hand stepper motor add ZL, steerStep lpm in itemp, PINC andi itemp,0b11110000 or itemp, r0 out PORTC, itemp cpi steerStep, 3 breq t0zeroStep inc steerStep rjmp t0done
t0setStep: ;Send step sequence to steering stepper motor add ZL, steerStep lpm in itemp, PINC andi itemp,0b00001111 or itemp, r0 out PORTC, itemp cpi steerStep, 3 breq t0zeroStep inc steerStep rjmp t0done t0zeroStep: ;Reset step counter after every 4 steps clr steerStep t0done: out SREG, savREG ;Restore the status register reti
|