Friday, January 30, 2009
Wind-Up Robots
Wednesday, January 28, 2009
MEMS 2-Axis Accelerometer
My next goal is to write C code for it using the AVR libraries and integrate it with my robot. I am thinking it will help with pathfinding as well as being able to tell when my robot is stuck on a chair leg or something.
Monday, January 26, 2009
Wednesday, January 21, 2009
Free upgrade to my electronics tools
At first, I was going to go with target because they have a good selection of things I could use. Second, I almost went with Hammacher Schlemmer because they have neat stuff. Then I thought about it more before I chose, and i decided that the best thing would be to go with Amazon.com because they have a wide variety of items to chose from.
A couple of days later I received an e-mail containing my Gift Card Code for Amazon.com. I quickly entered in this code into my account, and I had $100 in my balance!!! I held on to it for a few days while decided what I wanted, and at the same time added some things to my wish list. In the end, I ended up paying ~$40 because I went a little over, and there is multiple shipping costs from different vendors. Here is what I got for approximately $40USD:
Weller WES51
Weller ETH 1/32" Screwdriver Tip for SMD soldering
(ETA Shown)
1LB Kester 44 0.31" 60/40 Solder
Weller SM1 Solder Dispenser
Pretty good deal if you ask me!!
Monday, January 12, 2009
Battery Monitor - Voltage Divider Circuit
Since I am somewhat new to electronics, I wanted to learn how to implement a battery monitor sensor by using what is called a voltage divider circuit.
Just like LEDs use a series resistor to ensure they receive no more than 20mA of current, with 5vdc this usually turns out to be a 330ohm resistor.
If you wanted to power this same LED, but all you had was say a 9volt or 12volt power source, then you would have to use a second resistor on the ground side of the LED, which would give you a lower voltage AND lower current.
This voltage divider circuit has many more uses besides just LEDs, it can also be used to create a reference voltage or logical voltage level.
For example, I have a 6vdc NiMH battery, but when fully charged it reads 7.08vdc on the multimeter. For my sensor, I want to say that 5vdc is fully charged. I will do some math to calculate what resistors I need to get a 5vdc Vout. Or in my case, I dread math so I will use a Java applet I found:
The applet will help me get a close approximation to start with. I enter in 7v for Vs, and I find I can get 5.00vdc on the voltmeter with R1 = 20k, and R2 = 50k
Voltage Divider Applet
The only snag apparent right now is that with common 5% resistors, there are only a limited selection to chose from. Unfortunately, there is no such thing as a 5% 20k and 50k resistor.
There is another snag too that i'll tell you about now, is that this circuit is assuming there is nothing connected to Vout, meaning no load. It is basically just a series resistance. The way to deal with that is if you know the current that will be on the load, you can use another series resistor on your 5v. The other way, which is what I will use, is you can add a capacitor between ground, and the voltage you want to stabalize. In my case a 10uF 16V cap is perfect.
According to Ohm's Law, the ratio of voltage across our two resistors will be equal to the ratio of the resistance values themselves. In my case, I want to drop from 7.08 to 5, thats a drop of 2.08. Therefore my ratio is 2.08:5, or more simply 0.416:1. Unfortunately, this ratio will not work using common 5% resistors. I will round down and say my batteries max charge is 7vdc, which is fine as they will lower in voltage as they get older anyway. So lets say 2:5, or 0.4:1 (or for the purpose of the calculator below, 1:0.4)
In this next calculator, the table shows the significant digits (1st digit, and 2nd digit) of standard 5% resistor values. When you type in a ratio, it calculates the corresponding significant digits (1st digit, and 2nd digit) that would be required to complete that ratio.
Resistor Ratio Calculator
Go ahead and type in '0.4' in the desired ratio box.
All you need to do is pick out ratios of valid significant digits (meaning no decimal point, and a number you already see listed on the table, in my case the first 4 in 10:4 is not an existing resistor value).
The table shows that you can use resistance values with the first two digits of (this does not talk about the multiplier) 30:12, or 75:30 to obtain the ratio of 1:0.4.
If instead of doing 2/5 to get 0.4, you had done 5/2, you would have gotten 2.5. If you had specified 1:2.5 (the inverse of 1:0.4), you would have gotten the ratios of 12:30, and 30:75. Which is the same ratios that fit the standard resistor values.
Homemade Benchtop Power Supply
For Christmas, my step-mother received a new laptop, that being said there is always old junk that needs to go.
(I always can think of way to put old desktops and laptops to work.)
Anyway, I snatched up the power supply out of the old desktop and followed this tutorial:
Convert-a-Computer-ATX-Power-Supply-to-a-Lab-Power-Supply
Now easy access to these regulated voltages:
24v (+12, -12), 17v (+5, -12), 15.3v (+3.3, -12), 12v (+12, 0), 10v (+5, -5), 8.3v (+3.3v, -5), 7v (+12, -5), 5v (+5, 0), 3.3v (+3.3, 0), -5v (-5, 0), -12v (-12, 0)
When I have time I am going to go in and modify it a bit. I am going to add the switch to the front panel, as the one on the back panel is hard to reach. I am also going to add a 3mm LED holder, because when the LED contact touches the chassis it grounds, and does not light.
Adding a Parallax Ping to an AVR using C
Introduction
I chose to go with the Parallax Ping Ultrasonic Sensor for this upgrade to my robot. Though only tested on an ATmega8, 168, and 128 this should port over to any AVR 8-bit RISC microcontroller. The reason I chose this sensor is because it is readily available at some local electronics locations instead of having to order online. Most notably, this sensor can be picked up at your local Radio Shack in the Sensor drawer. The datasheet can be found on the Parallax website here (.pdf), please download yourself a copy. You also need to make sure that you have Procyon AVRlib installed.
Theory
The section were most interested in on the datasheet is the 'Communication Protocol' section on page 2.
Here we see that the trigger pulse requires the pin to go high (+5vdc) for a minimum of 2 microseconds, but typically 5 microseconds. If you look at the image above the table you see that it starts low (0vdc), goes high for 5us, and then goes low again. To do this we have to set the pin to be an output, and then we send our trigger pulse. Next, we toggle the pin to be an input and then we listen. We are listening for the Ping Sensor to send the pin a pulse which brings the pin high (+5vdc). While we are listening we have to go into a loop, where the only exit condition is if the pin goes high. Once we receive the signal we are waiting for, we immediatly exit the loop, start the timer, and enter another loop waiting for the singal to end when the pin goes low (0vdc). The last part is to get that timer data into a variable and then do the math to calculate the distance of the object. The minimum and maximum distance the Ping Sensor can read is 3cm to 300cm. The distance is only necesarry if we want to output it to UART in human readable format. Otherwise we can just take the value returned from the timer and use that in the main code to make decisions with.
You will need to create some sort of connector cable to interface with your MCU
You will also have to create some sort of mount. Your mount will differ depending on if you want to mount it directly to the chassis or to a servo. For now this tutorial only covers mounting it to the chassis and using it as a touchless bumper.
Coding
Timer -
We are going to use a basic timer in order to record the time that the Ping sensor brings the pin high. Which in turn we can use to calculate the distance away and object is. You need to include the timer header file depending on which mcu you're using.
#include "timer.h"or
#include "timerx8.h"
We also need to add this simple function:
//**************RESET TIMER**************
void reset_timer_0(void) {
//restart timer count
TCNT0=0x00;//clear timer
//clear timer0's overflow counter.
timer0ClearOverflowCount();
}
//***************************************
We also need some sort of function for going backward:
void robot_go_back(void)
{
servo_left(352);
servo_right(200);
}
In the Initialize area of your code add this line:
timerInit(); // initialize the timer system
Registers -
Image of an ATmega8/ATmega168 with ports:
Port registers allow for lower-level and faster manipulation of the i/o pins on the microcontroller. The ATmega8 and ATmega168 have three ports: B, C, and D.
Each port is controlled by three registers, which are also used in the macros.
The DDR register, determines whether the pin is an INPUT or OUTPUT.
The PORT register controls whether the pin is HIGH or LOW.
The PIN register reads the state of INPUT pins set to input with the macros.
DDR and PORT registers are both read and write accessible.
PIN registers correspond to the state of inputs and may only have read access.
The registers are specified with the name of the register and the port (ex. PORTx) x being the port.
DDRD – The Port D Data Direction Register
PORTD – The Port D Data Register
PIND – The Port D Input Pins Register - read only
PORTB – The Port B Data Register
PINB – The Port B Input Pins Register - read only
DDRC – The Port C Data Direction Register
PORTC – The Port C Data Register
PINC – The Port C Input Pins Register
Macros -
There is a header file called sfr_defs.h which is included in io.h. SFR stands for special functions register and the file contains a few useful macros which we can use:
#define bit_is_clear (sfr, bit) (!(_SFR_BYTE(sfr) & _BV(bit)))
Test whether bit bit in IO register sfr is clear. This will return non-zero if the bit is clear, and a 0 if the bit is set.
Test whether bit bit in IO register sfr is set. This will return a 0 if the bit is clear, and non-zero if the bit is set.
#define bit_is_set (sfr, bit) (_SFR_BYTE(sfr) & _BV(bit))
Wait until bit bit in IO register sfr is clear.
#define loop_until_bit_is_clear (sfr, bit) do { } while (bit_is_set(sfr, bit))
Wait until bit bit in IO register sfr is set.
#define loop_until_bit_is_set(sfr, bit) do { } while (bit_is_clear(sfr, bit))
These macros associate simple commands with complicated bitwise operators. You can see examples of these macros in action in the code below.
#define PORT_ON( port_letter, number ) port_letter |= (1<<number)
#define PORT_OFF( port_letter, number ) port_letter &= ~(1<<number)
#define PORT_ALL_ON( port_letter, number ) port_letter |= (number)
#define PORT_ALL_OFF( port_letter, number ) port_letter &= ~(number)
#define FLIP_PORT( port_letter, number ) port_letter ^= (1<<number)
#define PORT_IS_ON( port_letter, number ) ( port_letter & (1<<number) )
#define PORT_IS_OFF( port_letter, number ) !( port_letter & (1<<number)
#define PINGPIN 2 // assign a pin to the Ping Sensor
#define DDR DDRC
#define PORT PORTC
#define PIN PINC
Function:
void ping(void) {
PORT_ON(DDR, PINGPIN); // Switch PingPin to OUPUT
// ------Trigger Pulse--------------
PORT_OFF(PORT, PINGPIN); // Bring PingPin low before starting trigger pulse
delay_us(2); // Wait for 2 microseconds
PORT_ON(PORT, PINGPIN); // Bring PingPin High for 5us according to spec sheet.
delay_us(5); // Wait for 5 microseconds
PORT_OFF(PORT, PINGPIN);; // Bring PingPin Low and standby
//--------End Trigger Pulse---------------------
FLIP_PORT(DDR, PINGPIN); // Switch PingPin to INPUT
loop_until_bit_is_set(PIN, PINGPIN); // Loop until the the PingPin goes high (macro found in sfr_def.h)
//clears timer, reset overflow counter
reset_timer_0(); //reset timer 0
loop_until_bit_is_clear(PIN, PINGPIN); // Loop until the the PingPin goes low (macro found in sfr_def.h)
//read timer0's overflow counter
//255 is count before overflow, dependent on clock
int elapsed_time=timer0GetOverflowCount()*255+TCNT0;
PingVal = elapsed_time * 2.068965517;t
} // end ping function
In your Main:
// All the values are based on running at 8MHz. You can see in the comments, I multiplied the original 1MHz values by 8.
while(1) {
scan();
ping();
//Object Avoider
if (PingVal > 8) {
// object detected
if (sharp_IR_reading > scan_thresh) {
//240 far right, 400 center, 448 far left
//object on left
if(scan_angle > 380)
while (sharp_IR_reading > scan_thresh) {
robot_turn_right();
sharp_IR_reading=a2dConvert8bit(3);
} // end while
//object on right
else if(scan_angle < 360) // 41 * 8
while (sharp_IR_reading > scan_thresh) {
robot_turn_left();
sharp_IR_reading=a2dConvert8bit(3);
} // end while
} // end if
// object not detected
else
robot_go_straight();
} // end if
else {
while (PingVal < 16) {
robot_go_back();
ping();
} // end while
for (int i = 0; i > 5; i++)
robot_turn_right();
} // end else
delay_cycles(3200);//a small delay to prevent crazy oscillations >; 400 * 8
} // end while loop
Saturday, January 3, 2009
Atmel AVR High Voltage Fuse Reset
Parts:
1 - Breadboard
1 - Set of breadboard jumper wires
2 - ATmegas (one good one, and the one you're locked out of)
2 - Regulated power sources, 12vdc and 5vdc
1 - LED
1 - 2N3903 or 2N3904 transistor (available at Radio Shack)
1 - Tactile/Momentary Button (Omron B3F-1000 is a popular one, can be stuck into a breadboard)
20 - 1K Ohm Resistors, 1/4 watt is fine.
This tutorial is based off of the work of Jeff Keyzer at his website:
http://mightyohm.com/blog/2008/09/arduino-based-avr-high-voltage-programmer/
I have attached a hex file containing the code to 'fix' a locked ATmega8, If you want to use his code, you have to have the Arduino IDE installed and you have to compile it with that. Once you have the .hex file, you can upload it to your mcu via AVR Studio if you like.
http://mightyohm.com/blog/wp-content/uploads/2008/09/hvfuse.pde
Make sure before you compile it, that you change the high and low fuse values based on the ones listed on the AVR Fuse Calculator website:
http://palmavr.sourceforge.net/cgi-bin/fc.cgi
The schematics he provides are bit tricky without an actual Arduino if you are just using an ATmega on a breadboard.
http://mightyohm.com/blog/wp-content/uploads/2008/09/hvfuse_fixed.png
You can use an Arduino pin map to help:
http://www.arduino.cc/en/Hacking/PinMapping168
Otherwise I am providing the basic pin connections below (refer to the schematic for hooking up the transistor, led, and button):
Note: The form here is the pin number followed by the pin name.
Connections w/1k ohm resistor in series:
Good Atmega -> Bad Atmega
2PD0 -> 14PB0
3PD1 -> 15PB1
4PD2 -> 16PB2
5PD3 -> 17PB3
6PD4 -> 18PB4
11PD5 -> 19PB5
12PD6 -> 23PC0
13PD7 -> 24PC1
15PB1 -> 6PD4
16PB2 -> 5PD3
17PB3 -> 4PD2
18PB4 -> 3PD1
19PB5 -> 11PD5
23PC0 -> LED, Button
25PC2 -> 25PC2
26PC3 -> 9PB6
27PC4 -> 12PD6
28PC5 -> 13PD7
GND -> GND
Other connections (no resistor):
Good Atmega -> Bad Atmega
14PB0 -> 22AGND, 21AREF, 7VCC
24PC1 -> button
Just remember it will be easier to work with if you place the two ATmegas on the breadboard with the divots facing each other. I learned this from experience ;)
Once you get it all hooked up, here is how it goes:
- Apply the voltages.
- Wait for the red LED to turn on (if it isn’t already)
- Push the 'Go' tactile button
- As soon as the LED turns back on, the AVR is unlocked!
Any questions, feel free to contact me.