Download here - Adam Morse
Transcript
Autonomous Vehicular Trailer EE 452 Final Project Spring 2012 Conor Cahill, Steven Hopkins, and Adam Morse Abstract Today’s vehicles with cruise control typically lock the speed to a fixed set point. Problems arise when the speed of the lead traffic varies, causing the drivers to have to manually adjust the set speed. A simple addition of a distance sensor opens up the possibility to follow the leading vehicle and maintain a fixed safe distance. This project implements one such method of following a lead vehicle using an ultrasonic distance sensor to measure the distance. A microcontroller plus code contain the algorithm necessary to adjust the power of the motors to maintain the proper distance. In the future, this algorithm could be expanded to take other variables into account, such as requested speed and collision avoidance. Table of Contents Introduction ...................................................................................................................................................................2 Technical Approach .......................................................................................................................................................3 Block Diagram ................................................................................................................................................... 3 Software Systems.............................................................................................................................................. 4 Algorithm ...................................................................................................................................................... 4 Source Code ................................................................................................................................................ 10 Hardware Systems .......................................................................................................................................... 42 Hardware Description ................................................................................................................................. 42 Schematics .................................................................................................................................................. 43 Test Plan and Results ...................................................................................................................................................48 Conclusions ..................................................................................................................................................................52 References ...................................................................................................................................................................53 Appendixes ..................................................................................................................................................................54 Time Tracking .................................................................................................................................................. 54 User Manual .................................................................................................................................................... 55 Datasheets ...................................................................................................................................................... 58 Rover 5 ........................................................................................................................................................ 58 Motor Driver: Freescale MC33926.............................................................................................................. 60 Ultrasonic Distance Sensor: MaxBotics XL-MaxSonar-AE4 (MB1340) ........................................................ 85 MCU: Microchip PIC18F46K22 (Partial) ...................................................................................................... 90 Buzzer: Mallory AST1240MLTRQ ................................................................................................................ 94 Introduction An Autonomous Vehicular Trailer is a vehicle designed to be a trailer that follows behind a lead vehicle adjusting its velocity as necessary to maintain its relative position with the lead vehicle. This trailer is autonomous in that there are no direct communications/controls from the lead vehicle to the trailer. The trailer itself senses the location of the lead vehicle and adjusts its own velocity to automatically follow behind the lead vehicle. We will construct the trailer using a kit-based tracked vehicle with two DC motors (one for each track) connected to a motor control unit that is, in turn, controlled by our PIC18 microcontroller. In addition we plan to use an ultrasonic sensor to determine the distance between the trailer and the lead vehicle and LED indicators to represent “hazard” lights. The trailer will only adjust itself to movement in a straight line direction. It will not turn to follow the lead vehicle should the lead vehicle turn. If the trailer does not sense the lead vehicle, or loses track of the lead vehicle, it will stop and turn on its hazard lights and await the return of the lead vehicle. The software control will continuously monitor the distance between the lead vehicle and the trailer and will use this information to also calculate the relative velocity and relative acceleration. In addition separate wheel sensors will be used to monitor the absolute velocity of the trailer. The absolute velocity of the trailer will be used to define a target distance range for the trailer (getting higher as the velocity increases to allow for additional response distance). The distance, relative velocity and relative acceleration will be used to control the power provided to the motors in order to control the acceleration of the trailer in an efficient manner. We plan to use a proportional-integral-derivative (PID) algorithm to determine the amount of power to send to the motors in order to maintain the appropriate distance from the lead vehicle. The motors will also be used to provide braking force when necessary in order to maintain the appropriate separation distance when the lead vehicle slows abruptly. We plan to support both positive and negative velocity so that the lead vehicle can move forward and/or backward and the trailer will maintain the appropriate separation distance. Technical Approach Block Diagram The block diagram provides a high-level, graphic illustration of the components of the Autonomous Trailer. The arrows connecting the blocks illustrate a flow of information. The discrete elements of the system are the object to be followed (Lead Car or similar provided by user), an ultrasonic distance sensor, a microcontroller, a motor control board, the motors that drive the vehicle and the hazard lights/buzzer. Power is provided to the distance sensor, the microcontroller and the motor controller. Distance Sensor 8-Bit Microcontroller Power Manually Controlled Lead Car with Reflective Tape Motor Controller DC Motor1 DC Motor2 Hazard Lights (LED Array) Backup beeper (buzzer) Software Systems Algorithm We have broken our algorithm and functionality into several pieces of functionality tied together by our main function. The algorithm for each component is discussed separately. Main Loop Sensor Control, Pseudo-code ; Algorithm for initializing and reading ultrasonic distance sensor ; ; Parameters: None ; ; Outputs: WREG and ADRESL will contain a regularly updated 8-bit value representing distance ; in cm (1 bit per cm) ; ; Global Data: Oscillator will be configured to 16MHz ; ; Persistent Data: When bits 0 or 1 ADRESH are set, this indicates a distance sensor error, and ; error code WREG=0xFF ; is given ; ; Temporary Data: ; ; Algorithm ;********************************************************************** ; ; Initialize Sensor initSensor() { ;Set TRISA (pin RA2) to input and ANSELA (pin RA2) to configure analog TRISA <-- set bit 2 ANSELA <-- set bit 2 ;Configure ADCON0, ADCON1,ADCON2 ;ADCON0 (comments move right to left from LSB, ignoring unused bits) ;ADON<0> -- 1 -- initialize ADC ;CHS<4,0> -- 00010 -- Channel select AN2 ADCON0 <-- B'00001001' ;ADCON1 ;PVCFG <1,0> -- 00 -- positive voltage reference set to MCU internal 5V ;NVCFG <1,0> -- 00 -- negative voltage reference set to MCU internal 0V ADCON1 <-- B'00000000' ;ADCON2 ;ADCS<2,0> -- 010 -- Assume TAD>=1.6microsecond (from lecture), ;and MCU 16MHz device frequency, therefore use Fosc/32 as the ADC clock ;source (giving a period of 2microsecond, p299) ;ACQT<2,0> -- 100 -- If we assume maximum temp of 50C, utilizing TACQ ;formula, there is a still good deal of variation depending on the sensor ;impedance (unknown at this point). But based on a 2.5kohm impedance, the ;text (p577) calculates TACQ=~13microsec. To be conservative, we can use ;8*TAD ADFM -- 1 -- right justify results in ADRESL/ADRESH ADCON2 <-- B'10100010' } ;Read Sensor Value readSensor() { ; Begin acquisition/conversion sampling loop ; ; Start conversion ADCON0 <-- GO ; set GO bit ; ; Test if conversion is finished before proceeding If ADCON0 <GO/DONE> = 1 ( Return to test again with branch loop } ; ; Test for system error by testing ADRESH value ; If bits 0 or 1 are set, then WREG must give error code 0xFF ; If there is no error, place ADRESL into WREG as returned value If ADRESH <0> = 1 { ; poll for errors in the first bit of ADRESH WREG <-- 0xFF ; set error code } Else { WREG <-- ADRESL } If ADRESH <1> = 1 { ; poll for errors in the first bit of ADRESH WREG <-- 0xFF ; set error code } Else { WREG <-- ADRESL } ; Delay 2TAD before returning to readSensor start } Motor Control, Pseudo-code ; ; MotorControl.txt - pseudocode for MotorControl functions ; MotorInit - called to initialize the Motor Control system ; ; We are using a PWMs to control each motor and need to ; configure them for our use and for our motors ; Set the period Register for Timer 2 to be 66 (which gets us a 15Khz PWM freq) Configure CCP1 and CCP2 on Port C for output Enable Timer2 and set it's pre-scaler to 4 (so our input is (16M/4)/4 or 1Mhz) Associate Timer2 with PWM1 and PWM2 Enable PWM Mode on CCP1 and CCP2 Configure pins 7-3 on PortC for output Set the motor to off end MotorUpdate - called to update the motor settings ; ; Parameters: Arg1 - the desired motor power percentage (0-100) ; Arg2 - the desired direction (1=reverse, 0=forward) ; Set the motor duty cycle to the value from Arg1 on Motor 1 and Motor 2 If the desired direction is forward set MotorSettings to Forward clear Reverse status indicator else set MotorSettings to Reverse set Revers status indicator endif write the new MotorSettings to PortC end MotorEmergencyStop - called when we've lost track of Lead Vehicle Set motor duty cycle to zero for both Motor 1 and Motor 2 Set MotorSettings to OFF write the new MotorSettings to PortC end Process Data, Pseudo-code ; ; ProcessData.txt - algorithms for ProcessData subroutines ; ProcessDataInit - called at start of program and to reset ProcessData Initialize ProcessData variables to zero end ProcessDataLost - called when lead vehicle is lost Call ProcessDataInit to initialize variables end ProcessData Save parameter to SensorDist Get our previous return values and set new return values to same values if the motors are stopped if the lead vehicle is beyond target range save distance to target (SensorDist-TargetHigh) in DistOff set direction to forward else if the lead vehicle is below target range save distance to target (TargetLow-SensorDist) in DistOff set direction to reverse else (the vehicle is within target range) set NewMotorPower to zero endif if we are adjusting power (beyond or below) ; ; now to adjust power ; If we are within the low power adjustment range (< 5cm) set NewMotorPower to (1*DistOff) (e.g. 1%/cm) else set NewMotorPower to (2*DistOff) (e.g. 2%/cm) endif if NewMotorPower is greater than max allowed (20%) set NewMotorPower to 20% endif endif else (the trailer is moving) ; ; calculate some needed values for our operations/comparisons ; set DistChange to how far we've moved since last call set DistHigher flag to tru if our new distance is greater than prev dist set DistZero flag if our new distance is exactly the same set DistOff to the difference between our current distance and target distance set TgtBelow if we are below target distnce set TgtExact if we are exactly the target distance set CloserTgt if we are closer to target than we were before if we are not on target or distance has changed if moving forward if we are too close (TgtBelow == true) set ReducePower flag esle if we aren't closer than we were before set ReducePower flag else if we aren't catching up to correct position quickly enough set IncreasePower flag else set PowerOK flag endif else (we are moving backward) if we are too close (TgtBelow == true) set IncreasePower flag else if we aren't getting closer than we were before set ReducePower flag else if we aren't catching up to correct position quickly enough set IncreasePower flag else set PowerOK flag endif endif if IncreasingPower If we are within the low power adjustment range (< 5cm) set power increment to (1*DistOff) (e.g. 1%/cm) else set power increment to (2*DistOff) (e.g. 2%/cm) endif if power increment is greater than max allowed (20%) set power increment to 20% endif add power increment to NewMotorPower else if Reducing Power If we are within the low power adjustment range (< 5cm) set power decrement to (1*DistOff) (e.g. 1%/cm) else set power decrement to (2*DistOff) (e.g. 2%/cm) endif if power decrement is greater than max allowed (20%) set power decrement to 20% endif if power decrement is > existing power setting if current power is < 5% set NewMotorPower to zero else set NewMotorPower to PrevMotorPower/2 endif else subtract power increment from NewMotorPower endif else (power must be just right) ; nothign to do, current setting is OK endif endif /* reverse */ endif /* Moving */ if NewMotorPower > 100 (out of range high) set NewMotorPower to 100 endif save direction flag save motor power save distance end Source Code Main.asm ;****************************************************************************** ; * ; Filename: Main.asm * ; Date: 2/23/2012 * ; Authors: Adam Morse, Steve Hopkins, Conor P. Cahill * ; Company: UND, EE452, Spring 2012 * ; * ;-----------------------------------------------------------------------------; PROCESSOR DECLARATION ;-----------------------------------------------------------------------------LIST P=PIC18F46K22 ; list directive to define processor #INCLUDE <P18F46K22.INC> ; processor specific variable definitions #include "AutonomousTrailer.inc" ; Definitions for our project #include "Utilities.inc" ; ; get the processor configuration setup ; #include "ConfigProcessor.inc" ; ; external function references ; extern BackupBeeperInit, BackupBeeperEnable, BackupBeeperDisable, BackupBeeperUpdate extern HazardsInit, HazardsEnable, HazardsDisable, HazardsUpdate extern MotorInit, MotorUpdate, MotorEmergencyStop extern SensorInit, SensorRead extern ProcessData, ProcessDataLost, ProcessDataInit extern Delay_MS ; ; Local definitions ; MSTAT_BIT_LOST MSTAT_BIT_BKWRD MSTAT_BIT_NEED_BKWRD equ equ D'0' equ D'1' D'2' ; ; Reset Vector ; RES_VECT ORG GOTO 0x0000 START ; processor reset vector ; go to beginning of program ; ; High & Low priority interrupt vectors (just return for now) ; ISRH ORG RETFIE 0x0008 ISRL ORG RETFIE 0x0018 ;-----------------------------------------------------------------------------; MAIN PROGRAM ;-----------------------------------------------------------------------------START ; ; set clock to 16 mhz ; movf OSCCON,W,A andlw iorlw movwf b'10001111' b'01110000' OSCCON,A ; clear IRCF bits ; set IRCF to 111 = 16 MHz ; ; clear/initialize our registers ; clrf MainStatus ; ; Initialize all of the components ; Call SensorInit Call MotorInit Call HazardsInit Call BackupBeeperInit Call ProcessDataInit ; ; Slight delay to let everything quiesce before starting processing ; movlw D'200' movwf Arg1,A Call Delay_MS MainLoop: ; ; Read the distance sensor (no parameters to pass in) ; Call SensorRead ; ; Save the results ; movff Result1,MainSensorReading ; ; if there isn't an error, skip the error handling code ; movlw SNSR_LOSTVEHICLE cpfseq MainSensorReading,A bra MainSensorGood ; ; If we are already lost ; btfsc MainStatus,MSTAT_BIT_LOST,A bra MainAlertDone ; ; Set the lost status bit ; bsf MainStatus,MSTAT_BIT_LOST,A ; ; We've lost our lead vehicle, so we need to enable the hazards lights and stop the ; trailer ; Call HazardsEnable Call MotorEmergencyStop ; ; tell ProcessData we lost the vehicle ; Call ProcessDataLost MainAlertDone: ; ; Update the hazard lights (blinks them on/off periodically) (no args/return) ; Call HazardsUpdate ; ; skip to the end of the main loop ; bra MainLoopDone MainSensorGood: ; ; if we aren't in "lost" mode ; btfss MainStatus,MSTAT_BIT_LOST,A bra MainProcess ; ; Turn off hazards (motor will clear after process data) ; Call HazardsDisable ; ; clear "lost" status ; bcf MainStatus,MSTAT_BIT_LOST,A MainProcess: ; ; Go process the sensor data and calculate the motor ; movff MainSensorReading, Arg1 Call ProcessData ; ; remember if ProcessData set the reverse direction ; bcf MainStatus,MSTAT_BIT_NEED_BKWRD,A tstfsz Result2,A bsf MainStatus,MSTAT_BIT_NEED_BKWRD,A ; ; Update the motor settings with results from ProcessData ; movff Result1, Arg1 movff Result2, Arg2 Call MotorUpdate ; ; if the backward bit isn't set skip backwards code ; btfsc MainStatus,MSTAT_BIT_NEED_BKWRD,A bra MainMovingForward ; ; If backward status is alread set, skip setup code ; btfss MainStatus,MSTAT_BIT_BKWRD,A bra MainBackward_Process ; ; set backward status ; bsf MainStatus,MSTAT_BIT_BKWRD,A ; ; enable the backward beeper ; call BackupBeeperEnable bra MainLoopDone MainBackward_Process: ; ; Update the backward beeper ; Call BackupBeeperUpdate MainMovingForward: ; ; If we were not moving backwards, skip past cleanup code ; btfsc MainStatus,MSTAT_BIT_BKWRD,A bra MainLoopDone ; ; Turn off backup beeper ; Call BackupBeeperDisable ; ; clear backup status ; bcf MainStatus,MSTAT_BIT_BKWRD,A MainLoopDone: ; ; Delay 50ms between loop iterations ; movlw D'50' movwf Arg1,A Call Delay_MS goto MainLoop FINISHED: GOTO $ END ; stop here... ProcessData.asm ; ; ProcessData.asm - Functions used to process the sensor data and calculate motor ; configuration settings ; LIST P=PIC18F46K22 ; list directive to define processor #INCLUDE <P18F46K22.INC> ; processor specific variable definitions #INCLUDE "AutonomousTrailer.inc" ; Definitions for our project ; ; Define entry points that will be accessible from outside this file ; global ProcessData, ProcessDataInit, ProcessDataLost ; ; Local definitions ; TARGET_DIST TARGET_DIST_HIGH TARGET_DIST_LOW equ equ equ D'50' D'55' D'45' ; target follwing distance ; high allowed range ; low allowed range MAX_POWERINC DIST_LOW_POWER_INC equ equ D'20' D'5' ; maximum power change in one operation ; low pwer increases for DistOff < this ; ; Bit positions used to store data in PD_Status ; PDSTAT_DIR equ D'0' PDSTAT_DIST_ZERO equ D'1' PDSTAT_CLOSER_TGT equ D'2' PDSTAT_TGT_BELOW equ D'3' PDSTAT_TGT_ZERO equ D'4' PDSTAT_SENSOR_HIGHER equ D'5' ; ; Start of the code section ; Code ; ; Function: ProcessDataInit ; ; Purpose: To Initialize the registers used by ProcessData ; ; Parameters: none ; ; Returns: Nothing of any value ; ; Notes: ; ProcessDataInit: ; ; Initialize ProcessData variables ; clrf PD_PrevMPower clrf PD_Status return; ; ; ; ; ; ; ; ; ; Function: ProcessDataLost Purpose: Parameters: Returns: To reset things when we've lost the LV none Nothing of any value ; Notes: ; ProcessDataLost: Just call ProcessDataInit to do the work. call ProcessDataInit return; ; ; Function: ProcessData ; ; Purpose: To process the sensor distance data an determine a motor ; control power setting that will maintain the desired ; following distance ; ; Parameters: arg1 - the distance to the lead vehicle in centimeters ; ; Returns: Result1 - a pwer setting from 0 to 100% for the motor control ; Result2 - a direction bit (1=reverse, 0 = forward) ; ; Notes: ; ; Our goal is to follow along 50cm behind the lead vehicle (LV) and we allow ; a 10cm range (+/- 5CM) that we consider to be within range. As the distance ; increases we increase the power to the motor in order to catch up and get ; withiin the appropriate distance. When we start catching up, we start to ; decrease the power so that we ease into the desired range rather than having ; an abrupt power change once we're in range. ; ; when the vehicle does go out of the desired range, we try to bring it back to ; the exact midpoint of the range and then allow the range to take place ; ; In order to prevent radical jerky changes in motor power, we will limit the ; power change per operation to 20% ; ; ; ProcessData: ; ; save the parameter (distance sensor reading) ; movff Arg1, PD_SensorDist ; ; get the current settings for the direction and motor power ; movff PD_PrevDir, PD_NewDir movff PD_PrevMPower, PD_NewMPower ; ; if the motors aren't currently off (e.g. we are not stopped) ; go to check moving ; tstfsz PD_PrevMPower bra PD_CheckMoving ; ; if the lead vehicle is beyond the allowinable range ; movlw TARGET_DIST_HIGH cpfsgt PD_SensorDist bra PD_StopCheckSD_LT ; ; calculate the distance off target and set direction to forward ; movlw TARGET_DIST subwf PD_SensorDist,W,A movwf PD_DistOff,A bcf movlw movwf bra PD_Status,PDSTAT_DIR,A PD_DIRECT_FWD PD_NewDir,A PD_StopAdjustPower PD_StopCheckSD_LT: ; ; if the lead vehicle is below the allowinable range ; movlw TARGET_DIST_LOW cpfslt PD_SensorDist bra PD_StopCheckSD_EQ ; ; calculate the distance off target and set direction to reverse ; DistOff = TargetDistance - SensorDistance ; movlw TARGET_DIST movwf PD_DistOff,A movf PD_SensorDist,W,A subwf PD_DistOff,F,A bsf movlw movwf bra PD_Status,PDSTAT_DIR,A PD_DIRECT_REV PD_NewDir,A PD_StopAdjustPower PD_StopCheckSD_EQ: ; ; Else we're within range and should stay stopped ; clrf PD_NewMPower bra PD_Done PD_StopAdjustPower: ; ; Time to adjust our power based on the makeup distance ; ; if it's a small distance increment, ; increment power 1% per cm ; othersie ; incrment power 2% per cm ; and check to make sure we don't exceed max single iteration increment ; movlw DIST_LOW_POWER_INC cpfslt PD_DistOff,A bra PD_StopAdjustHighPower ; ; just use the distance for the lower power options (so 1cm=1%) ; movff PD_DistOff,PD_NewMPower bra PD_StopAdjustPowerDone PD_StopAdjustHighPower: ; ; for the high pwer options, shift PD_DistOff 1 position to left (*2) ; so we set it to 1cm=2%. ; RLNCF PD_DistOff,F,A ; ; if the result is greater than max increment, set it to max increment movlw MAX_POWERINC cpfslt PD_DistOff,A movwf PD_DistOff,A ; ; remember the new motor setting ; movff PD_DistOff, PD_NewMPower PD_StopAdjustPowerDone: ; ; OK, we're done with dealing with the stopped trailer ; bra PD_Done PD_CheckMoving: ; ; we know that we are moving and therefore we have to calculate if and by how much ; we should alter the power settings on the motors. To determine this we need to ; calculate the following values: ; ; PD_DistChange - how far we moved since the last change ; PD_Status(higher) - true if our new dist is > our prev dist ; PD_Status(zero) - true if we've stayed exactly the ; same distance ; PD_DistOff - how far we are off the target ; distance ; PD_Status(TgtBelow) - true if we're below the target distance ; PD_Status(TgtExact) - true if we're exactly on target ; PD_Status(CloserTGT) - true if we are closer to target distance ; ; ; calculate how far we've moved in the last iteration (absolute value) ; ; If SensorDistance < PrevDistance ; movf PD_PrevDist,W,A cpfslt PD_SensorDist bra PD_MV_SD_GT ; ; diff = PrevDist - SensorDistance ; clrf STATUS,A subfwb PD_SensorDist,W,A ; clear borrow bits ; ; SensorDistance is not higher than PrevDistance, so clear flag ; bcf PD_Status, PDSTAT_SENSOR_HIGHER bra PD_MV_SD_Done PD_MV_SD_GT: ; ; diff = SensorDistance - PrevDistance ; subwf PD_SensorDist,W,A ; ; if distance same (wreg == 0) tstfsz WREG,A bra PD_MV_SD_SetHigher ; ; set zero bit and clear higher bit ; bcf PD_Status,PDSTAT_SENSOR_HIGHER bsf PD_Status,PDSTAT_DIST_ZERO,A bra PD_MV_SD_Done PD_MV_SD_SetHigher ; ; set higher flag and clear zero flag ; bsf PD_Status,PDSTAT_SENSOR_HIGHER bcf PD_Status,PDSTAT_DIST_ZERO,A PD_MV_SD_Done: ; ; Remember our distance change ; movwf PD_DistChange,A ; ; calculate how far we are off the target distance ; remember if we are below/above/same as target distance ; ; If SensorDistance < TargetDistance ; movlw TARGET_DIST cpfslt PD_SensorDist bra PD_MV_TGT_GT ; ; diff = TargetDistance - SensorDistance ; PD_Status(closer) = TRUE ; clrf STATUS,A ; clear borrow bits subfwb PD_SensorDist,W,A bsf PD_Status,PDSTAT_TGT_BELOW,A bra PD_MV_TGT_Done PD_MV_TGT_GT: ; ; we aren't < Tgt, so clear below flag ; bcf PD_Status,PDSTAT_TGT_BELOW,A ; ; diff = SensorDistance - TargetDistance ; subwf PD_SensorDist,W,A ; ; set zero flag ; if diff is not zero ; clear zero flag ; bsf PD_Status,PDSTAT_TGT_ZERO,A tstfsz WREG,A bcf PD_Status,PDSTAT_TGT_ZERO,A PD_MV_TGT_Done: ; ; Remember our distance change ; movwf PD_DistOff,A ; ; Now to determin if we are closer to the LV or not ; ; ; start by clearing closer flag ; bcf PD_Status,PDSTAT_CLOSER_TGT ; ; if both TgtBelow and SensorHiger are true ; or both TgtBelow and SensorHiger are false - we are closer ; btfss PD_Status,PDSTAT_TGT_BELOW,A bra PD_MV_CL_CheckNotHigh btfss bra bra PD_Status,PDSTAT_SENSOR_HIGHER,A PD_MV_CL_Done PD_MV_CL_SetCloser PD_MV_CL_CheckNotHigh: btfsc bra PD_Status,PDSTAT_SENSOR_HIGHER,A PD_MV_CL_Done ; ; fall through to set closer flag ; PD_MV_CL_SetCloser: ; ; we are closer so set closer flag ; bsf PD_Status,PDSTAT_CLOSER_TGT PD_MV_CL_Done: ; ; we now have all the inputs we need, so lets go figure out any motor power ; and/or direction changes that we need ; ; ; if we are exactly on target AND distance hasn't changed ; btfss PD_Status,PDSTAT_TGT_ZERO,A bra PD_MV_CheckForward btfss PD_Status,PDSTAT_DIST_ZERO,A bra PD_MV_CheckForward ; ; there's no change to be made.... ; bra PD_Done PD_MV_CheckForward: ; ; First take a look at what we need to do if we are moving forward ; ; ; If we are moving backward, go to CheckReverse ; btfsc PD_Status,PDSTAT_DIR,A bra PD_MV_CheckReverse ; ; else if we're at SensorDistance < TargetDistance we're too close, go reduce power ; btfsc PD_Status,PDSTAT_TGT_BELOW,A bra PD_MV_ReducePower ; ; else if we are gaining on the LV, go immediately to reduce power ; btfss PD_Status,PDSTAT_CLOSER_TGT,A bra PD_MV_ReducePower ; ; if we are NOT catching up/closing the distance ; ; e.g. if( (Diff < 16) && (SensorDist-(Diff*8)) > TargetDistance ) ; ; Catching Up is defined as a distance difference >= 16 or when if we ; keep going at the current power for 8 more iterations we would be ; <= the target distance ; ; If we're already gaining 16cm since last iteration (unlikely) ; No need to increase power so skip it ; movlw D'16' ; limit to < 16 since we're gonna multiply by 8 cpfslt PD_DistChange,A bra PD_MV_OKPower ; ; if SensorDist-(DistChange*8) < TargetDist, we can skip changing as well ; movf PD_DistChange,W,A bcf STATUS,C,A rlcf WREG,W,A ; WREG = WREG * 2 (three times == WREG * 8) bcf STATUS,C,A rlcf WREG,W,A bcf STATUS,C,A rlcf WREG,W,A subwf PD_SensorDist,W,A movwf PD_Tmp,A movlw TARGET_DIST cpfsgt PD_Tmp bra PD_MV_OKPower ; ; go increase the power ; bra PD_MV_IncreasePower PD_MV_CheckReverse: ; ; Ok, if we got here we're going backwards so check to see if we need ; to increase or decrease power ; ; ; if we're at SensorDistance < TargetDistance we're too close, go increase power ; btfsc PD_Status,PDSTAT_TGT_BELOW,A bra PD_MV_IncreasePower ; ; else if we aren't getting closer to the TargetDistance, we need to go decrease power ; btfss PD_Status,PDSTAT_CLOSER_TGT,A bra PD_MV_ReducePower ; ; if we are NOT catching up/closing the distance ; ; e.g. if( (Diff < 16) && (SensorDist-(Diff*8)) > TargetDistance ) ; ; Catching Up is defined as a distance difference >= 16 or when if we ; keep going at the current power for 8 more iterations we would be ; <= the target distance ; ; If we're already gaining 16cm since last iteration (unlikely) ; No need to increase power so skip it ; movlw D'16' ; limit to < 16 since we're gonna multiply by 8 cpfslt PD_DistChange,A bra PD_MV_OKPower ; ; if SensorDist-(DistChange*8) < TargetDist, we can skip changing as well ; movf PD_DistChange,W,A bcf STATUS,C,A rlcf WREG,W,A ; WREG = WREG * 2 (three times == WREG * 8) bcf STATUS,C,A rlcf WREG,W,A bcf STATUS,C,A rlcf WREG,W,A subwf PD_SensorDist,W,A movwf PD_Tmp,A movlw TARGET_DIST cpfsgt PD_Tmp bra PD_MV_OKPower ; ; go reduce the power ; bra PD_MV_ReducePower PD_MV_IncreasePower: ; ; so now we know we need to increase power... ; ; ; start with a 1%/cm power change ; movff PD_DistOff,PD_PowerChange ; ; if we are beyond the low pwer range ; movlw DIST_LOW_POWER_INC cpfsgt PD_DistOff,A bra PD_MV_IncCheckMax ; ; for the high pwer options, shift PD_PowerChange 1 position to left (*2) ; so we set it to 1cm=2%. ; RLNCF PD_PowerChange,F,A PD_MV_IncCheckMax: ; ; if the result is greater than max increment, set it to max increment ; movlw MAX_POWERINC cpfslt PD_PowerChange,A movwf PD_PowerChange,A ; ; add the pwer change into the motor power ; movf PD_PowerChange,W,A addwf PD_NewMPower,F,A bra PD_Done PD_MV_ReducePower: ; ; so now we know we need to reduce power... ; ; ; start with a 1%/cm power change ; movff PD_DistOff,PD_PowerChange ; ; if we are beyond the low pwer range ; movlw DIST_LOW_POWER_INC cpfsgt PD_DistOff,A bra PD_MV_RedCheckMax ; ; for the high pwer options, shift PD_PowerChange 1 position to left (*2) ; so we set it to 1cm=2%. ; bcf STATUS,C,A rlcf PD_PowerChange,F,A PD_MV_RedCheckMax: ; ; if the result is greater than max increment, set it to max increment ; movlw MAX_POWERINC cpfslt PD_PowerChange,A movwf PD_PowerChange,A ; ; if the decrement is larger than the current power setting ; movf PD_PowerChange,W,A cpfslt PD_NewMPower,A bra PD_MV_RedSubtract ; ; if the current power is <= 5, set it to zero ; movlw D'5' cpfsgt PD_NewMPower,A bra PD_MV_RedSetZero ; ; Otherwise Set power to half of its existing value ; bcf STATUS,C,A rrcf PD_NewMPower,F,A bra PD_MV_RedDone PD_MV_RedSetZero: ; ; set power to zero ; clrf PD_NewMPower; bra PD_MV_RedDone PD_MV_RedSubtract: ; ; add the pwer change into the motor power ; movf PD_PowerChange,W,A subwf PD_NewMPower,F,A PD_MV_RedDone: bra PD_Done PD_MV_OKPower: ; ; Nothing to do - power is already OK ; bra PD_Done PD_Done: ; ; if NewMPower is greater than 100, limit it to 100 ; movlw D'100' cpfslt PD_NewMPower,A movwf PD_NewMPower,A ; ; save the old distance value ; movff PD_SensorDist,PD_PrevDist ; ; save the new settings for power & direction and ; place them in the return registers ; movff PD_NewMPower,PD_PrevMPower movff PD_NewMPower,Result1 movff movff return end PD_NewDir,PD_PrevDir PD_NewDir,Result2 MotorControl.asm ; ; MotorControl.asm - definition of functions used ; LIST P=PIC18F46K22 ; #INCLUDE <P18F46K22.INC> ; #INCLUDE "AutonomousTrailer.inc" ; to setup/control the motors list directive to define processor processor specific variable definitions Definitions for our project ; ; Local definitions ; MSTAT_REVERSE equ 0x01 MOTOR_SET_FWD MOTOR_SET_REV MOTOR_SET_OFF equ b'11010000' equ b'10101000' equ b'01010000' ; ; Define entry points that will be accessible from outside this file ; global MotorInit, MotorUpdate, MotorEmergencyStop ; ; Start of the code section ; Code ; ; Function: ; ; Purpose: ; ; Parameters: ; ; Returns: ; ; Notes: ; MotorInit: MotorInit Initialize the Motor Controls None Nothing of any value ; ; Configure the Timer 2 period register for PWM mode. We have a 16Hz clock and ; desire a 15Khz PWM frequency so: 16M/4/4/15K - 1 = 66 ; movlw d'66' movwf PR2,A ; ; configure CCP1 and CCP2 pin on PORT C for output ; bcf TRISC,CCP1,A bcf TRISC,CCP2_PORTC,A ; ; Clear Timer2 count and configure Timer2 as follows: ; ; b7='0' - unimplemented ; b6-3='0000' - no ouput post scaling ; b2='1' - enable timer ; b1-0='01' - prescaler is 4 (so Timer = (FOSC/4)/4 = 1Mhz) ; clrf TMR2,A movlw b'00000101' movwf T2CON,A ; ; Associate Timer2 with PWM1 and PWM2 ; movlb 0x0f movf andlw movwf movlb CCPTMRS0,W,A b'11100100' ; both C2TSEL and C1TSEL set to 0 CCPTMRS0,BANKED 0x00 ; ; Enable PWM Mode on CCP1 and CCP2 ; ; b7-6='00' - unimplmented ; b5-4='00' - LOW order bits of PWM Duty Cycle ; b3-0='1100' - Enable PWM Mode movlw 0x0C movwf CCP1CON,A movwf CCP2CON,A ; ; Configure pins 7-3 on PortC for use as output (motor control) ; ; We are using: ; ; RC7 - EN (enable bit on motor control board) ; RC6 - IN1_M1 - Motor 1 input 1 ; RC5 - IN2_M1 - Motor 1 input 2 ; RC4 - IN1_M2 - Motor 2 input 1 ; RC3 - IN2_M2 - Motor 2 input 2 ; movf TRISC,W,A andlw b'00000111'; clear TRISC bits<7:3> to set pins as output movwf TRISC,A ; ; Start with the motor off ; movlw MOTOR_SET_OFF movwf PORTC,A return ; ; Function: ; ; Purpose: ; ; ; Parameters: ; ; ; Returns: ; ; Notes: ; MotorUpdate: MotorUpdate Update the motor control settings based on a desired increase or decrease in power as indicated in Arg1 Arg1 - the desired motor power percentage (0-100) Arg2 - the desired direction (1=reverse, 0=forward) nothing of any value ; ; Notes: ; From the spec, CPRxH doesn't need to be set -- it's read-only in PWM mode ; The low order 2 bits of duty cycle settings are in CCPxCON b5-4. ; ; ; default settings are for the motor to be turned off -- this will get changed ; as we parse the input (most likely) ; movlw MOTOR_SET_OFF movwf MotorSettings, A ; ; get the passed in power percentage ; movf Arg1,W,A movwf movwf movwf movwf CCPR1L,A CCPR1H,A CCPR2L,A CCPR2H,A ; ; if direction is forward ; tstfsz Arg2,A bra MotorReverse ; ; Set motor settings to indicate forward ; movlw MOTOR_SET_FWD ; ; clear the reverse bit in the status ; bcf MotorStatus, MSTAT_REVERSE bra MotorSetup MotorReverse: ; ; Set motor settings to indicate reverse ; movlw MOTOR_SET_REV ; ; set the status to indicate reverse ; bsf MotorStatus, MSTAT_REVERSE MotorSetup: ; ; remember motor settings ; movwf MotorSettings, A ; ; Pass the motor settings out the port ; movff MotorSettings, PORTC return ; ; Function: MotorEmergencyStop ; ; Purpose: Initialize the Motor Controls ; ; Parameters: None ; ; Returns: Nothing of any value ; ; Notes: Just set the duty cycle to zero ; MotorEmergencyStop: ; ; set duty cycle to zero ; clrf CCPR1L,A clrf CCPR1H,A clrf CCPR2L,A clrf CCPR2H,A ; ; turn the motors off ; movlw MOTOR_SET_OFF movwf MotorSettings, A movff MotorSettings, PORTC return end Sensor.asm ; ; Sensors.asm - definitions functions used to configure and/or read the sensors ; LIST P=PIC18F46K22 ; list directive to define processor #INCLUDE <P18F46K22.INC> ; processor specific variable definitions #INCLUDE "AutonomousTrailer.inc" ; Definitions for our project ; ; Define entry points that will be accessible from outside this file ; global SensorInit, SensorRead ; ; Start of the code section ; Code ; ; Function: ; ; Purpose: ; ; Parameters: ; ; Returns: ; ; Notes: ; SensorInit: SensorInit To initialize the sensor configuration None Nothing of any value None ; ; Configure portA for input and set first bit for analog input ; clrf PORTA,A clrf ANSELA,A bsf ANSELA,ANSA2 bsf TRISA,RA2 ; ; Configure ADCON2: ; ; b7='1' - Right justified output ; b6='0' - unimplemented ; b5-3='100' - 8 TAD ; b2-0='020' - Conversion clock= FOSC/32 ; movlw B'10100010' movwf ADCON2,A ; ; Configure ADCON1: ; ; b7='0' - use CCP5 trigger ; b6-4='000' - unimplemented ; b3-2='00' - use internal AVdd for A/D Vref+ ; b1-0='00' - use internal Avss for A/D Vref; movlw B'00000000' movwf ADCON1,A ;Configure ADCON1, Internal ref ; ; Configure ADCON0: ; ; b7='0' - unimplemented ; b6-2='00010' - use AN2 for analog input ; b1='0' - No conversion in progress yet ; b0='1' - ADC is enabled ; movlw B'00001001' movwf ADCON0,A ;Configure ADCON0, AN2, ADC ON return ; ; Function: ; ; Purpose: ; ; Parameters: ; ; Returns: ; ; ; ; Notes: ; ; SensorRead: SensorRead To read the distance sensor None The low order 8 bits of the distance to the lead vehicle or 0xFF if there was an error or the vehicle is too far ahead We do not delay within the sensor function. Instead we depend upon a delay in the main loop between each iteration ; ; enable ADC conversion ; BSF ADCON0,GO ; start conversion ; ; Loop until the conversion is done ; adcpoll: BTFSC BRA ADCON0,DONE adcpoll ; ; Move the results into WREG and Result1 ; movf ADRESL, W, A movwf Result1,A ; ; if the high order register is not zero, we have an error ; Either the trailer is too far ahead or there was actuall an ; error in the sensor. In both cases we flag an error ; tstfsz ADRESH,A bra SensorRead_SetError ; ; check to see if we are less than 20CM from the vehicle (below ; the range for our sensor) ; movlw D'20' cpfslt ADRESL,A bra SensorRead_Done ; ; fall through to set error code when < 20CM SensorRead_SetError: ; ; set errror code in Result1 ; movlw SNSR_LOSTVEHICLE movwf Result1,A bra SensorRead_Done SensorRead_Done: return end Beeper.asm ; ; BackupBeeper.asm - Functions used to manage the backup Beeper ; LIST P=PIC18F46K22 ; list directive to define processor #INCLUDE <P18F46K22.INC> ; processor specific variable definitions #INCLUDE "AutonomousTrailer.inc" ; Definitions for our project ; ; Define entry points that will be accessible from outside this file ; global BackupBeeperInit, BackupBeeperEnable, BackupBeeperDisable, BackupBeeperUpdate ; ; local definitions ; BESTAT_ENABLED BESTAT_ON equ equ D'0' D'1' BE_CYCLE_ON_COUNT BE_CYCLE_OFF_COUNT equ equ D'10' D'20' ; approx .5 seconds ; approx 1 second BE_PWM_FREQ BE_PWM_ON_DUTYC BE_PWM_OFF_DUTYC equ equ equ D'200' D'100' D'0' ; 1300hz from (16M/4)/16/1300 ; moderate volume (25% of BW_PWM_FREQ) BE_PORT BE_PIN BE_PORT_CTRL equ PORTA equ RA5 equ TRISA ; Beeper is connected to PORTA:5 ; ; Start of the code section ; Code ; ; Function: BackupBeeperInit ; ; Purpose: To initialize the backup Beeper ; ; Parameters: ; ; Returns: ; ; Notes: ; BackupBeeperInit: ; ; The SFRs for the backup beeper are outside of the access bank, so we need to ; load the BSR (0xf) and use it for operations ; movlb 0x0F ; ; Configure the Timer 4 period register for PWM mode. We have a 16Hz clock and ; desire a 1300hz PWM frequency so: 16M/4/16/1300 - 1 = 200 ; movlw d'200' movwf PR4,BANKED ; ; configure RB5 pin on PORT B for output ; bcf TRISB,RB5,A ; ; Clear Timer4 count and configure Timer4 as follows: ; ; b7='0' - unimplemented ; b6-3='0000' - no ouput post scaling ; b2='1' - enable timer ; b1-0='01' - prescaler is 4 (so Timer = (FOSC/4)/4 = 1Mhz) ; clrf TMR4,A movlw b'00000101' movwf T4CON,BANKED ; ; Associate Timer4 with PWM3 ; movf CCPTMRS0,W,A andlw b'00111111' iorlw b'01000000' movwf CCPTMRS0,BANKED ; C3TSEL set to '01' = Timer4 ; ; Enable PWM Mode on CCPR3 ; ; b7-6='00' - unimplmented ; b5-4='00' - LOW order bits of PWM Duty Cycle ; b3-0='1100' - Enable PWM Mode ; movlw 0x0C movwf CCP3CON,BANKED ; ; clear the status word (indicateds disabled) ; clrf BE_Status ; ; reset BSR ; movlb 0x00 return ; ; Function: BackupBeeperEnable ; ; Purpose: To Enable the backup Beeper ; ; Parameters: None ; ; Returns: None ; ; Notes: ; BackupBeeperEnable: ; ; set status to enabled ; bsf BE_Status,BESTAT_ENABLED,A ; ; set the on indicator ; bsf BE_Status,BESTAT_ON,A ; ; set the on cycle count-down timer ; movlw BE_CYCLE_ON_COUNT movwf BE_Counter,A ; ; The SFRs for the backup beeper are outside of the access bank, so we need to ; load the BSR (0xf) and use it for operations ; movlb 0xf ; ; turn on the output ; movlw BE_PWM_ON_DUTYC movwf CCPR3L,BANKED ; ; reset BSR ; movlb 0x00 return ; ; Function: BackupBeeperDisable ; ; Purpose: To Enable the backup Beeper ; ; Parameters: None ; ; Returns: None ; ; Notes: ; BackupBeeperDisable: ; ; The SFRs for the backup beeper are outside of the access bank, so we need to ; load the BSR (0xf) and use it for operations ; movlb 0xf ; ; turn off the PWM ; movlw BE_PWM_OFF_DUTYC movwf CCPR3L,BANKED ; ; turn off the beeper ; bcf BE_PORT,BE_PIN ; ; set status to disabled ; bcf BE_Status,BESTAT_ENABLED,A ; ; reset BSR ; movlb 0x00 return ; ; Function: BackupBeeperUpdate ; ; Purpose: To update the BackupBeeper status (turn on/off) each iteration ; ; Parameters: None ; ; Returns: None ; ; Notes: ; BackupBeeperUpdate: ; ; decrement the countdown counter and return if not zero ; decfsz BE_Counter,F,A bra BEU_Done ; ; if we get here, the counter has run out so time to change the ; state of the beeper ; ; ; The SFRs for the backup beeper are outside of the access bank, so we need to ; load the BSR (0xf) and use it for operations ; movlb 0xf ; ; if they are on ; btfss BE_Status,BESTAT_ON,A bra BEU_TurnEmOn ; ; turn off the PWM ; movlw BE_PWM_OFF_DUTYC movwf CCPR3L,BANKED ; ; set the off countdown counter ; movlw BE_CYCLE_OFF_COUNT movwf BE_Counter,A ; ; flag that they are off ; bcf BE_Status,BESTAT_ON,A bra BEU_Done BEU_TurnEmOn: ; ; turn on the PWM ; movlw BE_PWM_ON_DUTYC movwf CCPR3L,BANKED ; ; set the on countdown counter ; movlw BE_CYCLE_ON_COUNT movwf BE_Counter,A ; ; flag that they are on ; bsf BE_Status,BESTAT_ON,A BEU_Done: ; ; reset BSR ; movlb 0x00 return end Hazards.asm ; ; Hazards.asm - Functions used to manage the Hazard LEDs ; LIST P=PIC18F46K22 ; list directive to define processor #INCLUDE <P18F46K22.INC> ; processor specific variable definitions #INCLUDE "AutonomousTrailer.inc" ; Definitions for our project ; ; Define entry points that will be accessible from outside this file ; global HazardsInit, HazardsEnable, HazardsDisable, HazardsUpdate ; ; Local definitions ; HZSTAT_ENABLED HZSTAT_ON equ D'0' equ D'1' HZ_CYCLE_ON_COUNT HZ_CYCLE_OFF_COUNT equ D'15' equ D'20' ; approx .75 seconds ; approx 1 second HZ_PORT HZ_PIN HZ_PORT_CTRL equ PORTB equ RB2 equ TRISB ; Hazards are connected to PORTB:2 ; ; Start of the code section ; Code ; ; Function: ; ; Purpose: ; ; Parameters: ; ; Returns: ; ; Notes: ; ; HazardsInit: ; ; ; bcf HazardsInit To initialize the backup beeper The hazards are controlled by a relay connected to digital port AN5 enable the port for output HZ_PORT_CTRL,HZ_PIN,A ; ; clear the status word (indicateds disabled) ; clrf HZ_Status return ; ; ; ; ; ; ; ; ; ; ; Function: HazardsEnable Purpose: To Enable the backup beeper Parameters: None Returns: None Notes: HazardsEnable: ; ; set status to enabled ; bsf HZ_Status,HZSTAT_ENABLED,A ; ; set the lights on indicator ; bsf HZ_Status,HZSTAT_ON,A ; ; set the on cycle count-down timer ; movlw HZ_CYCLE_ON_COUNT movwf HZ_Counter,A ; ; turn on the output pin ; bsf HZ_PORT,HZ_PIN return ; ; Function: HazardsDisable ; ; Purpose: To Enable the backup beeper ; ; Parameters: None ; ; Returns: None ; ; Notes: ; HazardsDisable: ; ; turn off the hazards ; bcf HZ_PORT,HZ_PIN ; ; set status to disabled ; bcf HZ_Status,HZSTAT_ENABLED,A return ; ; Function: ; ; Purpose: ; ; Parameters: ; ; Returns: ; ; Notes: ; HazardsUpdate: HazardsUpdate To update the Beeper status (turn on/off) each iteration None None ; ; decrement the countdown counter and return if not zero ; decfsz HZ_Counter,F,A bra HZU_Done ; ; if we get here, the counter has run out so time to change the ; state of the hazards ; ; ; if they are on ; btfss HZ_Status,HZSTAT_ON,A bra HZU_TurnEmOn ; ; turn them off ; bcf HZ_PORT,HZ_PIN ; ; set the off countdown counter ; movlw HZ_CYCLE_OFF_COUNT movwf HZ_Counter,A ; ; flag that they are off ; bcf HZ_Status,HZSTAT_ON,A bra HZU_Done HZU_TurnEmOn: ; ; turn them on ; bsf HZ_PORT,HZ_PIN ; ; set the on countdown counter ; movlw HZ_CYCLE_ON_COUNT movwf HZ_Counter,A ; ; flag that they are on ; bsf HZ_Status,HZSTAT_ON,A HZU_Done: return end Utilities.asm LIST P=PIC18F46K22 ; list directive to define processor #INCLUDE <P18F46K22.INC> ; processor specific variable definitions #INCLUDE "AutonomousTrailer.inc" ; Definitions for our project ; ; Define entry points that will be accessible from outside this file ; global Delay_S, Delay_MS ; ; Start of the code section ; Code ; ; ; ; ; ; ; ; ; ; ; ; ; Function: Delay_S Purpose: Parameters: to delay exeuction for a specified number of seconds Arg1 - # of seconds to delay Returns: nothing of any value Notes: We use the thousandths of a second delay function to do the real work and just loop through successive calls of delays of 100 thousandths of a second Delay_S: movff Arg1, UtilDS_Outer movlw movwf D'10' UtilDS_Inner,A movlw movwf call D'100' Arg1,A Delay_MS Delay_S_Outer: Delay_S_Inner: decfsz UtilDS_Inner,F bra Delay_S_Inner decfsz UtilDS_Outer,F bra Delay_S_Outer return ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; Function: Purpose: Parameters: Delay_MS to delay exeuction for a specified number of thousandths of a second (1-255) (so 10 = 1/100 second) Arg1 - # of hundredths of a second to delay Returns: nothing of any value Notes: We have a 16Mhz clock, so for each hundredth of a second we need to execute approximately 4K instructions. Given that our loop counters are 8 bit numbers, we need 3 levels of loops. The inner two levels create a 1/100 second delay while the outer loop works with the number of hundredths of a second parameter passed in. To execute 4K instructions, we have an inner loop that contains 17 instruction cycles (7 gotos, one DECFSZ and one branch). This loop is executed 25 times which gives ; ; ; ; ; ; ; ; ; ; ; ; ; us 25*17-1 or 424 instructions. The loop overhead in the middle loop consists of 20 instruction cycles and this loop is executed 9 times (424+21)*9-1 = 3995 instruction cycles. The outer loop will have 5 extra instruction cycles per loop execution, bringing the total to 4000 cycles per outer loop. The function function will have 5 instruction cycles of overhead (4 for the call/return and one for saving of WREG) so the delay will be slightly longer Delay_MS: ; ; save Arg1 in our outer loop counter ; movfF Arg1,UtilDMS_Outer OuterLoop: movlw movwf D'9' UtilDMS_Middle,A ; with 103 iterations of the inner loop, we execute 2069 instructions ; per iteration of the middle loop MiddleLoop: movlw movwf D'25' UtilDMS_Inner,A InnerLoop: goto $+2 goto $+2 goto $+2 goto $+2 goto $+2 goto $+2 goto $+2 decfsz UtilDMS_Inner,F bra InnerLoop goto $+2 goto $+2 goto $+2 goto $+2 goto $+2 goto $+2 goto $+2 nop decfsz UtilDMS_Middle, F bra MiddleLoop decfsz UtilDMS_Outer, F bra OuterLoop return end AutonomousTrailer.inc ; ; Global defined values and register definitions for the Autonomous Trailer ; project. ; ; ; Sensor definitions ; SNSR_LOSTVEHICLE equ 0xFF ; ; ProcessData definitions ; PD_DIRECT_FWD equ D'0' PD_DIRECT_REV equ D'1' ; ; Motor control Definitions ; MC_RES1_BIT_DIR equ 0 ; set to 1 if we are moving backwards ; ; Function Call Interface Registers ; Arg1 set 0x01 Arg2 set 0x02 Arg3 set 0x03 Result1 set 0x05 Result2 set 0x06 Result3 set 0x07 ; ; Main Loop registers ; MainStatus set 0x10 MainSensorReading set 0x11 ; ; Sensor/Hazard/Beeper registers ; HZ_Status set 0x20 HZ_Counter set 0x21 BE_Status set 0x22 BE_Counter set 0x23 ; ; Motor Control Registers ; MotorStatus set 0x30 MotorSettings set 0x31 ; ; Utility Registers ; UtilDS_Outer set 0x40 UtilDS_Inner set 0x41 UtilDMS_Outer set 0x42 UtilDMS_Middle set 0x43 UtilDMS_Inner set 0x44 ; ; ProcessData Registers ; PD_Status set 0x50 PD_PrevMPower set 0x51 PD_NewMPower set 0x52 PD_NewDir set 0x53 PD_PrevDir set 0x54 PD_DistChange set 0x55 ; the current motor setting PD_DistOff PD_Tmp PD_SensorDist PD_PowerChange PD_PrevDist set set set set set 0x56 0x57 0x58 0x59 0x5A ; ; Timers ; ; Timer2 - PWM control for moters ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; ; I/O Port reservations Port A: RA2 - used for ADC input port AN2 Port B: RB2 - Hazards RB5 - CCP3/P3A - Beeper pwm Port C: RC7 - EN RC6 - IN1_M1 RC5 - IN2_M1 RC4 - IN1_M2 RC3 - IN2_M2 RC2 - CCP1/P1A - Motor 1 PWM RC1 - CCP2/P2A - Motor 2 PWM ConfigProcessor.inc ; ; Configuration bit settings (copied from template) ; ;Setup CONFIG11H CONFIG FOSC = INTIO7, PLLCFG = OFF, PRICLKEN = OFF, FCMEN = OFF, IESO = OFF ;Setup CONFIG2L CONFIG PWRTEN = OFF, BOREN = OFF, BORV = 190 ;Setup CONFIG2H CONFIG WDTEN = OFF, WDTPS = 1 ;Setup CONFIG3H CONFIG MCLRE = EXTMCLR, CCP2MX = PORTC1, CCP3MX = PORTB5, HFOFST = OFF, T3CMX = PORTB5, P2BMX = PORTD2 ;Setup CONFIG4L CONFIG STVREN = OFF, LVP = OFF, XINST = OFF ;Setup CONFIG5L CONFIG CP0 = OFF, CP1 = OFF, CP2=OFF, CP3=OFF ;Setup CONFIG5H CONFIG CPB = OFF, CPD = OFF ;Setup CONFIG6L CONFIG WRT0 = OFF, WRT1 = OFF, WRT2 = OFF, WRT3 = OFF ;Setup CONFIG6H CONFIG WRTB = OFF, WRTC = OFF, WRTD = OFF ;Setup CONFIG7L CONFIG EBTR0 = OFF, EBTR1 = OFF, EBTR2 = OFF, EBTR3 = OFF ;Setup CONFIG7H CONFIG EBTRB = OFF Utilities.inc ; ; External symbols and definitions used by Utlities.asm ; ; This should be included by code modules that want to invoke functions defined in Utilities.asm ; extern Delay_MS, Delay_S Hardware Systems Hardware Description The hardware consists of a dual motor tracked chassis made by Dagu Electronics called the Rover 5. This kit came with 2 DC motors with 87:1 gear ratios to provide extra torque and optional wheel encoders. Other kits came with 4 motors, but the front 2 motors were disabled by removing one of the interconnecting gears in the transmission. The optional encoders were omitted because this project did not require absolute speed control. To maintain a fixed distance from the lead object, an ultrasonic distance sensor was used. The XL−MaxSonar−AE4, made by MaxBotics, emits a 44 kHz tone and internally measures the time between the transmission and the echo to determine the distance. Using this distance as the feedback mechanism to the MCU, we are able to control the speed of the motors to maintain a fixed distance of 50 cm to our target. The motor control consists of a motor driver chip by Freescale (MC33926) and the PWM function in the Microchip PIC18F46K22 MCU. The MCU is the heart of the system. It ties together the sensor readings, motor speed, back-up beeper, and hazard lights. Power Circuits: A single 9V battery is fed into an LM2940S-5.0 voltage regulator. It converts the 9 VDC to 5 VDC used to power the MCU and peripherals. A separate battery pack with six 1.2 VDC NiMH batteries connected in series provides up to 7.2 VDC to the motor driver H-bridge FET switches to power the motors. Having separate power sources insures that the power hungry and noisy motors do not interfere with the logic systems and cause brownout conditions or intermittent behavior in the MCU. Schematics Test Plan and Results The objective in testing the Autonomous Trailer is to determine the success of both the hardware and software design. Each functional component of the system will have a test assigned to it, and will be evaluated based on an appropriate criteria. Some components cannot be adequately tested quantitatively and will be given a qualitative assessment. After testing each component as independently as possible, the system as a whole will be evaluated as far as it meets the design objectives. 1. Distance Sensor 2. Data Processing 3. System Operation and Motor Control 1. Distance Sensor The distance sensor will be tested under three physical conditions: 20cm, 50cm and 100cm. 20cm indicates the smallest value that the sensor can reliably read and 100cm represents a high value for what we’d expect to measure. For our purposes, we also test the sensor at 50cm because that is our Trailer’s defined set point. At each distance, with an obstruction appropriately placed, an analog and digital reading will be taken. Analog measurement will be taken directly from the sensor output with a digital multimeter; while digital measurements will be taken using the watch-window in the MPLAB development environment. 20cm: Expected analog reading: 98mV (4.9mV/cm per datasheet) Expected digital reading: 20 Observed analog reading: 108 mV Observed digital reading: 0x16 or 22 50cm: Expected analog reading: 245mV (4.9mV/cm per datasheet) Expected digital reading: 50 Observed analog reading: 246mV Observed digital reading:0x30 or 36 100cm: Expected analog reading: 490mV (4.9mV/cm per datasheet) Expected digital reading: 100 Observed analog reading: 491mV Observed digital reading: 0x67 or 48 Conclusions: The conclusions for the distance sensor are impressive. The inaccuracies of the voltmeter and the manually measured distances may account for the differences between expected and observed results. We were also impressed at how well our ADC translated the analog values to accurate digital ones. A future study might be made of the accuracy of ultrasonic sensors versus other types of sensors (eg infrared). 2. Data Processing This software section of the system translates information from the distance sensor to a useable value for the motor control stage. It needs to compare the digital distance sensor values it receives to a pre-defined set-point (for our purposes, 50cm), and adjust the motor output value to force the vehicle to better approximate the set-point through its speed. By simulating different distance situations, we can show the processing stages ability to adjust the speed of the vehicle either up or down. Some of the situations are as follows. When the distance sensor is continually out of range high, we want the processing stage to recognize this as an error, bring the vehicle to a stop and put the hazards on. When the distance is high, but not out of range, we want the processing unit to output a high incremented speed value. When the distance is low, we expect a lower incremented value. When the distance is right on (50cm), we want to maintain the trailer’s current distance. Likewise we want to test that the processing unit signals a deceleration when the distance is below the set-point. All of these tests can be verified by using the watch window functionality of the MPLAB environment. 3. System Operation and Motor Control For this section, we are interested in the system’s ability as a whole to serve the defined objective. That objective is to maintain a defined following distance from a lead vehicle or simulated obstruction. This is a qualitative test. For the first test (the Collision Test), we run the Autonomous Trailer with a simulated lead vehicle in front of it, maintaining the defined 50cm. When the lead vehicle comes to an abrupt stop, we want to verify that the Autonomous Trailer quickly comes to a stop as well. Our group tested with more primitive design than is currently under development (improvements were conceived based partly on these tests). In this case, the PWM duty-cycle for the motors was basically made identical to the value of the distance sensor. 1. Collision Test: After running smoothly at its max speed, our Autonomous Vehicle came to a stop 30cm before the fixed obstruction. Conclusion: The reason for the 30cm stopping distance can be interpolated from our design. To be clear, this test was not run with the 50cm set-point that we devised for later designs. For this test, the distance values directly controlled the PWM duty-cycle. At 30cm the PWM duty-cycle was reduced to such a level that the motors could not overcome the resistance of the tracks and the friction of the floor. We know 30cm is less than 50% duty-cycle, and that appears to have been the threshold It was surely a success for us that the vehicle did not crash into the obstruction. For our more sophisticated design, we sought to achieve a more proportional control of the vehicle and maintain a fixed set-point through incremental control. The added functionality of moving in reverse, hazard lights and a buzzer also improved on this early design. For the second test, we are interested in the ability of our control system and motors to respond to the gradual changes of speed in the lead vehicle. We are interested in the ability of the Trailer to gradually increase in speed, gradually decrease in speed and to switch to reverse. 2. Direction and Speed Test For this test, we observe the vehicle traveling slowly to maintain a distance and then accelerating to catch up with a speeding lead car. Clearly the vehicle’s max speed is often less than that of the moving obstruction. This means that Autonomous Trailer is frequently operating at its peak speed. One of the conditions we were concerned about was the vehicle’s oscillation around a set-point. Because of the slow speed of the vehicle (10cm/s), overshooting the set-point appeared not to be a problem. Clearly the lower % PWM duty-cycle values (as low as 50%) were inhibited by the resistance of the tracks. We may incorporate this fact into future code. A YouTube video of the vehicle in action has been uploaded to: http://www.youtube.com/watch?v=zsaG9soie4 Conclusions The goal of this project was to prove the concept that you can follow a moving object with a microcontroller and a distance sensor to maintain a set distance. The complexity was in creating the algorithm and associated software. We each successfully built our own vehicles with all of the core features working. To make this a more robust system, a bit more code polishing may be required. In the future, adding in an encoder to measure and track the absolute speed could be implemented to improve on the design. References PIC ® Microcontroller: An Introduction to Software & Hardware Interfacing, Huang, ISBN 1-4018-3967-3 www.pololu.com Appendixes Time Tracking Time was allocated evenly between all three group members. Task Steve Hopkins Conor Cahill Adam Morse Percentage of allocated time Total Research and Planning 5% 3.75 hrs Algorithm Development and coding 70% 52.5 hrs Simulation and Testing 20% 15 hrs Documentation 5% 3.75 hrs Total group hours (25hr * 3 people) 75 hrs User Manual 1. Safety Concerns 2. Setup 3. Using Your Autonomous Vehicle 4. Shutdown and Storage 5. Troubleshooting 6. System Components Safety Concerns Your new Autonomous Trailer is an easy-to-use, fun demonstration tool for simulating collision avoidance systems. Yet with all electrical systems, there are important safety considerations to keep in mind. • • • • Adult Supervision: the Autononmous Trailer should not be used without adult supervision Pinch Points: exercise caution when handling the robot, as the tracks can begin moving unexpectedly creating a pinch point between the wheels and the tracks Unintended Additions: make no modifications to the existing system in particular do not power the device by anything other than the supplied 9V battery Shock Hazard: the Autonomous Trailer operates at low voltages yet it still important not to contact exposed terminations and not to remove the 9V battery while the tracks are in motion Setup The Trailer is easy to set up straight out of the box. Its programming is done in advance and all the pieces come pre-assembled. The following elements are all that is involved: • • • • • • • If you must operate the vehicle outside, only do so in a clean environment Avoid operating the vehicle in the rain or in dusty/dirty conditions Pick the vehicle up by the chassis and avoid touching PCB boards whenever possible Ensure that the microcontroller demoboard always is firmly attached to the chassis assembly (via the supplied rubber bands or other means) Place the car on your knee (or similar block) for setup such that the treads do not make contact with any surface Adjust the ultrasonic distance sensor so that it is level to the ground and points directly ahead of the vehicle Tuck all stray wires into the cab of the vehicle so they do not make contact with the tracks • • If a ‘lead car’ is to be used, place it a couple of feet in front of where the Autonomous Trailer will begin its course Remove all obstructions from the straight path along where the cars will travel 3. Using Your Autonomous Vehicle • • • • • Attach the 9V battery to the demoboard Plug the ENABLE pin plugged into the demoboard at RC7 After the tracks have begun to turn, place the vehicle on the floor behind the object that is to follow The Autonomous Trailer is designed to track 50cm behind the lead vehicle It will adjust its speed, and move forward and backwards, based on the movement of the lead vehicle 4. Shutdown and Storage • • • • • To shut the device off, first lift it off the ground Remove the ENABLE pin at RC7 Remove the 9V battery from the demoboard Remove the tracks from the vehicle to lessen the strain on the wheels and gearbox Store in a dry environment 5. Troubleshooting • • If the vehicle does not follow the target while in its operating range (45 cm to 55cm): o Adjust the distance sensor so that it points more directly at the object o Modify the lead vehicle so that it can be better recognized by the trailer (tape a vertical piece of cardboard on it, for instance) o Ensure that the lead vehicle does not exceed the Autonomous Trailer max speed of 10cm per second o Ensure that the distance sensor wires are firmly plugged into the demoboard o Confirm that wires are in the correct terminals (see Hardware Schematic) If the vehicle struggles to move: o Relocate to a surface with less friction o Ensure the all terminations between the motor controller, battery pack and demoboard are adequately connected 6. System Components Distance Sensor Microcontroller Demoboard 9V Battery location Robot Chassis I/O Terminal Block Motor Control Board Datasheets Rover 5 Rover 5 is a new breed of tracked robot chassis designed specifically for students and hobbyist. Unlike conventional tracked chassis’s the clearance can be adjusted by rotating the gearboxes in 5-degree increments. “Stretchy” rubber treads maintain tension as the clearance is raised. Each gearbox has an 87:1 ratio includes an optical quadrature encoder that gives 1000 pulses over 3 revolutions of the output shaft. The chassis can be upgraded to include four motors and encoders making it ideal for mecanum wheels. Inside of the chassis are 4 noise suppression coils at the bottom and a battery holder that accepts 6x AA batteries. It is recommended to use NiMh batteries as they last longer and have a higher current output than Alkaline batteries. Video of the chassis in action can be seen here: Video indoors autonomous: http://v.youku.com/v_show/id_XMjE5NzkwODA0.html Video outdoors RC mode: http://v.youku.com/v_show/id_XMjIwMTkxODk2.html Dimensions: Specifications: Motor rated voltage: 7.2V Motor stall current: 2.5A Output shaft stall torque: 10Kg/cm Gearbox ratio: 86.8:1 Encoder type: Quadrature Encoder resolution: 1000 state changes per 3 wheel rotations Speed: 1Km/hr Motor Driver: Freescale MC33926 Ultrasonic Distance Sensor: MaxBotics XL-MaxSonar-AE4 (MB1340) MCU: Microchip PIC18F46K22 (Partial) Buzzer: Mallory AST1240MLTRQ