User Tools

Site Tools


projects:assembly_car

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revision Previous revision
Next revision
Previous revision
projects:assembly_car [2013/12/19 21:31]
etappan [Code Description]
projects:assembly_car [2013/12/20 14:49] (current)
etappan [Files]
Line 16: Line 16:
 We created an autonomous robot that explores the world in linear trajectories while avoiding obstacle using IR range-finding. ​ We created an autonomous robot that explores the world in linear trajectories while avoiding obstacle using IR range-finding. ​
  
-The robot is an RC Venom car altered to be controlled by an Arduino Uno programmed in AVR Assembly (a very low-level programming language specific to the type of hardware used). The Arduino communicates to the hardware system (both the sensors and motors) using PWM (Pulse Width Modulation),​ a protocol often used to control servos. To sense the world, there are two IR sensors mounted ​to the front of the robot to determine the proximity of obstacle ​in its path and determine the best direction to turn towards ​to avoid it+The robot is Venom RC car altered to be controlled by an Arduino Uno programmed in AVR Assembly (a very low-level programming language specific to the type of hardware used). The Arduino communicates to the hardware system (both the sensors and motors) using PWM (Pulse Width Modulation),​ a protocol often used to control servos ​and in Remote Control. To sense the world, there are two IR sensors mounted ​on the front of the robot to determine the proximity of obstacles ​in its path and determine the best direction to turn to avoid them.
  
-When there are no obstacles around the robot, it goes full-speed directly forwards. When it senses an object ​directly in front of it, it slows down and turns away from the object. The speed and amount of turning is directly proportional to the distance of the object. If the object gets too close, the robot enters an "​OHMYGOODNESSIMGOINGTODIE"​ panic mode, and it stops and backs up to turn away from the object ​to continue ​on its merry-way. ​ +When there are no obstacles around the robot, it goes full-speed directly forwards. When it senses an object, it slows down and turns away. If the object gets too close, the robot enters an "​OHMYGOODNESSIMGOINGTODIE"​ panic mode, stopsbacks away from the object, and continues ​on its merry-way. ​
-  +
-DELETEME //"​This is a catchy sentence followed by a paragraph or two. The intended audience should include people that aren’t necessarily versed in Computer Architecture,​ but are technically competent. Even the MechEs should be able to understand this portion."//​ From Workplan: Goal: "To create an arduino-based,​ assembly-run robot built on an RC car platform that can avoid obstacles using the IR-rangefinder."​ Demo: "The robot will autonomously drive, using an IR rangefinder to avoid obstacles."​ +
-----+
  
-===== Why We Did It ===== 
-DELETEME //"A paragraph or so about why the project you chose is worthwhile and interesting."//​ 
  
-We chose to do our project mostly robots are awesome, and we wanted a derpy robot to play with. With a robot, ​we get more experience in programming in a different ​type of Assembly, as well as experience ​with working with hardware on a very low-level ​and how to deal with an predictable environment.+==== Why We Did It ==== 
 +We chose to do our project mostly robots are awesome, and we wanted a derpy robot to play with. While we'd worked with MIPS assembly in class, working with an Arduino pushed us to get experience in the very different ​AVR Assembly. Working ​with a robot was an excellent way to experience ​working with hardware on a very low-level.
 ---- ----
 ===== How We Did It ===== ===== How We Did It =====
Line 42: Line 38:
 The steering servo and electronic speed control both work off of standard 50 Hz Remote Control PWM signals. The pulse ranges from 1 ms to 2 ms, with ~1.5 ms being the neutral position. ​ For servos with larger ranges, you might see pulses between 0.5 and 2.5 ms (neutral will still be around 1.5 ms). The steering servo and electronic speed control both work off of standard 50 Hz Remote Control PWM signals. The pulse ranges from 1 ms to 2 ms, with ~1.5 ms being the neutral position. ​ For servos with larger ranges, you might see pulses between 0.5 and 2.5 ms (neutral will still be around 1.5 ms).
  
-Facing ​the steering servo (looking down the car): straight forward is pulse-width 1472 microseconds,​ full right (~45 degrees) is pulse-width 956 us, full left (~45 degrees) is pulse-width 1884 us.+From the perspective of the car: straight forward is pulse-width 1472 microseconds,​ full right (~45 degrees) is pulse-width 956 us, full left (~45 degrees) is pulse-width 1884 us. Throttle is more straightforward with a 2 ms pulse signalling full throttle forward, 1.5 ms signalling neutral (or braking, depending on settings), and 1 ms signalling full reverse. 
 + 
 +While the ATMega328 has built-in PWM support, it only supports fairly high frequencies. Ones much, much faster than the 50 Hz our car is expecting. To implement slow PWM we need to use some features of the AVR's timer/​counter system. For a positive PWM we hold a signal high for one count (the pulse), then hold it low for the remainder of the 20 ms period before starting over.
  
 == AVR Timers == == AVR Timers ==
-The Atmega has 3 internal timers (0, 1, and 2). Timers 0 and 2 are 8-bit timers, Timer 1 is a 16-bit timer. Settings are controlled by writing to the Timer Counter Control Registers (TCCRx, x=0,1, or 2).+The Atmega ​328p on our Arduino ​has 3 internal timers (0, 1, and 2). Timers 0 and 2 are 8-bit timers, Timer 1 is a 16-bit timer. Settings are controlled by writing to the Timer Counter Control Registers (TCCRx, x=0,1, or 2).
  
-Frequency is controlled partly via a prescaler, an integer which divides down the maximum frequency (16 MHz)--so the minimum prescaler of 8 makes the timer run at 2MHz, while a prescaler of 64 reduces the timer to 256KHz.+Frequency is controlled partly via a prescaler, an integer which divides down the maximum frequency (16 MHz)--so the minimum ​non-zero ​prescaler of 8 makes the timer run at 2MHz, while a prescaler of 64 reduces the timer to 256KHz.
  
-Timer 1 is a 16-bit timer with the option to run in compare mode, allowing us to trigger events much lower frequencies. This is useful for working with 50Hz RC PWM. In compare mode, the AVR will compare the timer to the value loaded in the Output Compare Register (OCR) and perform various operations when they match. This can generate square waves, control PWM, or generate interrupts. TCCR1A and TCCR1B is outlined below but the behavior is analogous for Timers 0 and 2. Bits which are not described were not used in this project but are described in the resources linked at the end of this page.+Timer 1 is a 16-bit timer with the option to run in compare mode, allowing us to trigger events much lower frequencies. This is useful for working with 50Hz RC PWM. In compare mode, the AVR will compare the number of timer counts ​to the value loaded in the Output Compare Register (OCR) and perform various operations when they match. This can generate square waves, control PWM, or generate interrupts. TCCR1A and TCCR1B is outlined below but the behavior is analogous for Timers 0 and 2. Bits which are not described were not used in this project but are described in the resources linked at the end of this page.
  
 |TCCR1A: ​ ||||||||| |TCCR1A: ​ |||||||||
Line 89: Line 87:
 === Sensor Processing === === Sensor Processing ===
  
-To decide how to react to the world determined to prevent the little robot from finding true freedom, the code samples from two analog input pins that are the signal wires to two IR sensors. The sensors are spaced apart and mounted on the front of the robot. In this way, the robot can determine how far away obstacles are, and determine how to turn from the side further way for more intelligent decision making. Unfortunately,​ but not surprisingly,​ the sensors are very noisy fellows and require a lot of averaging to get any resemblance of smooth behavior. The documentation above specifically warns against adding a capacitor between the signal and ground or VCC, so an RC low-pass filter is inadvisable. We could get around that by filtering in another way, but this is a CompArch project, so we will do this in software! Arg! Therefore, we uses a simple rolling average of the last sixteen points. We discarded the use of an exponential rolling average due to the problems of floating point multiplication (sadness). Since the CPU is running many thousands of times faster than the sensor is providing new data (about 40ms), we make sure to only average distinct values+To decide how to react to the world determined to prevent the little robot from finding true freedom, the code samples from two analog input pins that are the signal wires to two IR sensors. The sensors are spaced apart and mounted on the front of the robot. In this way, the robot can determine how far away obstacles are, and determine how to turn from the side further way for more intelligent decision making.
  
-Averaging ​in binary ​is obnoxioussince we need to add and divide several 8-bit numbers while account for overflowDividing earlier reduces ​the memory overheadbut decreases precision +Unfortunately,​ but not surprisingly,​ the sensors are very noisy fellows and require a lot of averaging to get any resemblance of smooth behavior. The documentation above specifically warns against adding a capacitor between the signal and ground or VCC, so an RC low-pass filter is inadvisable. We could get around that by filtering ​in another way, but this is a CompArch projectso we will do this in software! Arg! Therefore, we uses a simple rolling average of the last sixteen points. We discarded the use of an exponential rolling average due to the problems of floating point multiplication (sadness)Since the CPU is running many thousands of times faster than the sensor is providing new data (about 40ms)we make sure to only average distinct values
  
-Based on the values from the sensors, we have four general ​modes:+Taking an average of several values is obnoxious in AVR assembly, as eight bits is not enough for the sum of even two sensor values. We stored a 16 bit sum in two 8-bit registers and carefully took the carry into account while adding. Dividing before adding could allow us to work entirely within 8 bits, but would destroy precision. ​  
 + 
 +Based on the values from the sensors, we have three modes:
  
 1. WHEEEEEEEEEEEEEEE! \\ 1. WHEEEEEEEEEEEEEEE! \\
 2. Hmmmmm, a wall. I should probably avoid that. \\ 2. Hmmmmm, a wall. I should probably avoid that. \\
-3. OHMYGOODNESSAWALL. Panic!\\ +3. OHMYGOODNESSAWALL. Panic! Beep!Beep!Beep! ​Honk.\\
-4. Beep!Beep!Beep! ​Gotta get out of here!\\+
  
-In the "​WHEEEEEEEEEE!"​ mode, the sensors are reading values below about 40 (meaning nothing is within about 45 cm), and the robot goes full forward in a strait trajectory. When the car gets to an obstacle less than 45 cm away, it goes into "​Hmmmmm,​ a wall. I should probably avoid that," where the car turns towards the higher of the two values (towards the direction with the further away obstacle). If either of the values drop below about 10, then an obstacle is less than 700mm away, and the robot enters "​OHMYGOODNESSAWALL. Panic!"​ mode. In this mode, the robot stops and transitions to "​beep.beep.beep. Gotta get out of here!" mode by turning the wheels ​towards the closer side of the obstacle and backing ​away until the robot is far enough away to successfully go to mode 2 without immediately ​entering ​mode again. +In the "​WHEEEEEEEEEE!"​ mode, the sensors are reading values below about 40 (meaning nothing is within about 45 cm), and the robot goes full forward in a strait trajectory. When the car gets to an obstacle less than 45 cm away, it goes into "​Hmmmmm,​ a wall. I should probably avoid that," where the car turns towards the higher of the two values (towards the direction with the further away obstacle). If either of the values drop below about 10, then an obstacle is less than 700mm away, and the robot enters "​OHMYGOODNESSAWALL. Panic! ​Beep!Beep!Beep! Honk." mode. In this mode, the robot turns towards the closer side of the obstacle and backs away until the robot is far enough away to successfully go to mode 2 without immediately ​losing its shit again. Unfortunately,​ we did not fully implement the third mode. Instead the car backs up just enough to lose its shit again. It does, however, eventually make its way out of the panic mode through this oscillation
-==== Code Implementation Process ​====+==== Code ====
  
-To implement the codewe first used a simulator do sanity check our code before ​we added the uncertainty of the real world.+We started our work with Assembly by simulating basic code in the Emulare AVR emulator. Once we were confident in our toolset we moved on to almost exclusively running code on the Arduino. We used the WinAVR toolset to build our code
 + 
 +The basic architecture of our code is simple: ​we have a main loop that runs forever, reading samples from the ADC, averaging them, and then acting on the average. The snippet below shows the essence of our code, with some details removed. 
 +  
 +<​code>​ 
 +main: 
 +    call pwm_init 
 +    call adc_enable 
 + 
 +    ; ... (More initialization) ... 
 + 
 +    .loop: 
 +    ldi R24, 1       ; R24 = adc_read channel 
 +    call adc_read ​   ; R24 = adc_read voltage read 
 +    mov R25, R24 
 +    ldi R24, 0       ; R24 = adc_read channel 
 +    call adc_read ​   ; R24 = adc_read voltage read 
 + 
 + 
 +    call add_sample 
 +    call get_average ; R24 = adc rolling average for A0 
 +                     ; R25 = adc rolling average for A1 
 + 
 +    call evaluate 
 +    call choose_steer_angle 
 +    call choose_speed 
 + 
 +    rjmp .loop 
 +</​code>​ 
 + 
 +Our current build is comprised of two files, robit.S and data.S. These contain our actual logic and definitions of data locations in memory, respectively.
 ==== Gotchas ==== ==== Gotchas ====
  
Line 120: Line 149:
  
 Also, make sure your documentation holds true for your particular chip. We ran into some minor trouble because we trusted a table which implied that AVR chips universally have a 2.56V internal voltage for use with AREF. This is a lie. It is also sad. Also, make sure your documentation holds true for your particular chip. We ran into some minor trouble because we trusted a table which implied that AVR chips universally have a 2.56V internal voltage for use with AREF. This is a lie. It is also sad.
 +
 +=== Sharp IR is full of liars ===
 +We found many documents alleging to have graphs comparing Sharp IR voltage readings to real distances. These were false. We had much better luck, given our application,​ reading values via an Arduino script and configuring our regimes from there.
  
 === PWM for RC Servos === === PWM for RC Servos ===
Line 125: Line 157:
  
 === Enabling Correct Motor Controller Modes === === Enabling Correct Motor Controller Modes ===
-Venom does not document very well at all. [[http://​www.competitionx.com/​pdf/​esc/​venom-pro-brushless-esc-manual.pdf|This]] is not the electronic speed control (ESC) for our car. The programming is at least similar enough to let our car goes backwards. If it is not in the correct mode, the car will only be able to go forwards. How can you go two steps forwards without at least one back? You can't.+Venom does not document very well at all. [[http://​www.competitionx.com/​pdf/​esc/​venom-pro-brushless-esc-manual.pdf|This]] is not the electronic speed control (ESC) for our car. The programming is at least similar enough to let our car go backwards. If it is not in the correct mode, the car will only be able to go forwards. How can you go two steps forwards without at least one back? You can't.
 ==== Hardware Implementation ==== ==== Hardware Implementation ====
 +{{http://​cdn.instructables.com/​FTX/​AGWD/​H05NT69Z/​FTXAGWDH05NT69Z.LARGE.jpg?​200 }}
 Our robot is a Frankenstein of several components: an RC car chassis, an Arduino Uno, and two IR range-finder sensors. Our robot is a Frankenstein of several components: an RC car chassis, an Arduino Uno, and two IR range-finder sensors.
  
-The chassis we used as a [[http://​​www.horizonhobby.com/​​products/​​venom-creeper-rock-crawler-kit-1-10-green-electric-VNR8300GR#​​t1|Venom Creeper Rock Crawler]]. It was originally set-up to be controlled by RC, but we simply disconnected the motor controller and steering servo from the receiver ​and wired it to our Arduino ​to mimic the PWM signal and control ​the car autonomously. ​We used an [[http://​​arduino.cc/​​en/​​Main/​​ArduinoBoardUno|Arduino Uno]] with its [[http://​​www.atmel.com/​​Images/​​doc8161.pdf|AtMega328 microcontroller]]. 90% of the information on the Arduino board is irrelevant if you're just using it as a platform for the AtMega but the schematics are there. The most significant detail is the connection between the raw AtMega pins and the I/O pins of the Arduino.+The chassis we used as a [[http://​​www.horizonhobby.com/​​products/​​venom-creeper-rock-crawler-kit-1-10-green-electric-VNR8300GR#​​t1|Venom Creeper Rock Crawler]]. It was originally set-up to be controlled by RC, but we simply disconnected the motor controller and steering servo from the receiver. By wiring ​it to our Arduino ​we could mimic the PWM signal and run the car autonomously. ​We used an [[http://​​arduino.cc/​​en/​​Main/​​ArduinoBoardUno|Arduino Uno]] with its [[http://​​www.atmel.com/​​Images/​​doc8161.pdf|AtMega328 microcontroller]]. 90% of the information on the Arduino board is irrelevant if you're just using it as a platform for the AtMega but the schematics are there. The most significant detail is the connection between the raw AtMega pins and the I/O pins of the Arduino.
  
-To sense the world around it to detect obstacles, we mounted two [[http://​​zuff.info/​​SharpGP2D12_E.html|Sharp GP2D12 IR range-finding sensors]] to the front of the robot. Some important characteristics are that it has a 40ms update period, so we need to do our averaging only with new values, not when we query it at a the high-rate we do. Also, the analog voltage is inversely proportional (in a non-linear fashion) to the distance values. It has the following range and mapping: max 2.45V = 10cm and min 0.45V = 80cmwith an error of 200mV.+To sense the world around it to detect obstacles, we mounted two [[http://​​zuff.info/​​SharpGP2D12_E.html|Sharp GP2D12 IR range-finding sensors]] to the front of the robot. Some important characteristics are that it has a 40ms update period, so we need to do our averaging only with new values, not when we query it at a the high-rate we do. Also, the analog voltage is inversely proportional (in a non-linear fashion) to the distance values. It has the following ​alleged ​range and mapping: max 2.45V = 10cm and min 0.45V = 80cm with an error of 200mV. In practice, it was necessary to check values manually via an Arduino script.
  
 {{ :​projects:​img_3395.jpg?​400|}} {{ :​projects:​img_3395.jpg?​400|}}
Line 137: Line 170:
  
 Mounted IR range-finding sensors using the sophisticated wonders of tape and cardboard. ​ Mounted IR range-finding sensors using the sophisticated wonders of tape and cardboard. ​
- 
-{{http://​cdn.instructables.com/​FTX/​AGWD/​H05NT69Z/​FTXAGWDH05NT69Z.LARGE.jpg?​200 }} 
  
 We used an [[http://​arduino.cc/​en/​Main/​ArduinoBoardUno|Arduino Uno]] with its [[http://​www.atmel.com/​Images/​doc8161.pdf|AtMega328 microcontroller]]. 90% of the information on the Arduino board is irrelevant if you're just using it as a platform for the AtMega but the schematics are there. The most significant detail is the connection between the raw AtMega pins and the I/O pins of the Arduino. We used an [[http://​arduino.cc/​en/​Main/​ArduinoBoardUno|Arduino Uno]] with its [[http://​www.atmel.com/​Images/​doc8161.pdf|AtMega328 microcontroller]]. 90% of the information on the Arduino board is irrelevant if you're just using it as a platform for the AtMega but the schematics are there. The most significant detail is the connection between the raw AtMega pins and the I/O pins of the Arduino.
Line 168: Line 199:
   * [[http://​emulare.sourceforge.net/​debugging%20with%20emulare%20and%20insight.php | Debugging with Emulare]]: Emulare is an AtMEGA simulator. While it doesn'​t have many bells or whistles it's useful for confirming basic features of your assembly work. Can be used with assembly debugging tools such as those bundled with WinAVR.   * [[http://​emulare.sourceforge.net/​debugging%20with%20emulare%20and%20insight.php | Debugging with Emulare]]: Emulare is an AtMEGA simulator. While it doesn'​t have many bells or whistles it's useful for confirming basic features of your assembly work. Can be used with assembly debugging tools such as those bundled with WinAVR.
   * [[http://​www.nongnu.org/​avr-libc/​user-manual/​using_tools.html | Building Assembly]]: Exactly what you'd expect.   * [[http://​www.nongnu.org/​avr-libc/​user-manual/​using_tools.html | Building Assembly]]: Exactly what you'd expect.
 +  * [[http://​extremeelectronics.co.in/​avr-tutorials/​timers-in-compare-mode-part-i/​ | AVR Timers]]: This series of articles is a good resource for timers and PWM in AVR. Read as far back as you need to given your application.
 ==== Files ==== ==== Files ====
 +{{:​projects:​CompArchRobit.zip}}:​ A .zip archive with all of our assembly. robit.S is our main working build. Similarly-named files are backups of partially functional builds or else broken test builds. Running the following from a command line/prompt will build and deploy robit.S on Com10. Change the flash.bat file as needed to reflect the actual Com Port in use.
 +<​code>​
 +> cd "​CompArch Robit"
 +> make
 +Yes. Done. Good. :)
 +> flash
 +[...So much output... Holy cow...]
 +</​code>​
 +
 +{{:​projects:​Robit_Movie.zip}}:​ An early example of the car in motion. Later builds were less likely to capsize.
projects/assembly_car.1387506693.txt.gz · Last modified: 2013/12/19 21:31 by etappan