Introduction: Make an Attiny13 Based IR Proximity Sensor for $2.42
This is an extremely cheap IR proximity sensor you can make with a few cheap parts and an AVR programmer. I use an Arduino as my programmer in this Instructable.
This sensor only has a range of about 3 inches. You can easily add more LEDs or brighter ones to extend the range. You can also easily re-arrange the LEDS to detect when a beam is broken as well.
The design takes advantage of a cheap AVR (computer on a chip). The computer pulses the IR LEDs off and on and compares the analog readings from the sensor in each state. When the reading with the lights on is above the reading with the lights off the sense pin goes high indicating the sensor is seeing it's own (reflected) light. There is an LED on the sense indicator in this design so you can see when the sensor engages. You can connect the signal right to a microcontroller like an Arduino or Picaxe.
This design moves some processing out of your main robot brain and into it's own node. You may want to debounce the signal, but you don't have to flash the leds and take the readings. You can also use just one digital pin to take the reading. The sketch is around 700K out of 1024 available.
Why I built this
I'm way out of high school, but this is part of a series of designs related to bringing the robots from the game Robot Oddysey into the real world. I want to allow grade schoolers the same chance to learn robotics I had. So I am working on building really inexpensive robots that can move in 8 directions without turning. The "bumpers" are complete now.
Follow @dustin1970
Step 1: Gather Materials
Quantity |
Digikey Part Number |
Description |
Cost |
1 |
475-1439-ND |
PHOTOTRANSISTOR NPN W/FILTER 5MM |
$0.53 |
1 |
ATTINY13A-PU-ND |
IC MCU AVR 1K FLASH 20MHZ 8PDIP |
$0.95 |
3 |
CF14JT220RCT-ND |
RES 220 OHM 1/4W 5% CARBON FILM |
$0.24 |
1 |
CF14JT1M00CT-ND |
RES 1M OHM 1/4W 5% CARBON FILM |
$0.08 |
1 |
2N3904FS-ND |
IC TRANS NPN SS GP 200MA TO-92 |
$0.18 |
2 |
754-1241-ND |
EMITTER IR 3MM 940NM WATER CLEAR |
$0.44 |
TOTAL |
$2.42 |
You will also need
- Electrical tape
- plastic drinking straw
- scissors
- Wire snippers
- breadboard and/or soldering iron
- Jumper wires
- An AVR programmer (any Ardunio compatible will do)
- Ardunio 1.0 software with modifications to program Attiny and the Atiny13 core
Step 2: Create a Sensor Shroud
You don't want IR light leaking in from the sides of the sensor. We will create a little tunnel from electrical tape and a straw. My tape is opaque to IR. Yours probably is too but you can line it with aluminun foil if you want to be sure. Make sure no metal is exposed because it will ruin the circuit.
Cut off about 1.5" (4cm) of the straw. Wrap it in electrical tape. Trim the ends and make it neat.
Cut about 1/2" (8mm) bit of tape and roll it up from the short edge. Fold the roll in half. It won't stay but put a good crease in it. This will plug the bottom of the sensor and keep stray light out that way.
Step 3: Prepare the Sensor
Cut the middle leg off your phototransistor if it has one. It's not needed in this design and can actually cause problems if you leave it on. You don't have to cut it all the way back, but don't leave very much.
Gently wiggle the sensor into the straw until the base is 1/4" (5mm) in or so. Push in the folded roll of tape behind it and seal the back with a bit of tape.
Step 4: Wire It Up
Follow the wiring diagram and keep some notes in mind.
- The chip, LEDs and transistors only work one way around.
- The short leg of the LEDS is connected to the 220 ohm resistors.
- The long leg of the phototransistor is connected to the 1meg resistor.
- You can add more IR emitter/resistor pairs in parallel with the existing pair. Get the basic circuit working first. You could also just use one IR emitter, but 2 seemed to make the readings a lot more stable.
Attachments
Step 5: Wire Up the AVR (Arduino) and Program the Chip
Install Attiny13 Core13 from sourceforge. Here is an Instructable by diy_bloke with directions and even a zip file to download.
Here is MIT's instructions for modifying your environment to burn Attiny.
This page might help if you have problems. Check the comments.
Wire in the Arduino. You can unwire it when the programming is done.
Load the INO file and burn it to the Attiny13 chip.
Alternately just use an AVR programmer to burn the hex file or Instructable author nikkipugh has a super strip board shield design for programming attiny13 chips.
You may need a 10uf capacitor or 120 ohm resistor from the Arduino's reset to ground.
code:
/* Attiny13 proximity sensor by Dustin Andrews 2012 License: Creative Commons Unported http://creativecommons.org/licenses/by/3.0/ */ //Do some low level AVR pin writing to save instructions. 1010 of 1024. Close! #define SetPin(Bit) PORTB |= (1 << Bit) #define ClearPin(Bit) PORTB &= ~(1 << Bit) //wire your IR led to this pin. (chip pin 5?); #define irOutPin 3 //This pin goes high when the sensor detects and obstacle. (chip pin 6) #define outPin 1 // wire this pin to your phototrans vcc-->phototrans-->pin4-->1M res-->gnd(chip pin3) #define sensorInPin 2 void setup() { pinMode(irOutPin, OUTPUT); pinMode(outPin, OUTPUT); //pinMode(2, OUTPUT); analogReference(0);//analogread won't work on Atiny13 w/o this line. Won't work on others WITH it prob'ly. } void loop() { static long difference = 0; unsigned static long lastTime = 0; SetPin(irOutPin); delay1(); unsigned int r1 = analogRead(sensorInPin); ClearPin(irOutPin); delay1(); unsigned int r2 = analogRead(sensorInPin); difference += r1 - r2; if(millis() - lastTime > 5)//might get a smoother response with bigger delays { if(difference > 0) { SetPin(outPin); } else { ClearPin(outPin); } difference = 0; lastTime = millis(); } } void delay1() { //delay(1) is too costly in memory. Why is this so much cheaper? :D long start = millis(); while(true) { if(millis() - start > 1){break;} } }
Step 6: Build Some Awesome Robot With the Sensor
Troubleshooting:
- Check all the wires.
- Wiggle the LEDs and make sure they align well with the barrel.
- Check the wires again.
- Have someone look over your shoulder while you explain where each wire goes. (This helps so often it's not even funny)
- Check the polarity of the LEDs and sensor and transistor.
- Check the polarity of the Attiny. If it's hot you put in in backwards.
- Use a phone or other digital camera to check that the LEDs are glowing.
- Turn off any flourescent lights and try the sensor away from sunlight.
- Take one the LEDs and attach it to long wires and put it right down the barrel of the sensor to see if it can see at all.
- Change out the 1M Resistor for smaller values to get less sensitivity.
- Tweak the code.
Step 7: Optional - the Circuit Board
This step has a PDF you can use on a laser printer with the toner transfer or photo methods of making boards. There's lots of instructions all over for how to do this. I did determine that adding a .1uf cap across VCC and GND on the chip helps make the board work more reliably.
Print the pattern on what will be the bottom of the board. Put in the components in from the blank side of the board according to the diagram and solder them. I bent the LED and sensor leads 90 degrees so the sensor would be looking "ahead".
The PDF and layout are slightly different than the picture. I added the 0.1uf cap explicitly and made the base leg of the transistor run keep away from the sensor line.
Attachments

Participated in the
Arduino Challenge

Participated in the
Robot Challenge
36 Comments
11 years ago on Introduction
Hi! Thanks for sharing this. I've working on this for a couple of days now since I read this instructable and this article http://www.ikalogic.com/infra-red-proximity-sensor-part-1/ . I'm using a Picaxe 14M chip and a clear capsule phototransistor (w/o filter) So far I found this: The sensor is very sensitive to daylight (I was working next to my room's window LOL ;) ).
In order to solve that problem, watching the behavior of the readings on my PC, I programmed my Picaxe to read the value of the phototransistor on the ADC0 (leg 7) with a 8bit resolution and add some to the reading (4 to be specific); the microcontroller takes a first reading of the phototransistor with the IR led (only one), adds 4 to it, takes a second reading of the prototransistor with the led on and compares, if the second is bigger than the first the indicator led goes on. This is reliably working for me between 4" and 1/2" even working next to the window!!! :D
Here is the program I downloaded on my Picaxe:
main:
low 5
readadc 0,b1
debug
high 5
readadc 0,b2
debug
let b3=b1+4
if b2>b3 then high 4
else low 4
pause 5
endif
goto main
The IR LED is connected on the output 5 and the indicator LED is connected on the output 4. I'm not familiar with Arduino, so I hope Picaxe people can use this too, this is really helping my little robot so, thanks again!
Reply 11 years ago on Introduction
I am so glad this helped you out. Thanks for the insights. My program could use some tweaking for working in bright lights or sunlight. Right now it can get confused under fluorescent lights that have a similar period.
7 years ago
amazing
work mate
8 years ago on Step 5
I had hoped that your recommendation to include analogReference(0); would solve my analogRead problems on the Attiny13... but sadly it doesnt I updated my core... but no luck.
Any suggestions?
Reply 8 years ago on Step 5
seems it is fixed. apparently needed to restart my IDE after the update of the core
9 years ago on Step 1
I am getting an error:
###############################################################
Arduino: 1.5.6-r2 (Windows 7), Board: "ATtiny13 @ 4.8MHz (internal 4.8 MHz clock)"
Attiny13IRproxsense.ino:22:21: error: Arduino.h: No such file or directory
Attiny13IRproxsense.ino: In function 'void setup()':
Attiny13IRproxsense:24: error: 'OUTPUT' was not declared in this scope
Attiny13IRproxsense:24: error: 'pinMode' was not declared in this scope
Attiny13IRproxsense:27: error: 'analogReference' was not declared in this scope
Attiny13IRproxsense.ino: In function 'void loop()':
Attiny13IRproxsense:34: error: 'PORTB' was not declared in this scope
Attiny13IRproxsense:36: error: 'analogRead' was not declared in this scope
Attiny13IRproxsense:42: error: 'millis' was not declared in this scope
Attiny13IRproxsense.ino: In function 'void delay1()':
Attiny13IRproxsense:61: error: 'millis' was not declared in this scope
This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.
#################################################################
I think the problem is that we used the 20 MHz chip you recommend, but there is no 20MHz option in the board menu.
10 years ago on Step 4
This circuit works for me as described...but according to the datasheet it shouldn't(?)
The datasheet for the phototransistor used says that, starting from the long pin side, the pins are: BASE, COLLECTOR, EMITTER (long, long, short).
So, actually, the circuit has the BASE connected to GRN through 1M Resistor (and also to the ATTiny input) while the EMITTER goes to +5V.
I'm very new to circuits/transistors, but that setup doesn't make any sense to me. Why does it work? Am I misreading the datasheet? (This is the datasheet I'm looking at: http://catalog.osram-os.com/media/_en/Graphics/00045426_0.pdf)
Reply 10 years ago on Step 4
I think that datasheet is wrong. Last time I clicked the link the datasheet was in English and the pins were CBE not BCE. I agree it shouldn't work as specified in that datasheet!
Reply 10 years ago on Introduction
American stuff is usually CBE, while Japanese components are often BCE. But they should have different part numbers to differentiate them. As always, you are the final inspector.
10 years ago on Introduction
I think it's at least possible that the part you refer to in your instructable (475-1439-ND) refers to a slightly different part on Digi-Spark and the pins are different now.
Mine works by ignoring the first long pin and putting the short pin to the 1M resistor (and Pin 3) and the middle pin to +5vcc - so if anyone orders the part from DigiSpark and it's not working the way you think it should - I would try this!
Reply 10 years ago on Introduction
I think you mean digikey. :)
You are right! I have the wrong PN! It's 475-1493-ND. Curse my dyslexia!
http://www.digikey.com/scripts/DkSearch/dksus.dll?vendor=0&keywords=%09475-1439-ND is the correct link. I'll update the instructable!
10 years ago on Introduction
If anybody is having trouble programming the ATTiny45/85 bootloader or sketch, I believe there is a bug in the newer version of the Arduino IDE (1.0.2). I mirrored precisely the files and steps I took to do this process successfully and put it in a Google Site for my own records.
If it helps anyone else, feel free to check it out here
Reply 10 years ago on Introduction
Thanks so much for sharing this.
10 years ago on Introduction
To fix the light and fluorescent interferenc,e use a 38kHz Infrared Receiver Module instead of the phototransistor.
Make sure you set the output to the IR led to 38Khz using something like;
irsend.enableIROut(38);
irsend.mark(0);
online they can be had under $,1 at radio shack they are about $4.
Reply 10 years ago on Introduction
You may need this library to set the 38khz part
http://www.arcfn.com/2009/08/multi-protocol-infrared-remote-library.html
Reply 10 years ago on Introduction
Keep in mind the Attiny13 has VERY limited space. The posted library may or may not fit.
11 years ago on Step 5
The novice might be a bit confused in setting up the core files as the MIT page only describes it for the 45-85 core and the 13 core does not come with a boards.txt file, so allow me to expand a bit here:
-Go to your sketches folder
-most likely there is a folder called 'hardware' if not, create that.
-open the hardware folder
-create a folder called 'attiny13'
open that folder
-create a new folder called 'core13'
-open that folder and unzip the attiny core files as found in the link in the beginning of this article
-go back to your /hardware/attiny13 folder
-create a text file called 'boards.txt'
open that file.
paste the following text in that file:
###########################################################################
attiny13.name=Attiny13 @ 128 KHz (internal watchdog oscillator)
attiny13.upload.using=arduino:arduinoisp
# attiny13.upload.protocol=avrispv2
# attiny2313at1.upload.using=pololu
attiny13.upload.maximum_size=1024
attiny13.upload.speed=250 # important for not losing connection to a slow processor
attiny13.bootloader.low_fuses=0x7B
attiny13.bootloader.high_fuses=0xFF
attiny13.bootloader.unlock_bits=0x3F
attiny13.bootloader.lock_bits=0x3F
attiny13.build.mcu=attiny13
attiny13.build.f_cpu=128000
attiny13.build.core=core13
###############################################################
attiny13at4.name=ATtiny13 @ 4.8MHz (internal 4.8 MHz clock)
attiny13at4.bootloader.low_fuses=0x69
attiny13at4.bootloader.high_fuses=0xff
attiny13at4.upload.maximum_size=1024
attiny13at4.build.mcu=attiny13
attiny13at4.build.f_cpu=600000
attiny13at4.build.core=core13
###############################################################
attiny13.name=ATtiny13 @ 9.6MHz (internal 9.6 MHz clock)
attiny13.bootloader.low_fuses=0x7a
attiny13.bootloader.high_fuses=0xff
attiny13.upload.maximum_size=1024
attiny13.build.mcu=attiny13
attiny13.build.f_cpu=9600000L
attiny13.build.core=arduino:arduino
attiny13.build.variant=tiny8
###########################################################################
save it.
restart your Arduino IDE (if you had it open, close it and then start it again)
check if you can see the newly added Attiny13 board under 'tools-boards'
Reply 11 years ago on Step 5
Nice! You should make this into an Instructable and I will link to it. Also you need to edit one of the core Arduino files to fix an issue with the timer. It's on one of the pages I linked.
Reply 11 years ago on Introduction
I am the maintainer of the Core13 project.
Can you please describe the problem that you experienced with the timer and I will look for a solution and try to incorporate it permanently.
Reply 11 years ago on Step 5
hardware/arduino/cores/arduino/wiring.c: 44
-#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__)
+#if defined(__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) || defined(__AVR_ATtiny13__)
SIGNAL(TIM0_OVF_vect)
This page describes changing wiring.c at the end of the post.
http://tekstop.wordpress.com/2011/12/30/programming-attiny13-using-arduino-isp-and-all-the-hacking-involved/