User Tools

Site Tools


projects:assembly_car

This is an old revision of the document!


FIXME Not enough cats.

Some Assembly Required

Comp Arch Fall 2013 final project

Is Assembly Required: Yes



Team: Charles Goddard (2015), Victoria Coleman (2015), Eric Tappan (2015)

What We Did

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.

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.

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.


How We Did It

DELETEME “This portion can assume an audience that has taken Computer Architecture, but don’t get burdened oby buzzwords. A sure sign of a bad engineer is over reliance on acronyms.”

Code Description

print "Hello world"
run robit --wallAvoid=True --becomeSkynet=False

PWM

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.

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).

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.

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.

TCCR1A:
Bit 7 6 5 4 3 2 1 0
Name COM1A11) COM1A02) COM1B13) COM1B04) FOC1A5) FOC1B6) WGM117)) WGM108))
Initial value 0 0 0 0 0 0 0 0
TCCR1B:
Bit 7 6 5 4 3 2 1 0
Name ICNC19) ICES110) WGM1311)) WGM1212)) CS1213)) CS1114)) CS1015))
Initial value 0 0 0 0 0 0 0 0
COM1xy effects:
COM1x1 COM1x0 Description
0 0 Normal Port Operation (The timer doesn't change the voltage on the i/o pin)
0 1 Toggles OC1x16) on match
1 0 Clears OC1x17) on match–set level Low (GND)
1 1 Sets OC1x18) on match–set level High (VCC)
CSxy effects:
CSx2 CSx1 CSx0 Effect
0 0 0 Timer stopped.
0 0 1 Clock = normal CPU frequency (FCPU)
0 1 0 Clk = FCPU/8
0 1 1 Clk = FCPU/64
1 0 0 Clk = FCPU/256
1 0 1 Clk = FCPU/1024
1 1 0 External Clock source on pin T0. Clock on falling edge.
1 1 0 External Clock source on pin T0. Clock on rising edge.

The TCNT1 port holds the current value of Timer Counter 1, divided into two 8-bit ports TCNT1H (holding the high byte) and TCNT1L (holding the low byte). This is compared to the 16-bit value stored in the Output Compare Registers (OCR1A and OCR1B for timer 1), OCR1xH and OCR1xL. WGMxy determines the effect on match. Options vary between processors, but for our purposes we only care about Clear Time on Compare (CTC) which will reset the timer to zero on a match.

CTC:
WGM13 WGM12 WGM11 WGM10
0 1 0 0

The Timer Counter Interrupt Mask (TIMSK) is useful for more complicated timed operations, but all we need it for is to disable interrupts. This is done by clearing the register (filling it with 0s).

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.

Averaging in binary is obnoxious, since we need to add and divide several 8-bit numbers while account for overflow. Dividing earlier reduces the memory overhead, but decreases precision.

Based on the values from the sensors, we have four general modes:

1. WHEEEEEEEEEEEEEEE!
2. Hmmmmm, a wall. I should probably avoid that.
3. OHMYGOODNESSAWALL. Panic!
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 3 again.

Code Implementation Process

To implement the code, we first used a simulator do sanity check our code before we added the uncertainty of the real world.

Gotchas

Register weirdness

Not all registers are created equal. For whatever reason Registers R0 through R15 cannot load immediate values. Only the Registers R16 through R31 can be set to an immediate value through the LDI command. The following commands are restricted to Registers R16 and above:

  • ANDI Rx,K: Bit-And of register Rx with a constant value K
  • CBR Rx,M: Clear all bits in register Rx that are set to one within the constant mask value M
  • CPI Rx,K: Compare the content of the register Rx with a constant value K
  • SBCI Rx,K: Subtract the constant K and the current value of the carry flag from the content of register Rx and store the result in register Rx
  • SBR Rx,M: Set all bits in register Rx to one, that are one in the constant mask M
  • SER Rx : Set all bits in register Rx to one (equal to LDI Rx,255)
  • SUBI Rx,K: Subtract the constant K from the content of register Rx and store the result in register Rx.

Analog Read

AVR's analog to digital converter is pretty weird.

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.

PWM for RC Servos

Apparently the only rule about RC servos is you don't talk about RC servos. Luckily there isn't a lot of variability in the PWM format. Generally, PWM for any RC servo or motor controller is going to want a 50 Hz signal (so 20 ms wide) with pulses between 1 ms and 2 ms long. 1 ms is the lowest angle or full reverse, 1.5 ms is halfway between the extremes or neutral, and 2 ms is greatest angle or full forward.

Enabling Correct Motor Controller Modes

Venom does not document very well at all. 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.

Hardware Implementation

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 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 Arduino Uno with its 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 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 = 80cm. with an error of 200mV.

Mounted IR range-finding sensors using the sophisticated wonders of tape and cardboard.

cdn.instructables.com_ftx_agwd_h05nt69z_ftxagwdh05nt69z.large.jpg

We used an Arduino Uno with its 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.

AtMega328 pins on the Arduino Uno.
Pin layout for the Arduino Uno. Similar schematics
are available for other boards at the Arduino website.
Note the distribution of Ports B, C, and D.

The Arduino Schematic and Port Manipulation reference page may be useful if you want to apply some of your Comp Arch experience to making your Arduino scripts write to output crazy fast.

We wired up our hardware system in the following way:

Work Plan reflection

  • An Arduino doesn't have all that many parts to simulate. This let us get a bit ahead on understanding AVR assembly.
  • Learning assembly is complicated, and slow-going if you're trying to do it by reading lots of references between meetings for other projects. Get a feel for the basic architecture and start doing things.
  • Obscure RC cars are not documented for hackers. Luckily, RC PWM standards are well-documented. (hint: 50Hz, 1ms to 2ms pulses with output at 1.5ms always being halfway between the extremes.)
  • We expected to demonstrate obstacle avoidance for the final demo but 1) didn't realize that meant demo day and not expo, and 2) various hardware problems.

TODO

  • Servo control via interrupts: the existing AVR timers can only directly, simply implement two low frequency PWM waves. To add more requires more-or-less complicated interrupt structures. But more servos means the ability to scan with the rangefinders. So cool.
  • More complicated control logic: especially with scanning as above, it should be possible to store a rough map of the robot's surroundings. Building a roomba in assembly isn't normal, but in CompArch it is.

static.fjcdn.com_pictures_with_28eab0_1370012.jpg

  • Improve the panic behavior. One build, robit_no_backsie.S, tried to lock the robot into backing up until it passed a clearance threshold. For reasons that we do not entirely understand, this instead caused bizarre and inconsistent behavior, necessitating a rollback.
  • Make a kick-ass CompArch flag, w/logo: “Rage Against the Turing Machine”?

Resources

  • AVR assembly reference: Not necessarily presented in the best order but good for reference for various topics in AVR assembly. Probably worthwhile to read up on the registers and then consult as needed.
  • 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.
  • Building Assembly: Exactly what you'd expect.

Files

1) Timer 1 Channel A config 1
2) Timer 1 Channel A config 0
3) Timer 1 Channel B config 1
4) Timer 1 Channel B config 0
5) Force Output compare for Compare Unit A
6) Force Output compare for Compare Unit B
7) Waveform Generation Mode bit 1 (Timer 1
8) Waveform Generation Mode bit 0 (Timer 1
9) Input Capture Noise Canceler
10) Input Capture Edge Select
11) Waveform Generation Mode bit 3 (Timer 1
12) Waveform Generation Mode bit 2 (Timer 1
13) Clock Select bit 2 (Timer 1
14) Clock Select bit 1 (Timer 1
15) Clock Select bit 0 (Timer 1
16) , 17) , 18) varies between ATmega chips
projects/assembly_car.1387506666.txt.gz · Last modified: 2013/12/19 21:31 by etappan