Salut Nathonline,
J'ai acheté précisément deux Xbees modules pour mettre en sans-fil un vieux système que j'ai fait il y a de cela 6 ans.
Un ami à moi m'a donné deux de ces vieux aspirateurs Roomba. Ils ne fonctionnaient plus. J'ai réussi à réparer le vieux modèle, un de la série 400. J'ai changé la batterie! ouff très difficile comme réparation.
J'ai eu le même modèle auparavant. Ce modèle n'avait pas d'horloge interne mais pouvait être allumé avec une télécommande. J'ai donc fait, avec un micro-processeur, un convertisseur qui transpose les caractères ascii en code de la télécommande. Maintenant que j'ai de nouveau ce robot, j'ai décidé de l'utiliser au deuxième étage de ma maison puisque le premier ce fait avec mon roomba actuel qui a une horlorge interne.
Le problème sera de communiquer avec la boîte noire sans utiliser de fil. J'ai donc pensé à utiliser deux Xbees modules.
Ce sont des séries 2 donc il y en a un en coordinateur. J'ai donc configuré les Xbees en conséquence avec un PC puisque la configuration ce fait avec une application PC.
Ensuite j'ai branché le Xbee, mode router/end , sur le port série ttyAMA0 du Raspberry PI et branché le coordinateur sur le port usb avec l'adaptateur DFrobot, (robotshop RB-Dfr-148). Pour l'instant le coordinateur sera sur le port usb avec le Raspberry Pi.
L'autre Xbee sera avec le convertisseur optique. (La télécommande ASCII).
Pour tester les deux Xbees avec le Rpi, j'utilise minicom avec deux consoles. (apt-get install minicom)
La première console ouvre minicom pour le router/end Xbee.
P.S. Il faut désactiver la console login de ttyAMA0 dans inittab. Ajoutez le caractère # et faire un reboot.
Code: Select all
#T0:23:respawn:/sbin/getty -L ttyAMA0 115200 vt100
La deuxième console ouvre minicom pour le coordinateur sur l'adaptateur USB.
Voici un vidéo que j'ai fait il y a 6 ans de cela. (La webcam n'avait pas de filtre infra-rouge. Les capteurs sont donc visibles).
https://dl.dropboxusercontent.com/s/p4f ... roomba.wmv
Le schéma
https://dl.dropboxusercontent.com/s/hnj ... c_v1_1.pdf
Le code source du cpu
Code: Select all
/*
Copywright 2007 Daniel Perron
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/*
Author : Daniel Perron
Date : 28 October 2007
Version : 1.1
Name : ir.c
Compiler used : SDCC ( may 31 2007)
How to compile:
sdcc --model-small --iram-size 128 --data-loc 0x20 ir.c
packihx ir.ihx > ir.hex
Description: Send ,from rs-232 , ir command to roomba cleaner robot
- Normal mode. Send a string of command , maximum of 24 characters, ended by a cariage return.
- Direct mode. Execute command one character at the time.
Caracter command;
F -> Send I.R. forward.
L -> Send I.R. left.
R -> Send I.R. right.
P -> Send I.R. power.
D -> Send I.R. dock.
C -> Send I.R clean.
M -> Send I.R. maximum clean.
S -> Send I.R. spot clean.
#hh -> Send I.R. Raw data where hh is a 8 bits hexadecimal value.
A -> Power ON base station.
Z -> Power OFF base station.
W -> Wait NTimes * 100ms.
1..9 -> set NTimes value. NTimes=1 to 9.
! -> Enter direct mode.
ESC -> Exit from direct mode.
P.S. any data is send NTimes. A command like "5ZWWWWPWCA" will turn off base station, wait 2 seconds,Power ON roomba,Wait half of second,
start clean command and finally power up base station again. The Ir command is send Ntimes without gap.
This ensure that the command is received by the I.R. receiver. On this sample NTimes is equal to 5.
Ntimes could be change at any times like "9W1W5P5W". Ntimes= 1..9; (only one digit number,Zero excluded).
Processor: at80c2051 at 11.0592Mhz. 20 pins Atmel 8051 familly processor
Port 1 bit 0..7 -> Output -> All I.R. Led signal.
Port 3 bit 7 -> Outout -> Base station Relay.
Port 3 bit 5 -> Input -> 0 = Disable Txm , 1 = Enable Txm.
*/
#include <at89x51.h>
#define LEDS P1
#define BASE_STATION P3_7
#define TransmitEnable P3_5
#include <stdio.h>
#include <ctype.h>
bit BitHigh;
bit DirectMode;
#define TOKEN_NONE 0
#define TOKEN_IR 1
#define TOKEN_NTIMES 2
#define TOKEN_WAIT 3
#define TOKEN_DIRECT_MODE 4
#define TOKEN_BREAK 5
#define TOKEN_HELP 6
#define TOKEN_STATION_OFF 7
#define TOKEN_STATION_ON 8
#define TOKEN_DATA 9
#define TOKEN_DATA_HNIBBLE 10
#define TOKEN_DATA_LNIBBLE 11
unsigned char TokenType;
unsigned char TxmHeader;
unsigned char TxmData;
unsigned char RcvData;
unsigned char TxmBitCount;
unsigned char NTimes;
unsigned char RawIrData;
unsigned char Timer10ms;
unsigned char TimerCountDown;
// be carefull String are store in unused
// data memory gap. The working register block 2,3 and 4
#define STRING_MAX 24
__data __at (0x8) unsigned char String[STRING_MAX] ;
unsigned char StringCount;
void Delay_off(unsigned char count)
{
unsigned char loop;
LEDS=0xff; // leds off
for(loop=0;loop<count;loop++)
{
_asm nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
nop
_endasm;
}
}
void Delay_on(unsigned char count)
{
unsigned char loop;
// 11.0592Mhz / 12 = 921600 cycles/sec
// 921600 cycle/sec / 38400 Hertz = 24 Cycles
for(loop=0;loop<count;loop++) // 8 cycles for loop
{
LEDS=0; // led on // 2 cycles
_asm nop // nop is 1 cycle
nop
nop
nop
nop
nop
nop
nop
nop
nop
_endasm;
LEDS=0xff; // led off // 2 cycles
_asm nop
nop
_endasm;
}
}
const char * StringHelp = "\r\n"\
"=================================\r\n"\
" IR remote\r\n"\
" D.J.P. V1.1, 12 Oct 2007.\r\n"\
"=================================\r\n"\
" F -> Forward\r\n"\
" L -> Left\r\n"\
" R -> Right\r\n"\
" P -> Power\r\n"\
" D -> Dock\r\n"\
" C -> Clean\r\n"\
" M -> Max clean\r\n"\
" S -> Spot clean\r\n"\
" A -> Base Station ON\r\n"
" Z -> Base Station OFF\r\n"
"#hh -> Send I.R. Raw data\r\n"
" where hh = byte hex value\r\n"
" ! -> Enter interactive mode \r\n"
" W -> wait NTIMES * 100 ms\r\n"
"1..9 -> Set NTimes values\r\n"
"=================================\r\n"\
"\r\n";
void SendIr(unsigned char Data)
{
TxmHeader= 0x4a; // roomba header
TxmData= Data;
for(TxmBitCount=16;TxmBitCount>0;TxmBitCount--)
{
__asm
mov A,_TxmData
rlc A
mov _TxmData,A
mov A,_TxmHeader
rlc A
mov _TxmHeader,A
mov _BitHigh,C;
__endasm;
if(BitHigh)
{
Delay_on(114); // 38Khz for 3 ms
Delay_off(38); // 38Khz for 1ms
}
else
{
Delay_on(38); // 38Khz for 1 ms
Delay_off(114); // 38Khz for 3 ms
}
}
Delay_off(152);
}
void NSendIr(unsigned char Data)
{
unsigned char loop;
if(NTimes==0) NTimes=1;
if(NTimes>9) NTimes=9;
for(loop=0;loop<NTimes;loop++)
SendIr(Data);
}
void printerror()
{
if(TransmitEnable)
{
TI=0;
SBUF='X';
while(!TI);
}
}
void printchar(char value)
{
if(TransmitEnable)
{
TI=0;
SBUF=value;
while(!TI);
}
}
void print(const char * String)
{
if(TransmitEnable)
{
while(*String)
{
TI=0;
SBUF= *(String++);
while(!TI);
}
}
}
void printNibble(unsigned char value)
{
if(TransmitEnable)
{
value = value & 0xf;
if(value >9) value += 'A' - 10;
else value += '0';
TI=0;
SBUF=value;
while(!TI);
}
}
void printHex(unsigned char value)
{
if(TransmitEnable)
{
print("0x");
printNibble(value >> 4);
printNibble(value);
}
}
unsigned char GetHex(unsigned char value)
{
if( value < '0' ) return(16);
if(!( value > '9')) return(value - '0');
if(!( value < 'A' ))
if(!(value > 'F' ))
return(value - 'A' + 10);
return(16);
}
unsigned char GetCommand(unsigned char value)
{
unsigned char IrData;
value= toupper(value);
if((TokenType == TOKEN_DATA) || (TokenType == TOKEN_DATA_HNIBBLE))
{
IrData = GetHex(value);
RawIrData = RawIrData * 16;
RawIrData += IrData;
if(IrData == 16) TokenType = TOKEN_NONE;
else if(TokenType == TOKEN_DATA) TokenType= TOKEN_DATA_HNIBBLE;
else TokenType = TOKEN_DATA_LNIBBLE;
return(RawIrData);
}
if(value > '0')
if(value < ':')
{
TokenType= TOKEN_NTIMES;
return(value - '0');
}
TokenType= TOKEN_IR;
switch(value)
{
case 'F': return(130);
case 'L': return(129);
case 'R': return(131);
case 'P': return(138);
case 'D': return(143);
case 'C': return(136);
case 'M': return(133);
case 'S': return(132);
case 'H':
if(DirectMode)
TokenType=TOKEN_HELP;
else
TokenType=TOKEN_NONE;
break;
case 'W':
TokenType=TOKEN_WAIT;
break;
case 'Z':
TokenType=TOKEN_STATION_OFF;
break;
case 'A': TokenType=TOKEN_STATION_ON;
break;
case '#': TokenType=TOKEN_DATA;
break;
case '!': TokenType=TOKEN_DIRECT_MODE;
break;
case 27: TokenType=TOKEN_BREAK;
break;
default: // any unknowned command send 'X' back
TokenType=TOKEN_NONE;
}
return 0;
}
unsigned char ExecuteToken(unsigned char Token,unsigned char value)
{
unsigned char loop2;
unsigned char loopNtimes;
switch(Token)
{
case TOKEN_IR:
NSendIr(value); break;
case TOKEN_NTIMES: NTimes=value; break;
case TOKEN_WAIT:
for(loopNtimes=0;loopNtimes<NTimes;loopNtimes++)
for(loop2=0;loop2<100;loop2++)
Delay_off(38);
break;
case TOKEN_STATION_OFF: BASE_STATION= 1; break;
case TOKEN_STATION_ON: BASE_STATION= 0; break;
case TOKEN_BREAK: DirectMode=0;
StringCount=0;
break;
case TOKEN_DIRECT_MODE: DirectMode=1;
StringCount=0;
break;
case TOKEN_DATA:
case TOKEN_DATA_HNIBBLE: break;
case TOKEN_HELP: print(StringHelp);
return(0);
break;
case TOKEN_DATA_LNIBBLE:
NSendIr(RawIrData); break;
default:
StringCount=0;
printerror();
return(0);
}
return 1;
}
unsigned char GetStringToken(void)
{
unsigned char loop;
unsigned char value;
if(RcvData== '\r')
{
for(loop=0;loop<StringCount;loop++)
{
value=GetCommand(String[loop]);
if(!ExecuteToken(TokenType,value))
{
printerror();
StringCount=0;
return(0);
}
}
StringCount=0;
printchar('.');
}
else
{
if(StringCount < STRING_MAX)
{
String[StringCount++]=RcvData;
printchar(RcvData);; // ok string command ok echo it
}
else
{
StringCount=0;
printerror();
return(0);
}
}
return(1);
}
void main(void)
{
unsigned char value;
LEDS=0xff; // turn led off
NTimes=3; // In debug mode send the character 5 times.
DirectMode=0; // StringCode mode off
BASE_STATION=0;
StringCount=0;
TokenType= TOKEN_NONE;
// init serial
ES=0; // disable serial
/* PCON BIT 7 DOUBLE THE BAUD RATE IF SET */
/* PCON=PCON AND 7FH */
/* DOUBLE BAUD RATE */
// set 8bit data
SCON = 0x50;
TR1 = 1; // enable t1
TR0 = 0;
// // TR0 = 1; // enable t0 has wait timer
//TH1=0xFD; //9600baud for 11.0592Mhz
TH1= 0xE8; //1200 baud
// // TH0= 0xDB; // set 16bit counter at 9216 to get 10 ms timeout flag
// // TMOD = 0x21; // T1 has baud rate T0 has 16 bit timer
TMOD = 0x20;
PT0= 1;
TR0= 1;
ET0= 0;
RI=0;
EA=1;
// print(StringStart);
while(1)
{
if(RI) // ARE we getting character from rs 232
{
RcvData= SBUF; // caracter to transfer
RI=0;
if(RcvData == 10) continue;
if(DirectMode)
{
value=GetCommand(RcvData);
if(TokenType==TOKEN_NONE)
printerror();
else
{
if(ExecuteToken(TokenType,value))
printchar(RcvData);
}
}
else
{
if(!GetStringToken()) // GetStringCodeCommand
{
//ok bad command or buffer full
// forget string command
TokenType=TOKEN_NONE;
StringCount=0;
continue;
}
}
}
}
}
Maintenant il me reste à ajouter le Xbee à l'entrée de l'isolateur optique. Peut être le mieux serait d'enlever l'isolateur et de brancher directement le Xbee sur le micro-processeur tout en changeant le régulateur à 3.3V au lieu de 5V. (le cpu peut rouler à cette tension).
Daniel