Some Old Robot Code
Post date: Mar 23, 2012 4:31:15 AM
This actually has nothing to do with VKP but it came up in a discussion today so I dusted it off and commented it up. I'm posting it here because I don't have a more generic place to publish it but I want to send a link to some other robot nerds (yes you.)
This is an Arduino sketch that I wrote/cobbled which powers an Infra Red proximity sensor because I have two kids and a mortgage in california and the pre-built IR proximity sensors cost more than my motors.
pre-built == $14USD to the mid twenties.
mine
1 IR LED == free because I salvaged it from an old remote.*
1 TSOP38238 == $1.95 from sparkfun
1 a little bit of solder and wire
1 hunk of something to mount the LED and Sensor in. Optional if you are creative with your solder.
1 (each) a few inches of paper, aluminum foil and electrical tape to create tubes to go over both components to prevent triggerinig yourself since the LED and sensor are soldered together. ^_^
*Or you can buy them for about a buck each at sparkfun assuming you don't go find yourself a better deal.
Code:
// This code works for detection. I'm tuning it up so I can use it somewhere's else. The detector module built with this uses a standard
// IR led and a tsop382 though it should work with any 38khz carrier band IR reciever.
// You can see a sample of how to set up the reciever on lady Ada's site from my comments below. Connect the IR like any other LED.
// The down side to the TSOP is that it filters out any continuous pulses so if I just flash at 38hz it ignores it.
// Hooked my IR LED up through a resistor to lower the output power and jammed an aluminium foil tube over the top of the sensor.
// Right now it detects objects at between about two and four inches. When I first got it working I thought I had a code problem because
// the indicator light was on 100% of the time. Turned out it was because I was detecting the cieling, the wall on the other side of the kitchen,
// whatever part of the inside of my house it was pointed to.
// Some further playing with Resistor sizes and shielding materials/shapes will be neccesary to tune to specific ranges
// I would like to do a couple of things.
// A) switch to and verify some other IR code so that I can't be faked out by a remote control or randomly set off household stuff.
// B) create a mechanism for having multiple codes for multiple sensors so they can't accidentally trigger one another. (not 100% neccesary
// since it's simple enough to just not send/check from any sensors at the same time.
// C) Switch to using the phototransistor and doing FDM so that I can measure distance in addition to just detecting if something is there. But that's quite a bit more advanced.
int IndicatorPin = 12; // Light up pin 12 to show that we have successfully detected something. Replace this with another function in robot code.
int IRledPin = 4; // IRLED connected to pin 4
int IRSensorPin = 5; // input from IR sensor on pin 5
int STARTUPDELAY=(5*1000); // N * 1k == N seconds to wait at startup. Just in case I hozed myself.
// The setup() method runs once, when the sketch starts
void setup() {
// initialize the pins we are using for input and output.
pinMode(IRledPin, OUTPUT);
pinMode(IndicatorPin, OUTPUT);
pinMode(IRSensorPin, INPUT);
delay(STARTUPDELAY); // Wait a sec before we are ready I find this prevents me from accidentally creating an infinate loop which can cause you to be unable to do _anything_ w/ the arduino including upload fixed code.
//Serial.begin(9600); // you'll need to uncomment this and the relavent messages below if you want to log to serial out in order to observe your progress.
//Serial.println("Starting");
}
void loop() // All arduino code has one of these. Just pretend it's called main().
{
//Serial.println("Sending IR signal");
CheckSensor();
delay(60); // We don't want to flood the thing so we'll check only every 60ms
}
void CheckSensor() {
SendCode(); // Send a PWM IR signal then:
if (digitalRead(IRSensorPin) == 0) { // Check and see if we are getting any IR back
// if the output is low then we have detection light the LED
digitalWrite(IndicatorPin,HIGH); // Gah! We're gonna crash! Tell someone. In real robot code this would be replaced with turn left/right/back/etc code.
} else {
// failed no light
digitalWrite(IndicatorPin,LOW);
}
// If you look carefully you'll notice that I'm not actually checking to see that the signal is the correct one.
// If I was using just say an IR phototransistor that would mean my bot would be fairly succeptable to IR interfearence.
// However the IR module I am using has a number of built in protectoins against IR interfearance. Some of which cased me to
// take some, interesting, measures to get it to work. However it is still susceptable to some forms of interfearance.
// Specifically, any 38khz carrier based IR remote code (and probably a few near by like 37) will trigger it.
// Pointing yout TV remote at the sensor and hitting any button will likely trigger the proximity sensor.
// Ultimately I should be checking that the signal is correct. This would also bring the 'spurrious signals' protection
// into the code and out of the hardware allowing me to replace the tsop sensor with an IR photo transistor or something else.
// It also gives me the ability to send a different signal from each sensor preventing bounced signals from triggering us to turn the wrong way.
}
// Send a specially crafted IR signal that the IR reciever module will detect. Totally snarched from ladyada.net original signal send code below.
void SendCode() {
pulseIR(2080);
delay(27);
pulseIR(440);
delayMicroseconds(1500);
pulseIR(460);
delayMicroseconds(3440);
pulseIR(480);
// Why such a funky way to create an IR?
// First because I am using an IR sensor which I picked up from sparkfun, see below. Most IR sensors have some built in facilities to protect
// against IR interfearence. First is typically by blocking any constant like, I dunno, the sun, signals ad any 'spurrious' signals.
// the second is that they usually only trigger on signals that are pulse modulated aound a specific carrier frequency.
// Mine is 38khz but there are about ten or so others that are not uncommon. This helps prevent tv/electronics manufacturers from
// stepping on one another. It would suck to get a new DVD player only to learn that every time you hit play on the dvd player it
// powered off your TV.
// So why not just a plain 38khz base signal? Well it turns out the specific reciever module i'm using also blocks out 'any constant wave'
// Apparently not all of them do so while I was able to find code samples that did _exactly_ 100% of what I was trying to do they didn't work.
// Frustrating, you can imagine.
// http://www.sparkfun.com/products/10266
// If sparkfun ever takes that link down it's a TSOP 38238
}
// These two functions where snartched from here.
// http://www.ladyada.net/learn/sensors/ir.html
// The fun part however is apparently she got herself a new camera. I grabbed this some time in 2010/2011. I just looked it (mar 2012)up
// to grab the URL to stick into here and while the code is identical the word 'cannon' has been replaced with 'nikon' in all code and comments.
// This procedure sends a pure 38KHz pulse to the IRledPin
// for a certain # of microseconds. We'll use this whenever we need to send codes
void pulseIR(long microsecs) {
// we'll count down from the number of microseconds we are told to pulse for
cli(); // this turns off any background interrupts
while (microsecs > 0) {
// 38 kHz is about 13 microseconds high and 13 microseconds low
digitalWrite(IRledPin, HIGH); // this takes about 3 microseconds to happen
delayMicroseconds(10); // hang out for 10 microseconds
digitalWrite(IRledPin, LOW); // this also takes about 3 microseconds
delayMicroseconds(10); // hang out for 10 microseconds
// so 26 microseconds altogether
microsecs -= 26; // tick 26 seconds off the milosecs counter since we just spent them.
}
sei(); // this turns them back on
}
// old cannon signal generator
void SendCanonCode() {
// This is the code for my particular Canon, for others use the tutorial
// to 'grab' the proper code from the remote
pulseIR(2080);
delay(27);
pulseIR(440);
delayMicroseconds(1500);
pulseIR(460);
delayMicroseconds(3440);
pulseIR(480);
delay(65); // wait 65 milliseconds before sending it again
pulseIR(2000);
delay(27);
pulseIR(440);
delayMicroseconds(1500);
pulseIR(460);
delayMicroseconds(3440);
pulseIR(480);
}