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

}