I decoded the Tomy Isobot IR protocol and made a shield for the Pro Mini 8Mhz to attach like a backpack to the Isobot. I have attached some quick pics. It is completely self sustained (runs off Isobot's 3 Nimhs), has an IR receiver to decode button commands, IR led to send to the bot, and an extra analog port for a distance sensor like my Maxbotics sonar (or a ping). Now I will go ahead and try to make the Isobot autonomous. Ill post code if anyone asks.
Yes, bohne you are correct. The arduino basically emulates the remote right now, so to do a punch, it will send the punch command through the IR led. I couldnt ever directly control the each of the 17 servos like I originally planned but if I ever get an oscilloscope, that will be on my to do list
great idea, can you provide more information about the IR codes? Are they RC5 codes? Maybe you can provide the command set or a sketch as an example?
Do you know other toys that use the same IR codes?
//Isobot IR decoder
//Written by Miles Moody
//Isobot IR protocol works as follows
//carrier freq of about 38khz
//header pulse of 2550 micros high
//22 data bits=4 for channel number, 18 for button number
//highs carry no info and are 550 micros each
//lows are logic 0 if 550 micros, logic 1 if 1050 micros
//at end of stream or in between, 205 millis low
//NOTE: my ir reciever pin goes low when it detects high signal
// and stays high when nothing is being recieved
// that could cause some confusion
//-------------------buttoncodes-------------------------
#define forward 898819
#define backward 964611
#define sideright 703491
#define sideleft 637699
#define p1 922368
#define k1 991744
#define g1 602624
#define zero 1034752
#define hp 775424
//-------------------info about bits-------------------------------
#define totallength 22 //number of highs/bits 4 channel +18 command
#define channelstart 0
#define commandstart 4 //bit where command starts
#define channellength 4
#define commandlength 18
//---------determined empirically--------------
#define headerlower 2300 //lower limit
#define headernom 2550 //nominal
#define headerupper 2800 //upper limit
#define zerolower 300
#define zeronom 380 //nominal
#define zeroupper 650
#define onelower 800
#define onenom 850 //nominal
#define oneupper 1100
#define highnom 630
//---------------------pin assignments--------------
#define TXpin 7
#define RXpin 2 //doesnt use interrupts so can be anything
//----------------------variables----------------------
boolean bit2[totallength];
unsigned long buttonnum;
//-----------------------program-----------------------
void setup() {
Serial.begin(38400);
Serial.println("Analyze Isobot IR Remote");
pinMode(RXpin, INPUT);
pinMode(TXpin, OUTPUT);
}
void loop(){
//Serial.println(receivecode()); //To find buttoncodes
if(Serial.available()>0){ //Serial control
char switcher= Serial.read();
switch (switcher){
case 'w':
buttonwrite(TXpin, forward);
break;
case 's':
buttonwrite(TXpin, backward);
break;
case 'a':
buttonwrite(TXpin, sideleft);
break;
case 'd':
buttonwrite(TXpin, sideright);
break;
case 'p':
buttonwrite(TXpin, p1);
break;
case 'k':
buttonwrite(TXpin, k1);
break;
case 'g':
buttonwrite(TXpin, g1);
break;
case 'h':
buttonwrite(TXpin, hp);
break;
case '0':
buttonwrite(TXpin, zero);
break;
}
}
}
unsigned long receivecode(){ //receives single code then puts into ulong code
boolean bit[totallength]; //should be 22 data bits 0-3 are channel code 4-21 are command bits
unsigned long plen[totallength]; //pulse length for debugging
int i=0; //bit number
boolean channel;//channel A=0 channel B=1
unsigned long commandcode; //18bits
unsigned long totalcode; //22bits
Serial.println("Waiting...");
while(digitalRead(RXpin)==HIGH){}//kill time till header pulse comes in
//RX is low here
for(i=0; i<totallength; i++){
plen[i]=pulseIn(RXpin, HIGH); //get length of HIGH pulses (yea mine works backwards)
}
for (i=0; i<totallength; i++){ //sets bits based on pulselength of HIGHs
if (plen[i]<zeroupper && plen[i]>zerolower)bit[i]=0;
else if (plen[i]<oneupper && plen[i]>onelower)bit[i]=1;
}
if (bit[0]==0)channel=0; //calculates channel based on highest bit value
else if (bit[0]==1)channel=1;
//commandcode=BtoI(commandstart, commandlength, bit); //calculates just commandcode
//totalcode=BtoI(channelstart, totallength, bit); //calculates totalcode
/* //uncomment code for signal analysis
Serial.println("p len\thi/lo"); //prints pulse length and bit state
for (i=0; i<totallength; i++){
Serial.print(plen[i]);
Serial.print("\t");
Serial.println(bit[i], DEC);
}
*/
/*
Serial.print("ch\tb code\t code\n"); //prints channel, buttoncode, channelcode
if (channel==0)Serial.print("A\t");
else Serial.print("B\t");
Serial.print(commandcode);
Serial.print("\t");
Serial.println(totalcode);
*/
/*
ItoB(commandcode, 18); //checks ItoB
ItoB(totalcode, 22);
for(i=commandstart; i<totallength; i++) Serial.print(bit2[i], DEC);
Serial.println();
for(i=0; i<totallength; i++) Serial.print(bit2[i], DEC);
Serial.println();
*/
for(i=0; i<totallength; i++) plen[i]=0;
delay(1000); //delays to cut repeated
return(BtoI(channelstart, totallength, bit));
}
unsigned long BtoI(int start, int numofbits, boolean bit[]){ //binary array to integer conversion
unsigned long integer=0;
int i=start;
int n=0;
while(n<numofbits){
integer+=bit[i]*power2((numofbits-n-1)); //same as pow()
i++;
n++;
}
Serial.println();
return integer;
}
void ItoB(unsigned long integer, int length){ //needs bit2[length]
for (int i=0; i<length; i++){
if ((integer / power2(length-1-i))==1){
integer-=power2(length-1-i);
bit2[i]=1;
}
else bit2[i]=0;
}
}
unsigned long power2(int power){ //gives 2 to the (power)
unsigned long integer=1; //apparently both bitshifting and pow functions had problems
for (int i=0; i<power; i++){ //so I made my own
integer*=2;
}
return integer;
}
void buttonwrite(int txpin, unsigned long integer){ //must be full integer (channel + command)
ItoB(integer, 22); //must have bit2[22] to hold values
oscWrite(txpin, headernom);
for(int i=0;i<totallength;i++){
if (bit2[i]==0)delayMicroseconds(zeronom);
else delayMicroseconds(onenom);
oscWrite(txpin, highnom);
}
delay(205);
}
void oscWrite(int pin, int time) { //writes at approx 38khz
for(int i = 0; i < (time / 52) - 1; i++){ //prescaler at 26 for 16mhz, 52 at 8mhz, ? for 20mhz
digitalWrite(pin, HIGH);
delayMicroseconds(13);
digitalWrite(pin, LOW);
delayMicroseconds(13);
}
}
#include "WProgram.h"
#include "Isobot.h"
//Isobot IR decoder and Controller
//Written by Miles Moody
//Isobot IR protocol works as follows
//carrier freq of about 38khz
//header pulse of 2550 micros high
//22 data bits=4 for channel number, 18 for button number
//highs carry no info and are 550 micros each
//lows are logic 0 if 550 micros, logic 1 if 1050 micros
//at end of stream or in between, 205 millis low
//NOTE: my ir reciever pin goes low when it detects high signal
// and stays high when nothing is being recieved
// that could cause some confusion
//-------------------info about bits-------------------------------
#define totallength 22 //number of highs=bits 4 channel +18 command
#define channelstart 0
#define commandstart 4 //bit where command starts
#define channellength 4
#define commandlength 18
//---------determined empirically--------------
#define headerlower 2300 //lower limit
#define headernom 2550 //nominal
#define headerupper 2800 //upper limit
#define zerolower 300
#define zeronom 380 //nominal
#define zeroupper 650
#define onelower 800
#define onenom 850 //nominal
#define oneupper 1100
#define highnom 630
//global vars (might be needed)
bool bit2[22]={};
//Constructors
Isobot::Isobot(int txpin){
pinMode(txpin, OUTPUT);
TXpin=txpin;
}
Isobot::Isobot(int txpin, int rxpin){
pinMode(txpin, OUTPUT);
pinMode(rxpin, INPUT);
TXpin=txpin;
RXpin=rxpin;
}
//functions
void Isobot::oscWrite(int time){
for(int i = 0; i < (time / 52) - 1; i++){ //prescaler at 26 for 16mhz, 52 at 8mhz, ? for 20mhz
digitalWrite(TXpin, HIGH);
delayMicroseconds(13);
digitalWrite(TXpin, LOW);
delayMicroseconds(13);
}
}
unsigned long Isobot::power2(int power){ //gives 2 to the int(power)
unsigned long integer=1; //apparently both bitshifting and pow functions had problems
for (int i=0; i<power; i++){ //so I made my own
integer*=2;
}
return integer;
}
void Isobot::buttonwrite(unsigned long integer){ //must be full integer (channel + command)
ItoB(integer, 22); //must have bit2[22] to hold values
oscWrite(headernom);
for(int i=0;i<totallength;i++){
if (bit2[i]==0)delayMicroseconds(zeronom);
else delayMicroseconds(onenom);
oscWrite(highnom);
}
delay(205);
}
void Isobot::buttonwrite(unsigned long integer, int numoftimes){ //same as above but repeats numoftimes
ItoB(integer, 22);
for (int n=0;n<numoftimes;n++){
oscWrite(headernom);
for(int i=0;i<totallength;i++){
if (bit2[i]==0)delayMicroseconds(zeronom);
else delayMicroseconds(onenom);
oscWrite(highnom);
}
delay(205);
}
}
void Isobot::ItoB(unsigned long integer, int length){ //needs bit2[length]
for (int i=0; i<length; i++){
if ((integer / power2(length-1-i))==1){
integer-=power2(length-1-i);
bit2[i]=1;
}
else bit2[i]=0;
}
}
unsigned long Isobot::BtoI(int start, int numofbits, boolean bit[]){ //binary array to integer conversion
unsigned long integer=0;
int i=start;
int n=0;
while(n<numofbits){
integer+=bit[i]*power2((numofbits-n-1)); //same as pow()
i++;
n++;
}
Serial.println();
return integer;
}
unsigned long Isobot::receivecode(){ //receives single code then puts into ulong code
boolean bit[totallength]; //should be 22 data bits 0-3 are channel code 4-21 are command bits
unsigned long plen[totallength]; //pulse length for debugging
int i=0; //bit number
boolean channel;//channel A=0 channel B=1
unsigned long commandcode; //18bits
unsigned long totalcode; //22bits
Serial.println("Waiting...");
while(digitalRead(RXpin)==HIGH){}//kill time till header pulse comes in
//RX is low here
for(i=0; i<totallength; i++){
plen[i]=pulseIn(RXpin, HIGH); //get length of HIGH pulses (yea mine works backwards)
}
for (i=0; i<totallength; i++){ //sets bits based on pulselength of HIGHs
if (plen[i]<zeroupper && plen[i]>zerolower)bit[i]=0;
else if (plen[i]<oneupper && plen[i]>onelower)bit[i]=1;
}
if (bit[0]==0)channel=0; //calculates channel based on highest bit value
else if (bit[0]==1)channel=1;
//commandcode=BtoI(commandstart, commandlength, bit); //calculates just commandcode
//totalcode=BtoI(channelstart, totallength, bit); //calculates totalcode
/* //uncomment code for signal analysis
Serial.println("p len\thi/lo"); //prints pulse length and bit state
for (i=0; i<totallength; i++){
Serial.print(plen[i]);
Serial.print("\t");
Serial.println(bit[i], DEC);
}
*/
/*
Serial.print("ch\tb code\t code\n"); //prints channel, buttoncode, channelcode
if (channel==0)Serial.print("A\t");
else Serial.print("B\t");
Serial.print(commandcode);
Serial.print("\t");
Serial.println(totalcode);
*/
/*
ItoB(commandcode, 18); //checks ItoB
ItoB(totalcode, 22);
for(i=commandstart; i<totallength; i++) Serial.print(bit2[i], DEC);
Serial.println();
for(i=0; i<totallength; i++) Serial.print(bit2[i], DEC);
Serial.println();
*/
for(i=0; i<totallength; i++) plen[i]=0;
delay(1000); //delays to cut repeated
return(BtoI(channelstart, totallength, bit));
}
One thing to note for jcolebot, you have to change the prescaler in the .cpp file if youre using a 16mhz arduino from 52 to 26 or it wont oscwrite wont work right. I have been using an 8mhz pro mini arduino so i left it at 52.
To crazydoc, made a little progress with a proximity ultrasound sensor letting me either avoid obstacles walking around or home in on them and punch them. Should be really easy to get yours playing soccer but hard to do it well. I check here pretty regularly and id be glad to give any help i can with your project
I cant get you anymore pics for at least a week. Im on summer vacation away from my apartment right now.
I use this: FTDI Basic Breakout - 3.3V - DEV-08772 - SparkFun Electronics, i think its as cheap as it comes (most people already have the usb cable)
As for the version of arduino, i chose 8mhz pro mini cuz it runs off 3.3v as opposed to 5v. The isobot carries only 3.6v of AAAs so i would have needed another battery pack to run a full 5v 16mhz arduino. If youre not running the arduino off of the isobot's batteries, id recommend you go 16mhz 328 just cuz thats the newest and most compatible. Actually id recommend a 328 anyway just so you have the program space.
Sure, Id be happy to share any code. It just uses a maxbotix sonar sensor to sense distance forward, head turned left and right and goes whichever way is further away (or closer depending if its in "attack mode") Let me know if/when you get your hardware up and running.
very cool i had just done a very similar mod to a robosapien but instead of an ir led i tapped into the ir line on the robots motherboard it still is fully function with the remote when the arduino is off. i have also mounted a ping in its chest.seems we are after a common goal
You have to install the Isobot library like any other library. First create a folder named Isobot under the arduino-00xx->hardware->libraries folder then copy the isobot.h, isobot.cpp, and the keywords.txt (which i am about to post-this was a good reminder) with the proper extensions into the Isobot folder. The first time you compile with this library, it will give you an error but thats just it making an object file (arduino glitch). The second time it should be fine.