Full Version : Bell & Nazarian 911 RC Car Controller (AVR ASM)
avr >>ROBOTS & AUTONOMOUS VEHICLES >>Bell & Nazarian 911 RC Car Controller (AVR ASM)


AVR_Admin- 04-22-2006
Porche 911 RC Car

by Andrew Bell & Cory Nazarian
Introduction:

For the final project we decided to use a radio-controlled car from Radio Shack. We purchased an RC car, removed everything except the body and the motors, and replaced all of the circuitry with our own microcontroller-controlled network. We also built our own controller using just the existing case. For the transmission of control signals, we used a 418 MHz transmitter/receiver pair purchased from Abacom Technologies. We used two microcontrollers in this project, one for the controller, and one for the RC car.



High Level Design:

The goal of our final design project was to remove all circuitry from the existing car and controller, replace it with our own microcontrollers, logic, and associated circuitry, and have the car work the same way as when purchased. This goal was to be achieved through a very systematic approach, which we laid out before beginning the project.

To begin with, we set out to have two microcontrollers connected to each other through a null-modem cable using the UART communication protocol. One was to be a transmitter, and the other a receiver. The pushbuttons on one board would light their corresponding LEDs on the other microcontroller board. Once the UART communication was established, we next decided to simply remove the null-modem cable, and in its place, add the transmitter/receiver. Since the Tx/Rx operated in the same way as the UART (each sending an 8-bit data packet), the transition to a wireless communication network was relatively straight-forward. Once wireless communication was established, we proceeded to move our attention to the car.

Before dismantling the car, all voltages, and currents controlling the motors were carefully recorded. Then, all of the existing circuitry was removed, and replaced by our microcontroller, receiver, H-Bridge, and logic controlling circuitry. The car was now controlled by the pushbuttons on the development board, one button for forward, reverse, left and right. The forward/reverse signals operated the rear motors, while the left/right signals operated the front steering motor, which were strictly controlled by the microcontroller's timer.

Once the car was operating correctly via the development board, the next step was to attack the original RC controller. We removed all of the circuitry from it, and kept only the metal contacts on the PC board. The microcontroller and transmitter were then integrated with the controller, replacing the pushbuttons with the new switches on the controller. The original antenna was reattached to our new transmitter, and behold, a working RC car, just like the original, but even faster!



Program/hardware Design:

For the program design portion of this project, we wrote two portions of code, one that ran on the controller's microcontroller, and one that ran on the RC car's microcontroller.

The controlling microcontroller's function was to essentially receive commands denoting the direction of the vehicle and output an encoded 8 bit value of these directions. The input signals came from the metal contacts of the switches on the original controller to 4 input port pins ( indicating forward, reverse, left and right) on the microcontroller. The directions are then encoded as 1-byte words which are sent to the transmitter using the UART protocol. The code for the controller can be found in Appendix B - Controller Code.

The function of the car's microcontroller was to provide signals to control the motors. The inputs to this microcontroller came in 1-byte packets from the receiver, each one indicating the state that the car should be set to. As mentioned before, we implemented the UART receiving protocol at this end. The outputs consisted of 4 signals on port pins (Driving Direction, Driving PWM, Steering Direction, Steering PWM). The generation of forward and reverse signal was straightforward. The generation of the left and right signals was quite different. Instead of relying on feedback signals to control the steering (which was what the original Radio Shack car did), we took full advantage of the timer in these microcontrollers (TIMER0). The times taken for the wheels to turn left and right, and then back to center were recorded. Then, when the front wheels are to be turned, the left or right signal is held high for only a short period of time, controlled by the timer. Conversely, when the wheels are to be brought back to center, the timer is used again to make sure the wheels are brought back exactly to the center position. The code for the RC can be found in Appendix A - RC Car Code

This RC car project was a good balance of software and hardware. Once the software aspects of this project were clearly defined, we set out to turn the microcontroller's signals into voltages and currents that the motors could operate on. The main hardware components of the car included multiple batteries, the logic circuitry and the H-Bridges for both driving forward or reverse and steering left or right. The car contained two batteries: one 9.6V battery from the original car was used to power all the motors (the front motor running at 5V due to a voltage regulator), while an ordinary 9V battery was used to power the microcontroller, again through another 5V regulator. Although it may have been possible to power each from one battery, we believed it was best to keep the motors and microcontroller separate.

First, we constructed two identical portions of the logic circuitry seen in Appendix C, one generating forward and reverse signals (and their respective complements), and one generating left and right signals (and their respective complements). The inputs were just the PWM signal and a direction. We used custom IC's for the logic. Now, the signals leaving the this portion of the hardware were either 5V or 0V. These voltage levels were perfect as inputs to the front motor H-Bridge which operated on 5V, but would not be acceptable to run the rear wheels. Therefore we added 4 transistors to boost the voltage from 5V to 9.6V. The H-Bridge part that we sent away for was not acceptable, thus we needed to construct our own H-Bridge to control the motors. Again, the schematic for the H-Bridge can be seen in Appendix C. We originally used Motorola's TIP31 and TIP32 transistors for both the driving and steering motors, but they were not providing enough power for the driving motors, so we upgraded to the TIP102 and TIP107 series, which provided plenty of power, more than the original car! We also needed to integrate the microcontroller onto the car. To achieve this, we used a 4MHz crystal oscillator, and two 22pf capacitors to provide an accurate clock, and a 5V regulator connected to the 9V battery to provide power.

The circuitry for the controller was also completely built by us. The microcontroller for this portion again contained the oscillator and two capacitors, and was powered by a 9V battery (with the associated 5V regulator). The original two plastic levers, one for forward/reverse, and one for left/right, were kept intact. We soldered on 4 wires to the original metal contacts. These 4 wires were then Port B inputs to the microcontroller, with the associated pull-up resistors turned on. We wired the middle metal contact of each lever to ground, so that when the contact connected the middle plate to the port pin, it was pulled low, detected by the microcontroller, and an appropriate signal was sent to the transmitter. In addition, to cut down on power consumption by the microcontroller, and ease of use, we added a mechanical switch to turn the controller on and off.



Results of the Design:

My partner and I accomplished all of the objectives that we set out to achieve. Our goal was to create a radio controlled car that had the same functionality as the original. One key result of the design is that our car is clearly faster than the original. We could have increased the speed further by adding larger power transistors, except that we were not sure how much current the rear motors could handle. In addition, the steering is quicker also. This again is due to the larger power transistors, and larger voltage. From the original measurements, the steering motor was running on 4V, and we were powering it with 5V. Another key result of our design is that we were able to run our car for longer periods of time than the original car. This is due in part to the fact that we used two batteries. The 9.6V battery pack now only has to provide power to the motors, while the 9V battery we added powers the microcontroller, and direction generating signals. Since our original objective was to get the car running as it was originally, we decided it was necessary that all of the circuitry be transferred from the large, heavy breadboards to smaller PC boards where the components were soldered on. This made for cleaner, more compact, less noisy circuitry, and more importantly allowed the cover to be placed back onto the car! The same was true for the controller. We could have just controlled the car from the microcontroller board, using pushbuttons, but we envisioned a stand-alone controller, namely using the original. Additionally, the switch we added cut down on power consumption. Another great feature about our car is it can be rammed into cement walls from any direction, dropped and flipped without missing a beat. Really, it can, and we've tested it!



The Future:

This project turned out great, but there are still a few things we would like to add, and one minor thing we would have done differently. The change we would have made was: instead of using timer0 to control the steering, we would have used the feedback signals which came with the steering servo. The reason for this, is as the batteries lose juice, the amount of time required to turn the wheels all the way left or right, or back to center changes. Using the feedback signals would avoid this because the motor would keep turning until the wheels were fully turned or returned, independent of time and voltage.

A few additions we have thought about would be adding some minor bells and whistles like a horn and lights, but a major improvement would be to add analog control to the car. That is to say, the speed would increase as you pushed the lever higher and the wheels would turn farther as you pushed the turn lever farther. This would be difficult with our car because the controller has no support for this. The contacts are all or nothing, so new controlling circuitry would be essential. This would be the only hardware change though, as the RC car could support analog control with only a minor upgrade to the code in the microcontroller, and the use of the 8535 MCU instead of the 4414 MCU.

Link: http://instruct1.cit.cornell.edu/courses/e...ject.rccar.html

AVR_Admin- 04-22-2006
CODE

;Andrew Bell and Cory Nazarian
;EE 476 Final Project
;Code for RC Car
;Also see control.asm
;Version 2.0 Uart Communication with Forward and Reverse Motor Control
;and Full turning control
;All known bugs fixed

;Port B is hooked to LED's, and used to show what subroutine were in

;For Driving motor control
;PORT A0 is direction Bit
;PORT A1 is PWM bit

;For Turning motor control
;PORT A2 is direction Bit
;PORT A3 is PWM bit

.include "4414def.inc"

.device AT90S4414

;*******************************
;Register Definitions
.def    temp    =r16   ;temporary register
.def    savSREG =r17   ;save the status register
.def    TXbusy  =r18   ;transmit busy flag
.def    RXchar  =r19   ;a received character
.def    TXflash =r20   ;text to be sent is in flash if <>0
.def    command =r21
.def    lcommand=r22   ;last command
.def    donecmd =r23   ;this register has 1 if done current command, 0 if not  
.def    tmpcmd  =r24   ;register to hold command until last command completes
.def    wreg    =r25   ;temp register to be used in isrs
.def    turnback=r26   ;register contains where wheels were to turn back to orignal position
.def    doneturn=r27   ;says were done turning, set in tiemr 0 overflow interupt
.def    count   =r28   ;count register fro timer 0 overflow interupt

;*******************************
;Constants
.equ    baud96  =25;9600 baud constant for 4Mhz crystal
.equ    PreScal =3 ;set prescalar to divide by 8
.equ    TimerOff=0 ;set prescaqlr to 0 to turn off timer0
.equ    DoneTurning=60 ;set done turning count to 20 overflows

;All possible directions for the car to be going
.equ    stop    =0b00000001
.equ    fwd =0b00000010
.equ    rev =0b00000100
.equ    left    =0b00001000
.equ    right   =0b00010000

;Bits in command that directions represent
.equ    stopb   =0
.equ    fwdb    =1
.equ    revb    =2
.equ    leftb   =3
.equ    rightb  =4
.equ    garbagb1=5
.equ    garbagb2=6
.equ    garbagb3=7

.equ    True    =1
.equ    False   =0

;Constants for turning wheels back to center after turning
.equ    FrNthr  =0b00000000;wheels were not just turned
.equ    FrLeft  =0b00000010;wheels were just turned left
.equ    FrRight =0b00000100;wheels were just turned right

;Bits in turnback that represent to turn back from right or left
.equ    FrLeftB =1     ;From left bit
.equ    FrRightB=2     ;From Right bit

.macro addi
   subi @0, -@1
.endmacro

;*******************************
.cseg

.org $0000
   rjmp    RESET  ;reset entry vector
   reti        
   reti
   reti
   reti
   reti
   reti            
   rjmp    TIMER0 ;Timer 0 overflow
   reti        
   rjmp    RXdone ;UART receive done
   reti
   reti
   reti

;define fixed strings to be tranmitted from flash- zero terminated
crlf:   .db 0x0d, 0x0a, 0x00   ;carrage return/line feed


RESET:  ldi temp, LOW(RAMEND)  ;setup stack pointer
   out     SPL, temp
   ldi temp, HIGH(RAMEND)
   out SPH, temp

   ldi command,stop       ;start car in stopped mode
   ldi tmpcmd,stop    ;start car in stopped mode
   ldi turnback,FrNthr    ;Wheels were not just turned
   ldi doneturn,False     ;load dune turn variable to false

  ;setup UART -- enable RXdone int, and RX
   ldi     temp, 0b10110000
   out     UCR, temp
  ;set baud rate to 9600
   ldi temp, baud96
   out UBRR, temp

  ;setup timer0 stuff
   ldi Temp,exp2(TOIE0);enable timer interrupt
   out TIMSK, Temp

  ;setup port a7 for power
   ser temp
   out DDRA,temp
   ldi temp,0b10000000
   out PORTA,temp

  ;intialize text pointer BEFORE turning on interrupts
  ;because RESET causes the TX empty flag to be SET
   ldi ZL, LOW(crlf<<1);do shift to convert word-addr to byte
   ldi     ZH, HIGH(crlf<<1)

  ;setup LED"s for display
   ser temp           ;make port b outputs
   out DDRB,temp
   out PORTB,temp     ;turn off led's
   sei

;Figure out which dir to drive the car and turn the car and do it
RXloop: mov command,tmpcmd     ;move the next command into command
   cpi donecmd,True       ;if weve done current command already, wait for next
   breq    RXLoop

   ser wreg           ;turn all LED's off
   out PORTB,wreg

   sbrc    command,fwdb       ;drive forward
   rcall   DriveForward
   sbrc    command,revb       ;drive reverse
   rcall   DriveReverse
   sbrc    command,stopb      ;stop car
   rcall   Stopped
   sbrc    command,leftb      ;turn left
   rcall   TurnLeft
   sbrc    command,rightb     ;turn right
   rcall   TurnRight
   sbrc    command,garbagb1   ;use these 3 bits (not used) to see if out of range
   rcall   OutRange       ;when out of range, reciever recieves squared noise
   sbrc    command,garbagb2   ;so one of these 3 bits will be set at some point
   rcall   OutRange       ;when it is, stop the car and spin
   sbrc    command,garbagb3   ;note that car needs to be reset here
   rcall   OutRange

   ldi donecmd,True       ;Say weve done the current command

   sbrc    command,leftb      ;if this command is turn  right or left go back to get next command
   rjmp    noret
   sbrc    command,rightb
   rjmp    noret
                  ;otherwise, see if the last command turned the car, to turn wheels back
   sbrc    turnback,FrLeftB
   rcall   BackFrLeft
   sbrc    turnback,FrRightB
   rcall   BackFrRight

noret:  
   rjmp    RXloop


;*******************************
;Driving Routines

Stopped:               ;Stop the car
   cbi PORTB,0
   cbi PORTA,1        ;Turn Driving PWM Bit off
   ret

DriveForward:              ;Drive the car forward
   cbi PORTB,1
   sbi PORTA,0        ;Turn driving Dir bit to forward (1)
   sbi PORTA,1        ;Turn driving PWM bit on
   ret

DriveReverse:              ;Drive the car backwards
   cbi PORTB,2
   cbi PORTA,0        ;Turn driving Dir bit to reverse (0)
   sbi PORTA,1        ;Turn driving PWM bit on
   ret

TurnLeft:              ;Turn car left
   cpi turnback,FrLeft
   brne    noltyet
   ret
noltyet:ldi turnback,FrLeft    ;For turning back to middle after done turning left
   cbi PORTB,5
   cbi PORTB,3
   sbi PORTA,2        ;Turn turn Dir bit to left (1)
   sbi PORTA,3        ;Turn turning PWM bit on

  ;This code turns the motor on until wheels are fully turned to left then turns off pwm
   ldi     temp, PreScal  
   out     TCCR0, temp
tl: cpi doneturn,True
   brne    tl
   sbi PORTB,5
   cbi PORTA,3        ;Turn turning PWM bit off
   ldi doneturn,False     ;Set doneturn back to false
   ret

TurnRight:             ;Turn car right
   cpi turnback,FrRight
   brne    nortyet
   ret
nortyet:ldi turnback,FrRight   ;For turning back to middle after done turning right
   cbi PORTB,6
   cbi PORTB,4
   cbi PORTA,2        ;Turn turning Dir bit to right (0)
   sbi PORTA,3        ;Turn turning PWM bit on

  ;This code turns the motor on until wheels are fully turned to left then turns off pwm
   ldi     temp, PreScal  
   out     TCCR0, temp
tr: cpi doneturn,True
   brne    tr
   sbi PORTB,6
   cbi PORTA,3        ;Turn turning PWM bit off
   ldi doneturn,False     ;Set doneturn back to false
   ret

BackFrLeft:            ;Turn wheels back to center after turning to left is done
   ldi count,20
   ldi turnback,FrNthr    ;Wheels were not just turned
   cbi PORTB,5
   cbi PORTA,2        ;Turn direction to right
   sbi PORTA,3        ;Turn on the PWM to start turning back to center

  ;This lets the wheels turn back to center then turns off the pwm
   ldi     temp, PreScal      
   out     TCCR0, temp
tbl:    cpi doneturn,True      
   brne    tbl
   cbi PORTA,3        ;Turn turning PWM bit off
   ldi doneturn,False     ;set doneturn back to false
   ret
   
BackFrRight:               ;Turn wheels back to center after turning to right is done
   ldi count,20
   ldi turnback,FrNthr    ;Wheels were not just turned
   cbi PORTB,6
   sbi PORTA,2        ;Turn direction to right
   sbi PORTA,3        ;Turn on the PWM to start turning back to center

  ;This lets the wheels turn back to center then turns off the pwm
   ldi     temp, PreScal      
   out     TCCR0, temp
tbr:    cpi doneturn,True
   brne    tbr
   cbi PORTA,3        ;Turn turning PWM bit off
   ldi doneturn,False     ;set doneturn back to false
   ret

OutRange:              ;Out of range routine
   cbi PORTA,1        ;Turn Driving PWM Bit off
   cbi PORTA,3        ;Turn turning PWM bit off
   ret

;*******************************
;interrupt routines

RXdone: in  savSREG, SREG      ;save processor status  
   in  tmpcmd, UDR    ;get the character
   ldi donecmd,False      ;say we have not done this command
   out SREG, savSREG      ;restore proc status
   reti               ;back to pgm


;*******************************
;   Timer 0 overflow handler
TIMER0:
   in  savSREG,SREG
   inc count
   cpi count,DoneTurning
   brne    notdone
   ldi     wreg, TimerOff     ;turn off timer 0
   out     TCCR0, wreg
   ldi doneturn,True
   clr count
notdone:out SREG,savSREG
   reti
;-

AVR_Admin- 04-22-2006
CODE

Andrew Bell and Cory Nazarian
;EE 476 Final Project
;Code for controller
;Also see rccar.asm
;Version 2.0 Uart Communication with Forward and Reverse Motor Control
;and Full turning control
;All known bugs fixed

;Port B used as push buttons at this piont

.include "4414def.inc"

.device AT90S4414

;*******************************
;Register Definitions
.def temp =r16;temporary register
.def savSREG =r17;save the status register
.def TXbusy =r18;transmit busy flag
.def RXchar =r19;a received character
.def TXflash =r20;text to be sent is in flash if &lt;&gt;0
.def command =r21
.def lcommand=r22
.def wreg =r23;temp register to be used in isrs

;*******************************
;Constants
.equ baud96 =25;9600 baud constant for 4Mhz crystal

;All possible directions for the car to be going
.equ stop =0b00000001
.equ fwd =0b00000010
.equ rev =0b00000100
.equ left =0b00001000
.equ right =0b00010000

;Bits in command that directions represent
.equ stopb =0
.equ fwdb =1
.equ revb =2
.equ leftb =3
.equ rightb =4

.macro addi
subi @0, -@1
.endmacro


;*******************************
.dseg

;define variable strings to be tranmitted from RAM
stdir: .byte 3;the direction stored in mem

;*******************************


;*******************************
.cseg

.org $0000
rjmp  RESET;reset entry vector
reti  
reti
reti
reti
reti
reti
reti
reti  
reti
rjmp TXempty;UART buffer empty
rjmp  TXdone;UART transmit done
reti

;define fixed strings to be tranmitted from flash- zero terminated
crlf: .db 0x0d, 0x0a, 0x00;carrage return/line feed


RESET: ldi temp, LOW(RAMEND);setup stack pointer
out  SPL, temp
ldi temp, HIGH(RAMEND)
out SPH, temp

clr TXbusy ;start out not busy on TX

ldi command,stop;start the car in stop mode
ldi lcommand,0;make sure last command is not = command at start

;setup UART -- enable TXempty int, TX pin
ldi  temp, 0b00001000
out  UCR, temp

;set baud rate to 9600
ldi temp, baud96
out UBRR, temp

;setup port b for control
clr temp

out DDRB, temp
ser temp
out  PORTB,temp

;setup port a7 for power
ser temp
out DDRA,temp
ldi temp,0b10000000
out PORTA,temp


;intialize text pointer BEFORE turning on interrupts
;because RESET causes the TX empty flag to be SET
ldi ZL, LOW(crlf&lt;&lt;1);do shift to convert word-addr to byte
ldi  ZH, HIGH(crlf&lt;&lt;1)
sei


;now print three strings and wait for incoming character interrupt
TXloop: in command,PINB
com command
cpi command,0
brne notstop
ldi command,stop ;if command is 0, set it to stop (0b00000001)

notstop:ldi ZL, LOW(stdir)  ;ptr to RAM
ldi ZH, HIGH(stdir)
st Z, command ;the direction to ram
inc ZL  ;zero string terminator to RAM
clr temp
st Z, temp


;now the pointer to the variable message in RAM
ldi ZL, LOW(stdir) ;ptr to RAM
ldi ZH, HIGH(stdir)
ld r0,Z
out UDR, r0  ;fire off the UART transmit
clr TXflash  ;the string is in RAM
ser TXbusy  ;and set the TX busy flag
sbi UCR, UDRIE ;enable the TXempty interrupt
rcall TXwait

rjmp TXloop


;*******************************
;interrupt routines

; UART needs a character
TXempty:in savSREG, SREG;save processor status
tst TXflash ;Is the string in flash memory?
breq TXram ;If not, it is in RAM
inc ZL ;get the next char from flash  
lpm  ;and put it in r0
rjmp TXfls
TXram:  inc ZL ;get the next char from RAM
ld r0,Z
TXfls: tst r0 ;if char is zero then exit
breq TXend  
out  UDR, r0 ;otherwise transmit it
rjmp TXexit ;exit until next char
TXend: clr TXbusy ;no more chars
cbi UCR, UDRIE;clear the TXempty interrupt
TXexit: out SREG, savSREG;restore proc status
reti  ;back to pgm

; TX done -- buffer is empty  -- unused here
TXdone: in savSREG, SREG;save processor status
out SREG, savSREG;restore proc status
reti  ;back to pgm


;*******************************
;subroutine

TXwait: tst TXbusy ;now wait for the tranmission to finish
brne TXwait
ret
;-



Forumer™ is Voted #1 Free Forum Hosting provider
Build your own community today with the largest message board hosting company.