Go Down

Topic: I-Sobot hacked or Pro Mini shield (Read 22956 times) previous topic - next topic

knuckles904

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.






florinc

So the arduino does not interfere with the robot's servos yet, it can only interpret the commands from the remote for now, right?


bohne

cool project.

Did I get it right: you use an IR LED to control the robot? If you want to make the robot move, you send the corresponding IR code via this LED?
http://www.dorkbot.de
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1236434254
http://www.luminet.cc

knuckles904

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

bohne

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?
http://www.dorkbot.de
http://www.arduino.cc/cgi-bin/yabb2/YaBB.pl?num=1236434254
http://www.luminet.cc

knuckles904

#5
Mar 24, 2009, 12:24 am Last Edit: Mar 24, 2009, 12:25 am by knuckles904 Reason: 1
Its all in the code:

Code: [Select]
//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);
 }
}

knuckles904

turned the code into my first library. much neater now

example code:
Code: [Select]
#include <Isobot.h>

Isobot bot(7);
unsigned long time1, time2;

void setup(){
 time1=time2=millis();
 pinMode(13, OUTPUT);
}

void loop(){
 if(millis()>(5000+time1)){
   digitalWrite(13, HIGH);
   bot.buttonwrite(homeposition,3);
   
   time1=millis();
   digitalWrite(13,LOW);
 }
 
 if(millis()>(20000+time2)){
     digitalWrite(13,HIGH);
     bot.buttonwrite(rpunch,3);
     
     time2=time1=millis();
     digitalWrite(13,LOW);
 }
}


Isobot.h:
Code: [Select]
//Isobot IR Decoding and Sending Library
//Written by Miles Moody
//Free and open to the public

#ifndef Isobot_h
#define Isobot_h

#include "WProgram.h"
#include "WConstants.h"

class Isobot{
     public:
            Isobot(int txpin);
            Isobot(int txpin, int rxpin);
            unsigned long receivecode();
            void buttonwrite(unsigned long integer);
            void buttonwrite(unsigned long integer, int numoftimes);
     private:
             int TXpin;
             int RXpin;
             void oscWrite(int time);
             unsigned long power2(int power);
             void ItoB(unsigned long integer, int length);
             unsigned long BtoI(int start, int numofbits, boolean bit[]);
             
};

//-------------------buttoncodes-------------------------
#define forward      898819
#define backward     964611
#define sideright    703491
#define sideleft     637699
#define fleft        1030403
#define fright       571907
#define bleft        834819
#define bright       900611
#define fclockwise   966403
#define fcounter     1032195
#define bclockwise   573699
#define bcounter     639491
#define headleft     907015
#define headright    775948
#define leanforward  841478
#define leanback     1038081
#define lpunch       922368
#define r12          661248
#define lchop        858368
#define sidechopl    663040
#define combopunch   597248
#define rpunch       988160
#define rchop        924160
#define l12          792576
#define sidechopr    728832
#define lbackhand    529664
#define doublechop   989952
#define doublebackhand 925952
#define slapping     860160
#define rbackhand    595456
#define upperchop    531456
#define roundhousel  991744
#define roundhouser  533248
#define forwardkickl 599040
#define forwardkickr 664832
#define sidekickl    730624
#define roundhouselr 666624
#define forwardkicklr 732416
#define combokick    798208
#define sidekickr    796416
#define backkickl    927744
#define backkickr    993536
#define highkickl    864000
#define highkickr    995328
#define splits1      536832
#define guardl       602624
#define guardr       668416
#define doubleguard1 734208
#define doubleguard2 800000
#define dodgel       865792
#define dodger       931584
#define duck         604160
#define swayback     669952
#define upblock      735744
#define splits2      801536
#define comboblock   867328
#define zero         1034752
#define homeposition 775424
#define soundoff     840451
#define affirm       540416
#define disagree     803328
#define goodmorning  934912
#define greet1       1000704
#define greet2       608000
#define greet3       739328
#define greet4       805120
#define bye1         870912
#define bye2         936704
#define bye3         1002496
#define bye4         544000
#define bye5         542208
#define respect      869120
#define thanks1      609792
#define thanks2      675584
#define love1        872704
#define love2        938496
#define love3        1004288
#define standupfront 933120
#define standupback  998912
#define excited1     743168
#define excited2     874496
#define excited3     940288
#define excited4     618752
#define party        677376
#define amazed       750336
#define regret1      547584
#define regret2      744960
#define regret3      810752
#define worry        679168
#define pain1        1007872
#define pain2        615168
#define beg1         942080
#define beg2         880128
#define merry        552960
#define hilarious    1013504
#define hidenseek    613376
#define youlike      682752
#define mystery5     748544
#define tipsy        814336
#define tickleme     686080
#define tiredfeet    751872
#define needabreak   817664
#define wave1        883456
#define wave2        949248
#define applause     947712
#define mystery6     945920
#define toosexy      1015040
#define clink        556544
#define relax        753664
#define soccer1      885248
#define soccer2      600832
#define soccer3      535040
#define lift         819456
#define countonme    951040
#define articulation 1016832
#define showoff1     558336
#define showoff2     624128
#define showoff3     689920
#define showoff4     821248
#define cominthrough 887040
#define catch        1006080
#define pose1        771840
#define pose2        903168
#define pose3        968960
#define mystery1     684544
#define mystery2     816128
#define mystery3     881920
#define mystery4     549376
#define forwardsomersault  952832
#define headstandexercises 1018624
#define exercises    560128
#define airdrum      625920
#define airguitar    691712
#define randomperformance1 954624
#define randomanimal   627712
#define tropicaldance  825088
#define giantrobot     956416
#define western        1022208
#define randomperformance2  629504


#endif


knuckles904

and Isobot.cpp:
Code: [Select]
#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));
}


Hooray for my first library completed!!!

whisperoftheshot

This is amazing, I had this idea as well after i got an isobot for christmas.  Thank you so much, I am just about to try this out. ;D

whisperoftheshot

#9
Jun 03, 2009, 11:12 pm Last Edit: Jun 03, 2009, 11:12 pm by whisperoftheshot Reason: 1
ive been having some trouble using this, I am trying to control my isobot from keyboard commands sent through serial to the arduino.  I am using
Code: [Select]
#include <Isobot.h>

Isobot bot(13);
unsigned long time1, time2;
long timer;

void setup(){
   Serial.begin(38400);
 time1=time2=millis();
 pinMode(13, OUTPUT);
    Serial.println("Starting...");
    delay(500);
    Serial.println("go!");
}

void loop(){
 //timer = millis()/1000;
 //Serial.println(timer);
 delay(1000);
  //digitalWrite(13, HIGH);
  bot.buttonwrite(forward,3);
  Serial.println("Forward");
 //digitalWrite(13, LOW);
 
 
}

with the ir led on pin 13,
I was able to receive signals from the remote
and correctly identify which movement they were

Any ideas?  thanks in advancel. :-?

Crazydoc

Hello knuckles904,

great work on that I-Sobot hacking!  :)

Have you made any further progress on that topic ?

Would be nice to read some news.

I have bought an I-Sobot but it will take some time to get it to my place.

Can you show / explain your extra sensors please ?

I would like to add proximity sensors too.
I want to make this little fellow a soccer player. :)

Like two sensors on each foot. If there is something close to them (the ball), then he should make the kick on that specific foot.

But unfortunately I don't have great programming skills. :(



knuckles904

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

Crazydoc

#12
Jun 13, 2009, 12:59 am Last Edit: Jun 13, 2009, 01:04 am by Crazydoc Reason: 1
Hi,

can you show some more pictures of your setup please ?

Do you use a USB TTL-232R 3V3 cable ?

I wonder why the cable is more expensive than the Arduino Pro Mini itself. :(

If I start the project: Will it be better to buy the 16MHz version ?
Or the newer ATmega328 ?

Thanks.


knuckles904

I cant get you anymore pics for at least a week. Im on summer vacation away from my apartment right now.
I use this: http://www.sparkfun.com/commerce/product_info.php?products_id=8772, 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.

Crazydoc

I think I will buy the Arduino Pro Mini 328 - 5V/16MHz and the FTDI Basic Breakout 5V.

Ok, then I need two small LiPo batteries and a 5V voltage regulator but it will be easier with external sensors. Most of them are using 5V too.

So the I-Sobot is walking autonomously with your sensors and program code ?

Can you post any new updates of that code next week please ?

Thanks. :)

Go Up