Hallo,
ich will euch noch meine neueste Anwendung zeigen.
Die Bee bleibt innerhalb der schwarzen Linie und weicht Hindernissen aus:
http://www.youtube.com/watch?v=zkHDD5SZ50U
Druckbare Version
Hallo,
ich will euch noch meine neueste Anwendung zeigen.
Die Bee bleibt innerhalb der schwarzen Linie und weicht Hindernissen aus:
http://www.youtube.com/watch?v=zkHDD5SZ50U
Nochmals hallo,
bei der Bee werden den PINS 26 bis 29 (also PC4 - PC7) für die Taster verwendet.
Ist es möglich an diesen Pins je 2 IR-Sender und Empfänger anzuschliessen? Das wäre gut, denn dann könnte ich auf die "Fühler" verzichten.
Super, dann werde ich die Taster ablöten, und dann 2x2 Infrarot-DIODEN vom Typ SFH415-U und 2 Stk. IR-TRANSISTOR vom Typ SFH5110 an den PINs anschliessen.
Hallo,
ich habe mir an den Stecker X5 einen SFH5110 IR-Empfänger angeschlossen und mit einer RC5-Fernbedienung etwas herumgespielt.
Was dabei herausgekommen ist, ist folgendes Programm, mit dem man die Nibobee fernsteuern kann.
Viel Spass beim Ausprobieren.Code:/*********************************************
*** RC5 Dekoder
*** Version 1
***
*** Nibobee wird mit IR-Fernbedienung ferngesteuert.
***
*** PD0=RxD verbunden mit Ausgang IR-Empfänger SFH5110
***
*** 36kHz (27,7 usek) werden mit Timer2 erzeugt.
*** Der Eingang PD0 wird alle 8 * 27,7 = 222 usek
*** abgefragt.
***
*** LED0 (linke gelbe) = Betrieb
*** LED1 (linke rote) = blinkt bei RC5 Empfang
***
*** Author : H. Krause 2010
**********************************************/
#include <nibobee/iodefs.h>
#include <nibobee/delay.h>
#include <nibobee/led.h>
#include <nibobee/usart.h>
#include <nibobee/sens.h>
#include <nibobee/motpwm.h>
#include <stdlib.h>
volatile uint8_t count36kHz;
//IR-Fernbedienung PhilipsII
//diese Werte können an die Fernbedienung
//angepasst werden
#define IRPIVor 0x1020 //Vorwärts
#define IRPIRueck 0x1021 //Rückwärts
#define IRPIPlus 0x1010 //schneller
#define IRPIMinus 0x1011 //langsamer
#define IRPIStop 0x1036 //stop
#define IRPIKr 0x1034 //Kurve rechts
#define IRPIKl 0x1032 //Kurve links
#define IRPIPlay 0x1035 //frei
/*********************************************
*** Unterprogramme
*********************************************/
void SerPrint (char *data)
{
unsigned char i = 0;
while (data[i] != 0x00)
{
usart_putchar(data[i++]);
delay(3);
}
}
/***** RC5 ******** RC5 ********* RC5 ******************/
// -----------------------------------------------------------------------------
// Timing
// -----------------------------------------------------------------------------
#define IR_SAMPLES_PER_BIT 8 /*!< 8 Samples per Bit */
#define IR_SAMPLES_PER_BIT_EARLY 7 /*!< Flanke fruehestens nach 7 Samples */
#define IR_SAMPLES_PER_BIT_LATE 10 /*!< Flanke spaetestens nach 9 Samples */
#define IR_SAMPLES_PER_BIT_MIN 2 /*!< Flanke vor 3 Samples -> paket verwerfen */
#define IR_PAUSE_SAMPLES 250 /*!< Startbit ist erst nach 200 Samples ohne */
// Pegelaenderung gueltig -- eigentlich muesste
// man rund 500 Samples abwarten (50 x
// Bitzeit), doch weil der Samplezaehler ein
// Byte ist, beschraenken wir uns hier auf ein
// Minimum von 250 Samples
#define IR_PORT PORTD /*!< Port D */
#define IR_DDR DDRD /*!< DDR of Port D */
#define IR_PINR PIND /*!< Port D input */
#define IR_PIN PD0 /*!< Pin 0 */
#define RC5_COMMAND 0x103F /*!< Der Kommandobereich */
#define RC5_MASK (RC5_COMMAND)
static uint8_t RC5lastsample = 0; /*!< zuletzt gelesenes Sample */
static uint8_t RC5bittimer = 0; /*!< zaehlt die Aufrufe von ir_isr() */
static uint16_t RC5data_tmp = 0; /*!< RC5-Bitstream */
static uint8_t RC5bitcount = 0; /*!< anzahl gelesener bits */
volatile uint16_t RC5data = 0; /*!< letztes komplett gelesenes RC5-paket */
volatile uint8_t enableRC5 = 0; /*!< schaltet die RC5 Abfrage ein/aus */
/**********************************
* Interrupt Serviceroutine
* wird alle 27.7us aufgerufen
**********************************/
void IsrRC5 (void)
{
// sample lesen
uint8_t sample = 1;
//PORTB ^= (1<<PB1); //PB1=LED1 toggeln (Test)
if (enableRC5 && !(count36kHz % 8))
{
if ((IR_PINR & (1<<IR_PIN)) != 0)
{
sample = 0;
}
// bittimer erhoehen (bleibt bei 255 stehen)
if (RC5bittimer<255)
{
RC5bittimer++;
}
// flankenerkennung
if ( RC5lastsample != sample)
{
if (RC5bittimer <= IR_SAMPLES_PER_BIT_MIN)
{
// flanke kommt zu frueh: paket verwerfen
RC5bitcount=0;
}
else
{
// Startbit
if (RC5bitcount==0)
{
if ( (sample==1) && (RC5bittimer > IR_PAUSE_SAMPLES) )
{
// Startbit speichern
RC5data_tmp = 1;
RC5bitcount++;
led_set(1,1); //LED1 an
}
else
{
// error
RC5data_tmp = 0;
}
// bittimer-reset
RC5bittimer = 0;
// Bits 2..14: nur Flanken innerhalb des Bits beruecksichtigen
}
else
{
if (RC5bittimer >= IR_SAMPLES_PER_BIT_EARLY)
{
if (RC5bittimer <= IR_SAMPLES_PER_BIT_LATE)
{
// Bit speichern
RC5data_tmp = (RC5data_tmp<<1) | sample;
RC5bitcount++;
}
else
{
// zu spaet: paket verwerfen
RC5bitcount = 0;
}
// bittimer-reset
RC5bittimer = 0;
}
}
}
}
else
{
// keine flanke innerhalb bitzeit?
if (RC5bittimer > IR_SAMPLES_PER_BIT_LATE)
{
// 14 bits gelesen?
if (RC5bitcount==14)
{
RC5data = RC5data_tmp;
}
// paket verwerfen
RC5bitcount = 0;
led_set(1,0); //LED1 aus
}
}
// sample im samplepuffer ablegen
RC5lastsample = sample;
}
}
/*********************************************************
* IR-Daten lesen
* @return wert von ir_data, loescht anschliessend ir_data
*********************************************************/
uint16_t ReadRC5 (void)
{
uint16_t retvalue = RC5data;
RC5data = 0;
return retvalue;
}
/*****************************************
* Init IR-System
*****************************************/
void InitRC5 (void)
{
IR_DDR &= ~IR_PIN; // Pin auf Input
IR_PORT |= IR_PIN; // Pullup an
enableRC5 = 1;
}
/************************ RC5 Ende **************************/
/*********************************************
*** Interrupt Service Routinen
*********************************************/
ISR (TIMER2_COMP_vect)
{
//wird nicht benutzt
}
// Frequenzkorrektur für 36kHz (512-416 plus 3 Takte fürs Laden von TCNT2?)
ISR (TIMER2_OVF_vect)
{
TCNT2 = 99;
count36kHz ++;
IsrRC5(); //RC5 Decoder aufrufen
}
/*********************************************
*** Hauptprogramm
*********************************************/
int main(void)
{
static unsigned int cmd;
int16_t speed_l = 0;
int16_t speed_r = 0;
//Test
//char text[7];
motpwm_init();
led_init();
sens_init();
InitRC5();
//usart_enable();
//UCSRB = _BV(RXCIE) + _BV(UDRIE) + _BV(RXEN) + _BV(TXEN);
UCSRB = _BV(TXEN); //Nur Sender TxD aktivieren
usart_setbaudrate(2400);
// Setup Timer2
TCCR2 = (1 << WGM20)|(1 << CS20); // PhaseCorrect-PWM, no prescaling, no OC2-Pin!
TCNT2 = 96; // (512-416) 36kHz @15MHz
//OCR2 = 151; // (255-(208/2)) 151 ist 50:50 Compare Match für symetrische Halbwellen
//TIMSK |= (1 << OCIE2)|(1 << TOIE2); // Comp und OVF-ISR enable, Overflow bei Bottom!
TIMSK |= (1 << TOIE2); // OVF-ISR enable, Overflow bei Bottom!
enable_interrupts();
//Test
//delay(200); // wait4programmer
//SerPrint("\n\r\n*** Nibobee mit RC5 ***");
led_set(0,1);
delay(2000); // wait4programmer
//Test
//SerPrint("\n\r*** Fuehler links schalten --> Start ***");
//mit Schalten von Fühler links das Programm starten
while(sens_getLeft() == 0)
{
delay(100);
PORTB ^= (1<<PB0);
} // hektisches Blinken mit LED0
led_set(0,1); //LED0 einschalten
//Test
//SerPrint("\n\r*** --> Start ***");
while(1)
{
cmd = ReadRC5();
if (cmd)
{
cmd &= RC5_MASK;
//Test
//led_set(2,1);
//itoa(cmd, text, 16);
//SerPrint(text);
switch (cmd)
{
case IRPIVor:
//Test
//SerPrint("vor\r\n");
speed_l = speed_r = 200;
break;
case IRPIRueck:
//Test
//SerPrint("zurueck\r\n");
speed_l = speed_r = -200;
break;
case IRPIPlus:
//Test
//SerPrint("schneller\r\n");
if (speed_r > 0)
{
speed_l += 50;
speed_r += 50;
if (speed_r > 1023)
speed_l = speed_r = 1023;
}
else
{
speed_l -= 50;
speed_r -= 50;
if (speed_r < -1023)
speed_l = speed_r = -1023;
}
break;
case IRPIMinus:
//Test
//SerPrint("langsamer\r\n");
if (speed_r > 0)
{
speed_l -= 50;
speed_r -= 50;
if (speed_r < 0)
speed_l = speed_r = 0;
}
else
{
speed_l += 50;
speed_r += 50;
if (speed_r > 0)
speed_l = speed_r = 0;
}
break;
case IRPIStop:
//Test
//SerPrint("stop\r\n");
speed_l = speed_r = 0;
break;
case IRPIKr:
//Test
//SerPrint("Kurve rechts\r\n");
if (speed_r > 0)
{
speed_l += 50;
speed_r -= 50;
if (speed_r < 0)
speed_l = speed_r = 0;
}
else
{
speed_l -= 50;
speed_r += 50;
if (speed_r > 0)
speed_l = speed_r = 0;
}
break;
case IRPIKl:
//Test
//SerPrint("Kurve links\r\n");
if (speed_r > 0)
{
speed_l -= 50;
speed_r += 50;
if (speed_r < 0)
speed_l = speed_r = 0;
}
else
{
speed_l += 50;
speed_r -= 50;
if (speed_r > 0)
speed_l = speed_r = 0;
}
break;
case IRPIPlay:
//Test
//SerPrint("play taste\r\n");
break;
}//end switch
motpwm_setLeft(speed_l);
motpwm_setRight(speed_r);
}//end if (cmd)
delay(100);
}
return(0);
}
Skroete
Hallo
TCNT2 += 99;
Tolle und prompte Umsetzung und vorbildliche Dokumentation. Ob meine aktuelle Fernbedienung RC5 kann werde ich damit mal testen.
Gruß
mic
Hallo,
mir ist es lieber, wenn die Bee auf dem 3. Punkt rollt anstatt rutscht und habe mir kurzerhand aus einer ausgedienten Andrückrolle eines Kassettenrekorders eine drehbare Rolle gebastelt.
Hallo
Ich habe meine alte RC 5-Dekodierung vom asuro ausgegraben. Sie liest nach dem Erkennen eines Signals stur die 14 RC5-Bits ein:
Das funktioniert dann so:Code:// nibobee mit RC5 steuern 17.1.01 mic
// RC5-Funktion aus: https://www.roboternetz.de/phpBB2/ze...=287750#287750
#define ddr_acs_led_l DDRA // Anoden der IR-LEDs links
#define port_acs_led_l PORTA
#define pin_acs_led_l (1<<PA2)
#define ddr_acs_led_r DDRA // rechts
#define port_acs_led_r PORTA
#define pin_acs_led_r (1<<PA3)
#define ddr_acs_36kHz DDRC // Kathoden der IR-LEDS mit 36kHz getaktet
#define port_acs_36kHz PORTC
#define pin_acs_36kHz (1<<PC2)
#define ddr_acs_tsop DDRC // Eingang IR-Empfänger
#define port_acs_tsop PINC // Achtung, das ist ein Eingang!
#define pin_acs_tsop (1<<PC3)
#include <nibobee/iodefs.h>
#include <nibobee/led.h>
volatile uint8_t count36kHz;
volatile uint8_t acs=0;
void Sleep(uint8_t pause);
void Msleep(uint16_t pause);
void ACSData(uint16_t *data);
void ACS_init(void);
int main(void)
{
//uint16_t data[2]; // Speicher für ACS-Werte
led_init();
ACS_init();
led_set(0,1);
Msleep(2000); // wait4programmer
led_set(0,0);
//port_acs_led_l |= pin_acs_led_l;
//while(1);
unsigned int count, temp; // Zaehler, IR-Kommando
unsigned char daten[14], ir_status; // IR-Datenspeicher, IR-Eingangspegel
while(1)
{
temp=0;
while (port_acs_tsop & pin_acs_tsop); //warten auf die Flanke des Startbits
led_set(2,1); // Alarmstufe ROT: ein Zeichen ist im Anflug
led_set(0,0);
for (count=0; count<14; count++) { // im Gesamten warten wir auf 14 RC5-Bits
// Die RC5-Bitlaenge beträgt 1,778 ms. Bei 36 Takten pro Millisekunde ergibt das 36*1,778 = 64
Sleep(48); // Information einlesen nach 3/4 der Bitlaenge
ir_status=(port_acs_tsop & pin_acs_tsop); // Pegel Speichern
if (ir_status) daten[count]='1'; else daten[count]='0'; // und merken
if (ir_status) temp |= (1 << (13-count)); // das MSB(=mostsuefikantbit) zuerst
while (ir_status == (port_acs_tsop & pin_acs_tsop)); // Bit gelesen, warten auf naechste Flanke
}
temp=temp/2 & 0xf; // Die Info steht in den Bits 1-4
led_set(2,0); // Daten gelesen
/*
#define pow1 150 // Langsame Geschwindigkeit
#define pow2 200 // Schnelle Geschwindigkeit
switch (temp) {
case 1: MotorDir(FWD,FWD); MotorSpeed(pow1,pow2); break;
case 2: MotorDir(FWD,FWD); MotorSpeed(pow2,pow2); break;
case 3: MotorDir(FWD,FWD); MotorSpeed(pow2,pow1); break;
case 4: MotorDir(BREAK,FWD); MotorSpeed(0,pow1); break;
case 5: MotorDir(BREAK,BREAK); MotorSpeed(0,0); break;
case 6: MotorDir(FWD,BREAK); MotorSpeed(pow1,0); break;
case 7: MotorDir(RWD,BREAK); MotorSpeed(pow1,0); break;
case 8: MotorDir(RWD,RWD); MotorSpeed(pow1,pow1); break;
case 9: MotorDir(BREAK,RWD); MotorSpeed(0,pow1); break;
default: MotorDir(BREAK,BREAK); MotorSpeed(0,0); break;
}
*/
while(temp--) // temp mal blinken
{
Msleep(500);
led_set(3,1);
Msleep(200);
led_set(3,0);
}
led_set(0,1);
}
return(0);
}
ISR (TIMER2_COMP_vect)
{
port_acs_36kHz ^= pin_acs_36kHz; // IR-LEDs togglen
}
// Frequenzkorrektur für 36kHz (512-416 plus 3 Takte fürs Laden von TCNT2?)
ISR (TIMER2_OVF_vect)
{
TCNT2 += 99; // += bewirkt, dass schon erfolgte Zähltakte nicht ignoriert werden!
port_acs_36kHz &= ~pin_acs_36kHz; // bei Nulldurchgang soll die IR-LED aus sein!
//port_acs_36kHz |= pin_acs_36kHz; // seltamerweise funktioniert das auch?
if(count36kHz) count36kHz--;
if(acs) acs--;
}
void Sleep(uint8_t pause) // 1/36000 Pause blockierend
{
count36kHz=pause;
while(count36kHz);
}
void Msleep(uint16_t pause) // 1/1000 Pause blockierend
{
while(pause--) Sleep(36);
}
void ACSData(uint16_t *data)
{
OCR2=253;
port_acs_led_l |= pin_acs_led_l; // ACS LED left on
while((port_acs_tsop & pin_acs_tsop) && (OCR2 > 151))
{
acs=8; // Impulse senden, acs wird in OVF-ISR runtergezählt
while(acs);
OCR2--;
}
port_acs_led_l &= ~pin_acs_led_l; // ACS LED left off
data[0]=OCR2;
while(!(port_acs_tsop & pin_acs_tsop)); // warten bis keine Echo mehr
OCR2=253;
port_acs_led_r |= pin_acs_led_r; // ACS LED right on
while((port_acs_tsop & pin_acs_tsop) && (OCR2 > 151))
{
acs=8;
while(acs);
OCR2--;
}
port_acs_led_r &= ~pin_acs_led_r; // ACS LED right off
data[1]=OCR2;
while(!(port_acs_tsop & pin_acs_tsop));
}
void ACS_init(void)
{
// Setup Timer2
TCCR2 = (1 << WGM20)|(1 << CS20); // PhaseCorrect-PWM, no prescaling, no OC2-Pin!
TCNT2 = 96; // (512-416) 36kHz @15MHz
OCR2 = 151; // (255-(208/2)) 151 ist 50:50 Compare Match für symetrische Halbwellen
TIMSK |= (1 << OCIE2)|(1 << TOIE2); // Comp und OVF-ISR enable, Overflow bei Bottum!
enable_interrupts();
ddr_acs_led_l |= pin_acs_led_l; // die Anoden der IR-LEDs
port_acs_led_l &= ~pin_acs_led_l;
ddr_acs_led_r |= pin_acs_led_r;
port_acs_led_r &= ~pin_acs_led_r;
ddr_acs_36kHz |= pin_acs_36kHz; // die Kathoden der IR-LEDs
}
Bild hier
http://www.youtube.com/watch?v=TvZ_JJk_yJE
Ich werde wohl auf AAs umrüsten, dann habe ich weniger Druck auf dem TT-Ball.
Gruß
mic
Hallo Pinsel!Zitat:
Zitat von pinsel120866
Dein "Bienchen" sieht wirklich Spitze aus!!! Da ich das genau so schön haben möchte, würde ich das gern nachbauen. Allerdings habe ich noch keinerlei Erfahrungen mit Servos :-( - das soll sich jetzt ändern! Der von Dir verwendete Servo scheint ja sehr klein zu sein und sehr gut an die Stirnseite des NIBObee zu passen. Was ist das für ein Servo, wo hast Du den her? Hast noch ein paar Tips für den Aufbau? Könntest Du den Quellcode des im Video verwendete Programms hier veröffentlichen?
Danke!
Hallo Tuxi-Halle,
freut mich, dass dir meine Erweiterung so gut gefällt. Der Aufbau ist auch einfach, weil du fertige Bauteile verwenden kannst:
1. Servo: http://www.conrad.de/goto.php?artikel=230500 auf X3 stecken (ACHTUNG vorher Plus-Minus vertauschen bzw. auf Polung achten)
2.US-Modul SRF05: http://www.shop.robotikhardware.de/s...roducts_id=133 kommt auf X2 (Leitung vorher richtig anlöten, Bedienungsanleitung genau durchlesen)
3. Halterung: Hier muss du etwas basteln.
4. Testprogramm ist angehängt.