PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : NIBObee Erweiterungen



m.a.r.v.i.n
21.11.2009, 18:42
Hallo NIBObee Fans,

in diesem Thread geht es um Erweiterungen rund um den NIBObee Roboter.

Ich mache mal den Anfang und stelle ein I2C LCD Modul vor. Das Display war eigentlich für ein anderes Projekt bestimmt, ließ sich aber recht einfach für den NIBbee anpassen.

Das Display ist ein EA DOGM163 (http://www.lcd-module.de/produkte/dog.html)-A 3x16 Zeichen Display. Angesteuert kann es über SPI oder im 4-Bit oder 8-Bit Parallelmode. Durch einen I2C Portexpander Chip PCF8574 kann es auch im 4-Bit Mode über I2C angesteuert werden. Am NIBObee liegt am Port X4 die I2C Schnittstelle und 5V Spannungsversorgung an.

http://farm3.static.flickr.com/2788/4122379136_cf8c1232f1.jpg

Weitere Bilder gibt es auf Flickr (http://www.flickr.com/photos/hmblgrmpf/sets/72157622770689906/)

Ein Video gibt es auch:
http://www.youtube.com/watch?v=gih_0ag8Mng

Fragen hierzu kann ich leider erst morgen beantworten. Dann werde ich auch Schaltpläne und den Sourcecode veröffentlichen.

m.a.r.v.i.n
24.11.2009, 21:18
Hallo,

wie versprochen (mit einiger Verspätung) Schaltplan und Sourcecode für das I2C LCD.

Schaltung:
Die Schaltung ist etwas komplexer,alssie sein müßte. Ich wollte mir aber bei dem Display alle Möglcihkeiten offenhalten, deshalb sind Anschlüsse für 4-Bit, SPI und I2C Mode vorhanden. Zudem gibt es noch ein paar Jumper um zwischen den verschiedenen Modi umschalten zu können. Es kann natürlich auch ein anderes LCD Modul verwendet werden. Die Initialisierung müßte dann angepasst werden.

Software:
Die Software besteht aus den I2C Routinen (hier wurden einfach die I2C Routinen vom Nibo2 benutzt) und den LCD Funktionen (Basierend auf der Arduino ChrystalDisplay Lib). Das ganze wurde als extra Lib gepackt und die makefiles entsprechend angepasst. Das Testbeispiel beruht auf dem NIBObee SelbstTest, erweitert um die LCD Ausgabe der Linien und Odometrie Sensoren.

Edit:
Achtung!!! Aus gegebenen Anlass eine Warnung für den Nachbau. Da das I2C LCD Modul ursprünglich für ein anderes Projekt vorgesehen war, stimmt die I2C Steckerbelegung nicht mit dem NIBObee Steckverbinder überein. VCC und GND sind vertauscht! Attachment wurde aktualisiert.

pinsel120866
25.11.2009, 07:20
Hallo m.a.r.v.i.n,

Wieder mal ein feines Projekt, das du da gemacht hast!

Würde es dir etwas ausmachen, noch eine Stückliste anzugeben? Wäre nett!

Noch eine Frage: Wie sieht der Schaltplan aus, wenn ich das Display nur via I2C (ohne SPI, Jumper, usw.) an der Bee betreiben will?

Oder anders gefragt - wenn ich die Platine lt. Schaltplan mache, welche Jumper muss ich für I2C schliessen?

Danke für die Infos.

m.a.r.v.i.n
25.11.2009, 14:31
Hallo Pinsel,

hiere zunächst mal die Stückliste als Reichelt Warenkorb (https://secure.reichelt.de/?;ACTION=20;LA=5010;AWKID=188393;PROVID=2084).

Der PCF8591 von Conrad ist ein I2C A/D Wandler. Der ist hier nicht zu gebrauchen.

Zu erwähnen wäre noch, dass 2 x 10kOhm Widerstände als I2C PullUps notwendig sind. Die habe ich auf die NIBObee Platine gepackt. In der Stückliste sind jeweils 2 SMD und 2 Kohleschicht Widerstände mit dabei.

Leider gibt es bei Reichelt zur Zeit das von mir verwendete DOGM163W nicht, deshalb steht das DOGM162W in der Stückliste. Dieses hat nur 2x16 Zeichen. Bei Verwendung eines anderen Displays ist u.U. ein anderes Backlight und damit evtl andere Vorwiderstände nötig. Einige DOGM sind z.B. ohne Backlight gar nicht verwendbar. Im Zweifelsfall hilft ein Blick ins Datenblatt (http://www.lcd-module.de/pdf/doma/dog-m.pdf).

Bei Verwendung eines anderen LCDs als das hier verwendete DOGM ist zudem ein Kontrastregler (5-10kOhm Trimmer) notwendig.

Ein ähnlicher Schaltplan ohne SPI und Jumper wurde von mir schon mal für den Asuro (http://www.asurowiki.de/pmwiki/pmwiki.php/Main/LCDErweiterung)verwendet (allerdings mit etwas anderer Belegung der Steuerleitungen).

2 Jumper müssen für den I2C Mode gesteckt werden, CSB auf GND und PSB auf 5V.

Der 3. Jumper ist für das Backlight (an/aus/Software). Ich sehe gerade, der fehlt komplett im Schaltplan. #-o

pinsel120866
25.11.2009, 16:09
Vielen Dank für die Anwort.

Wenn es dir nicht zu viele Umstände macht, poste bitte noch den aktualisierten Schaltplan.

m.a.r.v.i.n
25.11.2009, 23:01
OK, Schaltplan und obiges Attachment wurden aktualisiert.

pinsel120866
26.11.2009, 10:21
Super, danke für deine Bemühungen!

Noch eine letzte Bitte - Wie bzw wo hast du die I2C-Pullup-Widerstände angebracht? Könntest du ev. ein Foto posten?

Jetzt muss ich mir nur noch ein PCF8574P organisieren, Conrad hat die leider nicht im Sortiment und bei Reichelt brauche ich 150€, sonst versenden die nicht nach Österreich. :-k

Schönen Tag!

pinsel120866
26.11.2009, 19:14
Hallo,

ich habe mal schnell ein SRF05 Modul an X2 (Port C2) angehängt. Geht sehr einfach und läuft problemlos.

m.a.r.v.i.n
26.11.2009, 20:08
Hallo pinsel,

so sehen dieI2C PullUps bei mir aus. 2 x 10kOhm SMD Widerstände an Port X4 gegen VCC.

http://farm3.static.flickr.com/2651/4136662640_66254d352b.jpg

SRF05 ist auch nicht schlecht. Vielleicht den Sensor noch auf auf einen kleinen Servo montiert und man hätte ein Front Sonar

radbruch
27.11.2009, 19:59
Hallo

Die vielen freien Ports sind echt klasse, die AAAs dagegen eher nicht. Ein kleiner Vorgucker:

http://i2.ytimg.com/vi/uwCx0GrFykU/2.jpg (http://www.youtube.com/watch?v=uwCx0GrFykU)
http://www.youtube.com/watch?v=uwCx0GrFykU
(Orginales 8MB-AVI (http://radbruch.bplaced.net/robot/nibobee/nibobee-rotordisplay2.avi))

Schönes WE

Gruß

mic

m.a.r.v.i.n
28.11.2009, 20:38
Hallo mic,

cool, ein Rotor Display.
Und endlich mal eine sinnvolle Anwendung für die Plexiglaskuppel. Als Fingerkuppenabhackschutz :wink:

Da drängen sich mir direkt ein paar Fragen auf:
* Wie werden die LEDs mit Strom versorgt, Schleifkontakte oder eigene Stromversorgung die mitrotiert?
* gibt es eine Datenschnittstelle zur NIBObee über IR oder so etwas?
* Wie werden die LEDs mit dem Motor synchronisiert?

radbruch
28.11.2009, 21:26
Hallo

Jepp, das soll ein Rotordisplay werden. Das wollte ich schon immer mal bauen:) Die Grundlagen hatte ich mir schon erarbeitet (Laser-Projektor (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=38361), Charlieplexing (https://www.roboternetz.de/phpBB2/viewtopic.php?p=405188#405188)) und nun möchte ich das mit dem schwenkbaren Sharp kombinieren: http://www.youtube.com/watch?v=mR2mYKt9X94

Auf dem Rotor befinden sich nur die zwölf LEDs mit ihren Vorwiderständen und ein Auswuchtgewicht. Über vier Schleifringe (die Herstellung ist geheim weil peinlich) sind sie direkt mit den Kontrollerpins verbunden. Eine (IR-)Verbindung zum PC gibt es im Moment nur von der Biene zum PC, eine Synchronikation mit der Rotorlage findet noch nicht statt. Das ist aber alles in Planung ;)

Gruß

mic

m.a.r.v.i.n
29.11.2009, 23:36
Hallo NIBObee Fans,

der Speicher des ATmega16 könnte bei größeren Programmen schonmal eng werden.Klar könnte man ohne weitere auch einen ATmega32 verwenden, der ist Pin und Sourcecode kompatibel.

Es gibt aber auch die moderneren Prozessoren wiedem ATmega164, 324, 644. Diese sind zwar pin, aber nicht ganz Sourcecode kompatibel. Die Änderungen an der NIBObee Lib halten sich aber in Grenzen.

Anbei sind die geänderten Files beigefügt, damit man die NIBObee Lib auch mit den ATmegaxx4 Prozessoren verwenden kann. Ausprobiert habe ich das ganze mit einem ATmega644.

Zum Übersetzen der Lib oder eines Programmes kann man einfach ein anderes Device angeben:

make DEVICE=atmega644

Edit: Dateianhang wurde aktualisiert. Jetzt wird auch der ATmega644p unterstützt.

oberallgeier
30.11.2009, 10:10
... der Speicher des ATmega16 könnte bei größeren Programmen schonmal eng werden ...Das hatten ja die bei nicai auch so gesehen (http://www.nicai-systems.de/nibobee_daten.html) ;-) .

pinsel120866
07.12.2009, 12:42
Hallo m.a.r.v.i.n,

ich habe versucht deine I2C-Lib in die LIB der NIBOBee einzubinden und kriege beim Übersetzen eine Latte von Fehlern:

Build started 7.12.2009 at 12:39:52
avr-gcc -mmcu=atmega16 NibobeeTest.o -L"C:\Program Files\NIBObeeLib\lib" -lnibobee_line -lnibobee_utils -lnibobee_base -o NibobeeTest.elf
NibobeeTest.o: In function `print_hex':
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:38: undefined reference to `usart_putchar'
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:39: undefined reference to `usart_putchar'
NibobeeTest.o: In function `main':
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:47: undefined reference to `usart_setbaudrate'
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:48: undefined reference to `usart_enable'
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:54: undefined reference to `i2c_init'
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:55: undefined reference to `lcd_init'
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:56: undefined reference to `lcd_setBacklight'
NibobeeTest.o: In function `usart_txempty':
C:\Users\HP\Documents\NibobeeTest\..\..\..\..\Prog ram Files\NIBObeeLib\include/nibobee/usart.h:102: undefined reference to `usart_txbuf_begin'
C:\Users\HP\Documents\NibobeeTest\..\..\..\..\Prog ram Files\NIBObeeLib\include/nibobee/usart.h:102: undefined reference to `usart_txbuf_end'
NibobeeTest.o: In function `main':
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:97: undefined reference to `usart_putchar'
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:99: undefined reference to `usart_putchar'
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:101: undefined reference to `usart_putchar'
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:102: undefined reference to `usart_putchar'
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:135: undefined reference to `lcd_setCursor'
C:\Users\HP\Documents\NibobeeTest\default/../NibobeeTest.c:140: undefined reference to `lcd_setCursor'
make: *** [NibobeeTest.elf] Error 1
Build failed with 15 errors and 0 warnings...


Was habe ich vergessen?

m.a.r.v.i.n
07.12.2009, 13:19
Hallo Pinsel,

Die Libs nibobee_usart und nibobee_i2c fehlen im Makefile, bzw. werden nicht mitgelinkt. Schau mal in der NIBObee Tutorial (http://download.nicai-systems.com/nibo/Tutorial_NIBObee_20091123.pdf) nach, wie Libs unter AVRStudio zu einem Projekt hinzugefügt werden (Seite 16).

pinsel120866
07.12.2009, 17:32
Vielen Dank m.a.r.v.i.n, jetzt hat es geklappt.

Noch eine Frage zur Ausgabe der Daten via RS232:

Beim Übersetzen von folgendem (Codeschnipsel):

lcd_setCursor(0,1);
printf("L: %3x %3x %3x ", rval,cval,lval);
writeString("Liniensensoren: ");
writeInteger(rval);
writeInteger(cval);
writeInteger(lval);

odoL += odometry_getLeft(1);
odoR += odometry_getRight(1);
lcd_setCursor(0,2);
printf("O: %4d %4d", odoR,odoL);
writeString("Odometriesensoren: ");
writeInteger(odoR);
writeInteger(odoL);

_delay_ms(500);

schimpft er mit:

Build started 7.12.2009 at 17:24:18
avr-gcc -I"C:\Users\HP\Documents\NibobeeTest\..\..\..\..\Prog ram Files\NIBObeeLib\include" -mmcu=atmega16 -Wall -gdwarf-2 -std=gnu99 -D_NIBOBEE_ -DF_CPU=15000000UL -Os -fsigned-char -MD -MP -MT NibobeeTest.o -MF dep/NibobeeTest.o.d -c ../Nib
obeeTest.c

../NibobeeTest.c: In function 'writeInteger':
../NibobeeTest.c:53: warning: implicit declaration of function 'itoa'
../NibobeeTest.c: In function 'main':
../NibobeeTest.c:220: error: too few arguments to function 'writeInteger'
../NibobeeTest.c:221: error: too few arguments to function 'writeInteger'
../NibobeeTest.c:222: error: too few arguments to function 'writeInteger'
../NibobeeTest.c:229: error: too few arguments to function 'writeInteger'
../NibobeeTest.c:230: error: too few arguments to function 'writeInteger'
../NibobeeTest.c:112: warning: unused variable 'speed_r'
../NibobeeTest.c:111: warning: unused variable 'speed_l'
make: *** [NibobeeTest.o] Error 1
Build failed with 5 errors and 3 warnings...


Was ist hier wieder falsch von mir?

P.S. Danke an m.a.r.v.i.n! Anbei ein Foto meiner Bee mit LCD-Display

m.a.r.v.i.n
07.12.2009, 20:42
Hallo Pinsel,

sieht toll aus, deine Biene. Schön, das es doch noch noch funktioniert hat. :wink:

Zu den Fehlermeldungen. Der Funktion writeInteger werden zuwenig Parameter übergeben. Wo ist denn diese Funktion? Zur NIBObee lib gehört sie zumindest nicht.

pinsel120866
07.12.2009, 21:43
OK, danke.

Diese Funktionen (von Radbruch übernommen) stehen zur Auswahl:

void writeChar(uint8_t data )
{
while ( !( UCSRA & (1<<UDRE)) );
UDR = data;
}
void writeString(char *string)
{
while(*string)
writeChar(*string++);
}

void writeInteger(int16_t number, uint8_t base)
{
char buffer[17];
itoa(number, &buffer[0], base);
writeString(&buffer[0]);
}


Welcher Parameter fehlt hier?

radbruch
07.12.2009, 21:57
writeInteger(odoR);
writeInteger(odoL);

Die Zahlenbasis fehlt. Das writeInteger() erwartet als zweiten Parameter die Basis des Zahlensystems: 2, 10, 16...

Diese drei Funktionen reichen für eine einfache blockierende Kommunikation. Die nibobee-Lib bietet zusätzlich noch gepuffertes Senden und Empfangen, das ist aber entsprechend kompliziert...

btw. habe ich nun eine bessere Anwendung des asuro-IR-Transceivers in Betrieb:
https://www.roboternetz.de/phpBB2/viewtopic.php?p=473845#473845

Gruß

mic

pinsel120866
08.12.2009, 17:56
Hallo Zusammen,

ich möchte ans Bee-Port X3 einen Miniservo anschliessen, um ein Front-Sonar mit meinem SRF05 zu machen.

Dazu müsste es doch möglich sein, den Servostecker direkt anzustecken, natürlich muss ich vorher plus und minus beim Servostecker vertauschen - was meint ihr?

Bitte kurz um Hilfe ob das geht, ich will meinen einzigen Miniservo nicht schrotten... 8-[

Virus
08.12.2009, 18:33
welchen stecker hat der miniservo? JR oder FUTABA?

für experimente gibst beim großen C einen miniservo für 5euro oder so. Da ist der Verlust verschmerzbar :^)

radbruch
08.12.2009, 18:45
Hallo

Wirklich zufällig hängt das Servo das meinen Sharp schwenkt auch an X3 :)


// Nibobee Motor- und Odometrytest 18.11.09 mic

#include <nibobee/iodefs.h>
#include <nibobee/delay.h>
#include <nibobee/analog.h>
#include <nibobee/odometry.h>
#include <nibobee/led.h>
#include <nibobee/sens.h>
#include <stdlib.h> // C standard functions (e.g. itoa...)
uint16_t nibobee_initialization; // ???

#define LineLEDs_on PORTB &=~(1<<PB4)
#define LineLEDs_off PORTB |= (1<<PB4)
#define DIR_R 7
#define DIR_L 6
#define PWM_L 5
#define PWM_R 4

void ir_init(void);
void writeChar(uint8_t data );
void writeString(char *string);
void writeInteger(int16_t number, uint8_t base);
void motorDir(uint8_t dir_left, uint8_t dir_right);
void motorSpeed(uint8_t speed_left, uint8_t speed_right);

uint8_t p=0, servo=0;

int main(void) {

uint8_t c;
uint16_t echo[16];
uint8_t servopos=0;
int8_t schwenk=1;


led_init();
sens_init();
analog_init();
odometry_init();
odometry_reset();
ir_init();
led_set(LED_L_YE,1);


PORTD |=(1<<PWM_L)|(1<<PWM_R); // Pullups einschalten damit der Pegel high bleibt
DDRD |=(1<<DIR_L)|(1<<DIR_R)|(1<<PWM_L)|(1<<PWM_R);

writeString("\n\n\r");
writeString("Sharp-Test mit Schwenkservo\n\r");
writeString("21.11.09 mic\n\n\r");
delay(2000);
servo=108;

while(1)
{
servo=35+servopos*10;
delay(100);
echo[14-servopos]=analog_getValue(ANALOG_EXT3);
if((servopos==0) || (servopos==14))
{
for(c=0; c<15; c++)
{
writeInteger(echo[c], 10);
writeString("-");
}
writeString("\n\r");
}
servopos+=schwenk;
if(!servopos) schwenk=1; else if(servopos==14) schwenk=-1;
}
return 0;
}

// Die ISR erzeugt die 36kHz-Trägerfrequenz und "lauscht" gleichzeitig am TXD-Pin
// um die seriellen Daten auf die Trägerfrequenz zu mischen. Zusätzlich erzeugt
// sie die Impulse für das Servo an PC3. Letztlich dekrementiert sie p solange
// bis es 0 ist

ISR (TIMER2_COMP_vect)
{
static uint8_t status=0;
if(PIND & 2) // Der TSOP invertiert die empfangenen Daten!
LineLEDs_off;
else
if(status) {LineLEDs_on; status=0;} else {LineLEDs_off; status=1;}

static uint16_t count=1;
if(count>servo) PORTC &= ~(1<<PC3); else PORTC |= (1<<PC3);
if(count<1440) count++; else {count=1; if(p) p--;};
}
void ir_init(void)
{
#define UBRR_BAUD_2400 390 // Baudrate auf 2400 setzen
UBRRH = UBRR_BAUD_2400 >> 8;
UBRRL = (uint8_t) UBRR_BAUD_2400;

UCSRC = (1<<URSEL)|(0<<USBS)|(3<<UCSZ0); // 8, none, 1
UCSRB |= (1<<TXEN); // Senden enablen

TCCR2 = (1 << WGM21) | (1 << CS20); // CTC-Mode, no prescaling, no OC2-PIN!
OCR2 = 208; // 36kHz @15MHz
TIMSK |= (1 << OCIE2);

DDRB |= (1<<PB4); // LineLED ist ein Ausgang
LineLEDs_on; // LineLED schaltet gegen GND!
DDRD |= 2; // TXD Ausgang und low
PORTD &= ~2;
sei();
}
void writeChar(uint8_t data ) // Code aus ATMega16-Datenblatt
{
while ( !( UCSRA & (1<<UDRE)) );
UDR = data;
}
void writeString(char *string)
{
while(*string)
writeChar(*string++);
}
void writeInteger(int16_t number, uint8_t base)
{
char buffer[17];
itoa(number, &buffer[0], base);
writeString(&buffer[0]);
}
void motorDir(uint8_t dir_left, uint8_t dir_right)
{
if(dir_left) PORTD |= (1<<DIR_L); else PORTD &= ~(1<<DIR_L);
if(dir_right) PORTD &= ~(1<<DIR_R); else PORTD |= (1<<DIR_R);
}
void motorSpeed(uint8_t speed_left, uint8_t speed_right)
{
if(speed_left) PORTD &= ~(1<<PWM_L); else PORTD |= (1<<PWM_L);
if(speed_right) PORTD &= ~(1<<PWM_R); else PORTD |= (1<<PWM_R);
}
(ungeputzer Arbeitscode)

Ein 36kHz-Takt wird mit Timer2 erzeugt:

TCCR2 = (1 << WGM21) | (1 << CS20); // CTC-Mode, no prescaling, no OC2-PIN!
OCR2 = 208; // 36kHz @15MHz
TIMSK |= (1 << OCIE2);


In der ISR wird dann das Signal ausgegeben:

ISR (TIMER2_COMP_vect)
{
...
static uint16_t count=1;
if(count>servo) PORTC &= ~(1<<PC3); else PORTC |= (1<<PC3);
if(count<1440) count++; else {count=1; if(p) p--;};
}


Und schließlich kann man dann die Servoposition in der Variablen servo übergeben. Mitte ist ca. 108, 0 bedeutet kein Impuls senden. Das sollte direkt so funktionieren, mein Sharp hängt auch an X3 ;)

http://i4.ytimg.com/vi/G836SWiYA_c/3.jpg (http://www.youtube.com/watch?v=G836SWiYA_c)
http://www.youtube.com/watch?v=G836SWiYA_c

Servostecker mußte man für ADC0/1 beim RP6 auch "Umbauen".
Warum die Hersteller das Servopinout nicht übernehmen ist mir schleierhaft:
http://radbruch.roboterbastler.de/rp6/greifer2/servoanschluss1_klein.jpg (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=356247#356247)

Gruß

mic

pinsel120866
08.12.2009, 19:20
@Virus: Es ist genau so ein Billigservo vom C, ein Modelcraft ES-05 JR

@mic: Demnach hast du die PINS2 (=PC3), PIN3 (GND) und PIN4(VCC) verwendet, wenn ich das richtig im Code gelesen habe. Poste bitte mal ein Foto oder Video deiner Erweiterung, sieht sicher cool aus.

EDIT: Habe mir gerade das Video angesehen - du hast sicher mittlerweile ein Monopol auf die gelben Zahnräder vom C?
:-)

radbruch
08.12.2009, 20:07
Es sind immer die selben gelben Zahnräder ;)

Das Miniservo und der Sharp stecken bei meiner bee direkt im X3:
http://radbruch.bplaced.net/robot/nibobee/sharpundservoanx3_2_klein.jpg (http://radbruch.bplaced.net/robot/nibobee/sharpundservoanx3_2.jpg) http://radbruch.bplaced.net/robot/nibobee/sharpundservoanx3_0_klein.jpg (http://radbruch.bplaced.net/robot/nibobee/sharpundservoanx3_0.jpg) http://radbruch.bplaced.net/robot/nibobee/sharpundservoanx3_1_klein.jpg (http://radbruch.bplaced.net/robot/nibobee/sharpundservoanx3_1.jpg)

Gruß

mic

pinsel120866
08.12.2009, 20:41
Könntet ihr euch bitte mal meinen Servocode ansehen?



#include <nibobee/iodefs.h>
#include <nibobee/delay.h>
#include <nibobee/analog.h>
#include <stdlib.h>

unsigned char i, servo_stellzeit;

void servo(unsigned char winkel)
{
unsigned int count=0;
do
{
count++;

if(winkel)
{
PORTC |= (1 << PC3);
delay(winkel);
}
PORTC &= ~(1 << PC3);

delay(255-winkel);
}
while (count<servo_stellzeit);
}

int main(void)
{

analog_init();

while(1)
{
servo_stellzeit=150;
delay(100);
for (i=15; i<85; i+=2) servo(i);
delay(100);
for (i=75; i>17; i-=2) servo(i);
delay(100);
}
return 0;
}

Der Servo zuckt bei diesem Programm in 1 Grad-Schritten, sollte aber zwischen zwei Positionen hin- und herdrehen...

radbruch
08.12.2009, 21:27
Hallo

Ein delay() dauert ca. 1 ms und ist damit zu grob für eine vernünftige Servoansteuerung:

#include <nibobee/iodefs.h>
#include <nibobee/delay.h>
#include <nibobee/analog.h>
#include <stdlib.h>

unsigned int winkel, nibobee_initialization;
unsigned char i;

int main(void)
{

analog_init(); // wollen wir später wirklich alle ADC-Kanäle einlesen?
delay(3000); // wait4programmer ;)

while(1)
{
for(i=0; i<50; i++) // ein Zyklus dauert ca. 20 ms
{
PORTC |= (1 << PC3); // Implus senden
delay(1);
PORTC &= ~(1 << PC3); // Pause senden
delay(19);
}
for(i=0; i<50; i++)
{
PORTC |= (1 << PC3);
delay(2);
PORTC &= ~(1 << PC3);
delay(19);
}
for(i=0; i<100; i++)
{
winkel=1000;
while(winkel--) PORTC |= (1 << PC3); // Impulslänge als Zählschleife
PORTC &= ~(1 << PC3);
delay(19);
}
}
return 0;
}
Wenn es blockierend sein darf, würden Zählschleifen funktionieren :)

gruß

mic

pinsel120866
08.12.2009, 22:03
Wenn ich deine Code flashe, passiert gar nichts...

Unter BASCOM wäre es viel einfacher:

'Verwendeter Compiler Bascom V 1.11.9.3
'
'Aufgabe:
'Extremwerte Modelcraft Top Line Mini Servo ES-05 JR
'Autor: Pinsel120866
'################################################# ##

$regfile = "m16def.dat"
$crystal = 15000000
$baud = 9600
$hwstack = 32
$framesize = 32
$swstack = 32

Config Servos = 1 , Servo1 = Portc.3 , Reload = 10
Config Portc = Output
Enable Interrupts


Do
Servo(1) = 44
Waitms 1000
Servo(1) = 113
Waitms 1000
Servo(1) = 182
Waitms 1000

Loop
End
Warum bringe ich dies unter "Zäh" nicht her?

radbruch
08.12.2009, 22:52
Mein Servo steuert mit dem Programm drei Positionen an. Das Programm startet mit einer langen Pause (ca. 3 Sek.):

pinsel120866
10.12.2009, 15:55
Hallo,

meine nächste Erweiterung ist ein Sonar, also im meinem Fall das SRF05 auf einem Servo montiert.

Ein Video dazu gibt es auch: http://www.youtube.com/watch?v=jQpR5Hr82Vk

pinsel120866
23.12.2009, 09:50
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

pinsel120866
23.12.2009, 14:53
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.

radbruch
23.12.2009, 15:18
Ja, das funktioniert wunderbar:

http://radbruch.roboterbastler.de/nibobee/erweiterung_x4_klein.jpg (http://radbruch.roboterbastler.de/nibobee/erweiterung_x4.jpg) http://radbruch.bplaced.net/robot/nibobee/sharpundservoanx3_2_klein.jpg (http://radbruch.bplaced.net/robot/nibobee/sharpundservoanx3_2.jpg)
(Anklicken für vergrössertes Katzenhaar;)

Das ist die Prozessorseite der Widerstände, an X1 funtioniert es genauso. So habe ich mein Rotordisplay angeschlossen;)

Gruß

mic

pinsel120866
23.12.2009, 16:07
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.

Skroete
16.01.2010, 18:19
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.



/*********************************************
*** 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);
}





Viel Spass beim Ausprobieren.
Skroete

radbruch
16.01.2010, 19:15
Hallo

TCNT2 += 99;

Tolle und prompte Umsetzung und vorbildliche Dokumentation. Ob meine aktuelle Fernbedienung RC5 kann werde ich damit mal testen.

Gruß

mic

pinsel120866
16.01.2010, 19:42
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.

radbruch
17.01.2010, 23:02
Hallo

Ich habe meine alte RC 5-Dekodierung (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=287750#287750) vom asuro ausgegraben. Sie liest nach dem Erkennen eines Signals stur die 14 RC5-Bits ein:

// nibobee mit RC5 steuern 17.1.01 mic

// RC5-Funktion aus: https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=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
}

Das funktioniert dann so:
http://i1.ytimg.com/vi/TvZ_JJk_yJE/default.jpg (http://www.youtube.com/watch?v=TvZ_JJk_yJE)
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

Tuxi-Halle
18.01.2010, 15:40
Hallo,
meine nächste Erweiterung ist ein Sonar, also im meinem Fall das SRF05 auf einem Servo montiert.
Ein Video dazu gibt es auch...
Hallo Pinsel!
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!

pinsel120866
18.01.2010, 18:31
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/shop/catalog/product_info.php?cPath=71&products_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.

pinsel120866
18.01.2010, 18:45
Nachtrag:

Ich habe die Räder gegen ASURO-Räder ausgetauscht, der Grip ist deutlich besser.

Tuxi-Halle
19.01.2010, 02:28
Anbei sind die geänderten Files beigefügt, damit man die NIBObee Lib auch mit den ATmegaxx4 Prozessoren verwenden kann. Ausprobiert habe ich das ganze mit einem ATmega644.

Zum Übersetzen der Lib oder eines Programmes kann man einfach ein anderes Device angeben:

make DEVICE=atmega644

Hallo m.a.r.v.i.n,
den ATmega644 hatte ich gleich mit dem NIBObee mitbestellt, weil ich dachte, daß es nicht übel wäre, für 5€ 4x soviel Speicher zu haben wie das Original.
Heute wollte ich nun auf den 644 umsteigen und hab es so gemacht, wie oben beschrieben: Deine Dateien in den /src - Zweig kopiert, die libs wie beschrieben neu gebaut, die Projekte auf den 644 angepasst genau wie den Aufruf von avrdude. Damit lassen sich die Programme auch übersetzen und auf den NIBObee laden.
So weit - so gut. Dann gehen die Problem aber los: Die Programme laufen wesentlich laaaaaaaangsamer, als mit dem ATmega 16 - handgestoppt so um den Faktor 20. Die Liniensensoren funktionieren, lcd-Anzeige klappt, aber die linken Fühler funktionieren nicht mehr - die rechten Fühler dagegen schon. Alles wie gesagt wesentlich langsamer.
Wenn ich den ATmega16 wieder einbaue und die entsprechenden Einstellung wiederherstelle, dann klappt alles normal.
Hast Du eine Idee, was da falsch laufen könnte? Habe ich etwas vergessen? Ist der 644 defekt? Bin etwas ratlos...

Tuxi-Halle
19.01.2010, 02:44
Hallo pinsel,


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/shop/catalog/product_info.php?cPath=71&products_id=133 kommt auf X2 (Leitung vorher richtig anlöten, Bedienungsanleitung genau durchlesen)

Prima - danke! Habe mir mal die SRF-Sensoren angesehen. Ich überlege, ob ich gleich den SRF10 nehme - den gibt es gleich mit passendem Montage-Winkel. Kleiner ist er auch noch und läßt sich wegen i2c-Ansteuerung leicht programmieren - der NIBObee hat ja alles, was man dafür braucht ;-) Spricht außer dem Preis etwas gegen dieses Teil?


4. Testprogramm ist angehängt.

Könnte man sich Deinen Quellcode mal ansehen?

pinsel120866
19.01.2010, 19:31
Hi Tuxi,

natürlich kannst du das SFH10 nehmen.

Mein Testprogrammcode sieht so aus:

'Verwendeter Compiler Bascom V 1.11.9.3
'
'Aufgabe:
'Entfernung wird gemessen und in Zentimetern über
'RS232 ausgegeben
'Autor: Pinsel120866
'################################################# ##

$regfile = "m16def.dat"
$crystal = 15000000
$baud = 9600
$hwstack = 32
$framesize = 32
$swstack = 32
Dim Zeitmessung As Word
Dim Entfernung As Word
Wait 1
Print "**** SRF05 mit NIBOBee *****"
Print "Entfernung in cm anzeigen"
Print " "
Config Pinc.2 = Output
Do
Portc.2 = 0
Pulseout Portc , 2 , 40
Pulsein Zeitmessung , Pinc , 2 , 1
Zeitmessung = Zeitmessung * 10
Entfernung = Zeitmessung / 58
Print "Entfernung: " ; Entfernung ; " cm"
Wait 1
Loop

m.a.r.v.i.n
19.01.2010, 20:54
Hallo m.a.r.v.i.n,
den ATmega644 hatte ich gleich mit dem NIBObee mitbestellt, weil ich dachte, daß es nicht übel wäre, für 5€ 4x soviel Speicher zu haben wie das Original.
Heute wollte ich nun auf den 644 umsteigen und hab es so gemacht, wie oben beschrieben: Deine Dateien in den /src - Zweig kopiert, die libs wie beschrieben neu gebaut, die Projekte auf den 644 angepasst genau wie den Aufruf von avrdude. Damit lassen sich die Programme auch übersetzen und auf den NIBObee laden.
So weit - so gut. Dann gehen die Problem aber los: Die Programme laufen wesentlich laaaaaaaangsamer, als mit dem ATmega 16 - handgestoppt so um den Faktor 20. Die Liniensensoren funktionieren, lcd-Anzeige klappt, aber die linken Fühler funktionieren nicht mehr - die rechten Fühler dagegen schon. Alles wie gesagt wesentlich langsamer.
Wenn ich den ATmega16 wieder einbaue und die entsprechenden Einstellung wiederherstelle, dann klappt alles normal.
Hast Du eine Idee, was da falsch laufen könnte? Habe ich etwas vergessen? Ist der 644 defekt? Bin etwas ratlos...

Hallo Tuxi-Halle,

der Prozessor ist sicher nicht defekt. Die Fuse Bits stimmen nur nicht. Ein fabrikfrischer Prozessor läuft mit internem Takt mit 1MHz.
Hier sind 2 Screenshots zur Verwendung des myAVR Progtool (http://shop.myavr.de/index.php?sp=download.sp.php) mit der NIBObee.
1. Zeigt die Einstellung der Programmer Hardware. Unter Sonstiges usbasp und als Schnittstelle usb auswählen.
http://www.flickr.com/photos/hmblgrmpf/4224673867/

2. Zeigt die Fuses Einstellungen des Original NIBObee Controller. In die Fuse & Lock-Bits Einstellung gelangt man unter Brennen, bearbeiten.
http://www.flickr.com/photos/hmblgrmpf/4224673787/

Tuxi-Halle
19.01.2010, 21:17
Hallo pinsel,
danke für die schnelle Antwort!


natürlich kannst du das SFH10 nehmen.

Schon bestellt ;-) Leider ist das Ding samt Befestigungswinkel teurer als der ganze NIBObee :-( Aber was solls...


Mein Testprogrammcode sieht so aus:
'Verwendeter Compiler Bascom V 1.11.9.3
...

Bascom kenne ich zwar nicht, aber man versteht auch so, was gemacht wird ;-)
Ich meinte aber eher die Ansteuerung des Servos, weil ich das noch nie gemacht habe. Die eigentliche Messerei muß ich mit dem SFH10 sowieso anders machen. Den Conrad-Servo hab ich mir angeschaut - wirklich schön klein und preiswert das Ding! Braucht man dafür extra Treiberschaltkreise oder wie geht das? Kannst Du dafür mal ein Code-Schnipsel posten?
Danke!

radbruch
19.01.2010, 21:56
Hier sind 2 Screenshots zur Verwendung des myAVR Progtool mit der NIBObee. Wiewas? So einfach ist das? Und funktioniert wunderbar. *dankedankedanke*

Tuxi-Halle
19.01.2010, 22:21
Hallo m.a.r.v.i.n,


Die Fuse Bits stimmen nur nicht. Ein fabrikfrischer Prozessor läuft mit internem Takt mit 1MHz.
Danke! Daran wird es wohl liegen.
Ich hab mal die fuses des ATmega16 ausgelesen:
http://img686.imageshack.us/img686/7575/avrdudeatmega16.jpg

Und dann die des ATmega644:
http://img42.imageshack.us/img42/1429/avrdudeatmega644.jpg

Wenn ich Dich recht verstanden habe, dann muß ich wohl die Werte des 16ers aus dem NIBObee in den 644er schreiben, also "hfuse=D1" und "lfuse=EF". Was ist aber mit den "efuse", die es offenbar beim 16er gar nicht gibt? Einfach so lassen ("FF")? Habe leider nix wirklich Erhellendes "ergoogeln" können :-(

Tuxi-Halle
19.01.2010, 22:45
Hallo m.a.r.v.i.n,
habs einfach mal so gemacht (efuse="FF", hfuse="D1", lfuse="EF") - funktioniert :-)
Nochmals vielen Dank!
btw.:kennst Du ein vernünftiges Tutorial zum Thema "fuses"?

pinsel120866
21.01.2010, 18:46
Hi tuxi,

ich gebe dir mal den gesamten C-Code meines Greifer-Asuros:
Den Ablauf siehst du unter http://www.youtube.com/watch?v=wQY2dqMZH3Y


/************************************************** **********************

Test Programm fuer den ASURO IR-Adapter mit 2 Sende-LEDs

Der ASURO ermittelt ueber den nach vorne gerichteten
Infrarot Empfänger und Sender über die Reflektion des
Lichtes an einem Objekt ungefaehr dessen Abstand.

Es wird je nach Abstand der Rechten SendeLED die Status-LED in
verschiedenen Farben eingeschaltet. Wir der Abstand kleiner als 17 cm
werden die Motoren mit verschiedenen Geschwindigkeiten eingeschaltet.

Zur Compilierung dieses Programmes wird asuro.c und asuro.h aus
der ASURO Lib 2.6.1 benötigt. Die ASURO Lib ist auf sourceforge
zu finden.

************************************************** **********************

Hardware: ASURO Roboter

prozessor: ATMEGA32
clock: 16MHz Crystal

************************************************** **************************

date authors version comment
====== ====================== ======= ==============================
Jan.08 (ch) robo.fr V1.0 First implemetation
Apr.08 (kk) pinsel V1.1 Erweiterung auf 2 SendeLEDs

Versions:

V1.0
- first version
V2.0
- Auf 2 SendeLEDs erweitert

************************************************** *************************/
/************************************************** *************************
*
* (c) 2007 robo.fr , christoph(at)roboterclub-freiburg.de
*
************************************************** *************************
* 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 version 2 of the License, *
* If you extend the program please maintain the list of authors. *
* If you want to use this software for commercial purposes and you *
* don't want to make it open source, please contact the authors for *
* licensing. *
************************************************** *************************/

#include "asuro.h"
#include <stdlib.h>

unsigned char i, servo_stellzeit;

/************************************************** ***********************

uint8_t objekt_sichtbar(uint8_t abstand)

Ist ein Objekt in der Entfernung kleiner oder gleich
dem Eingangsparameter "abstand" erkennbar?

objekt_sichtbar(7) liefert TRUE zurück, falls überhaupt
ein Object detektierbar.

abstand:
0: 5cm
1: 7cm
2: 13cm
3: 15cm
4: 16cm
5: 17cm
6: 18cm
7: 22cm

( Testobjekt: Joghurtecher, Umgebungsbeleuchtung: Zimmer )

return: TRUE falls Objekt gefunden
FALSE wenn nicht

Zeitbedarf: 5ms

author: robo.fr, christoph ( ät ) roboterclub-freiburg.de
date: 2008

************************************************** ***********************/
uint8_t objekt_sichtbar_rechts(uint8_t distance_r)
{
uint16_t j,z;

PORTB |= (1 << PB6); // PB6 auf HIGH (LED ausschalten)
DDRD |= (1 << DDD1); // Port D1 als Ausgang
PORTD &= ~(1 << PD1); // PD1 auf LOW

OCR2 = 254-distance_r; // wenn OCR2=0xFE dann Objekt sehr nahe
z=0;
for(j=0;j<30;j++) // loop time: 5ms
{
if (PIND & (1 << PD0))z++;
Sleep(6); // 6*Sleep(6)=1ms
}
if (z>=29) return FALSE; // Objekt nicht gefunden
else return TRUE;
}

uint8_t objekt_sichtbar_links(uint8_t distance_l)
{
uint16_t i,y;

PORTD |= (1 << PD1); // PD1 auf HIGH (LED ausschalten)
DDRB |= (1 << DDB6); // Port B6 als Ausgang
PORTB &= ~(1 << PB6); // PB6 auf LOW

OCR2 = 254-distance_l; // wenn OCR2=0xFE dann Objekt sehr nahe
y=0;
for(i=0;i<30;i++) // loop time: 5ms
{
if (PIND & (1 << PD0))y++;
Sleep(6); // 6*Sleep(6)=1ms
}
if (y>=29) return FALSE; // Objekt nicht gefunden
else return TRUE;
}
/************************************************** ***********************

uint8_t abstand()

Abstandsermittelung über IR-Sendiode / IR-Empfänger.
0:kleinster Abstand
7:größter Abstand
255: kein Objekt

Zeitbedarf: 5ms*9=45ms

author: robo.fr, christoph ( ät ) roboterclub-freiburg.de
date: 2008

************************************************** ***********************/
uint8_t abstand_rechts()
{
uint8_t k,n;

k=255;
for(n=0;n<4;n++)
{
if (!objekt_sichtbar_rechts(n)) k=n; // solange kein Objekt, Distanz erhoehen
}
return k;
}

uint8_t abstand_links()
{
uint8_t l,m;

l=255;
for(m=0;m<4;m++)
{
if (!objekt_sichtbar_links(m)) l=m; // solange kein Objekt, Distanz erhoehen
}
return l;
}

//************************************************** **********************
void RaceStart(void) // blink until any switch is pressed,
{ // then wait until switch is released
uint8_t t1, t2;
unsigned int col=OFF;


while (1) // blinking StatusLED until any switch is pressed
{
t1 = PollSwitch();
t2 = PollSwitch();
if (t1==t2)
{
if (t1)
{
break;
}
else
{
col ^= GREEN;
StatusLED(col);
}
}
Msleep(50);
}

StatusLED(OFF); // turn off StatusLED and ...
BackLED(ON,ON); // ... turn on both BackLED's

while (1) // wait until switch is released
{
t1 = PollSwitch();
t2 = PollSwitch();
if (t1==t2)
{
if (!t1)
{
break;
}
}
Msleep(50);
}

BackLED(OFF,OFF); // turn off BackLED's indication start of race
}

//************************************************** **********************
void servo(unsigned char winkel)
{
unsigned int count=0;
do
{
count++;

if(winkel)
{
PORTB |= (1 << PB0);
Sleep(winkel);
}
PORTB &= ~(1 << PB0);

Sleep(255-winkel);
}
while (count<servo_stellzeit);
}


/************************************************** ***********************

Hauptprogramm

************************************************** ***********************/
int main(void)
{
uint8_t n,m;
float volt;
int proz;
unsigned int sensors[2];
DDRB |= (1 << PB0);

Init();
initLcd();

volt=2.56/1024*Batterie()*22/10;
proz=(int)(((volt)/5)*100); //so ungefähr
// Output some strings to the LCD
writeStringToLCD("*ASURO bereit*");
writeStringToLCD("Batterie: ");
writeIntegerToLCD(proz);
writeStringToLCD("%");

RaceStart();

FrontLED(OFF);
while(1)
{
n=abstand_rechts();
m=abstand_links();

if ((n!=255) || (m!=255))
{
if ((n<0) && (m<0))
{
MotorDir(RWD,RWD);
MotorSpeed(155,165);
}
else if (m>n)
{

StatusLED(RED);
BackLED(ON,ON);
servo_stellzeit=12; //Servogeschw. einstellen
MotorSpeed(10,10); //kurze Pause
Msleep(1);
MotorSpeed(BREAK,BREAK);
Msleep(500);
MotorSpeed(10,10); //kurze Pause
Msleep(1);
MotorDir(FWD,FWD); //Kleines Stück vor
MotorSpeed(110,100);
Msleep(1100);
MotorSpeed(BREAK,BREAK);
clearLCD();
writeStringToLCD("Close Gripper");
for (i=15; i<85; i+=2) servo(i); //Greifer zumachen
MotorSpeed(10,10); //Kurze Pause
Msleep(1);
MotorDir(RWD,RWD); //Kleines Stück zurück
MotorSpeed(120,120);
Msleep(500);
MotorSpeed(BREAK,BREAK);
clearLCD();
writeStringToLCD("Turn left");
MotorSpeed(135,0); //Vierteldrehung nach links
Msleep(1000);
MotorSpeed(BREAK,BREAK);
clearLCD();
writeStringToLCD("Open Gripper");
for (i=75; i>17; i-=2) servo(i); //Greifer aufmachen
MotorSpeed(10,10); //Kurze Pause
Msleep(1);
MotorDir(RWD,RWD); //Kleines Stück zurück
MotorSpeed(120,120);
Msleep(500);
MotorSpeed(BREAK,BREAK);
clearLCD();
writeStringToLCD("Turn right");
MotorSpeed(0,135); //Vierteldrehung nach rechts
Msleep(1000);
MotorSpeed(BREAK,BREAK);
MotorSpeed(10,10); //Kurze Pause
Msleep(1);
clearLCD();
writeStringToLCD("That's it!");

MotorSpeed(0,155);
BackLED(ON,OFF);
clearLCD();
IRData(sensors);
writeStringToLCD("**NACH LINKS**");
writeIntegerToLCD(sensors[0]);
writeStringToLCD("*Wert*");
writeIntegerToLCD(sensors[1]);
}
else if (n>m)
{

StatusLED(RED);
BackLED(ON,ON);
servo_stellzeit=12; //Servogeschw. einstellen
MotorSpeed(10,10); //kurze Pause
Msleep(1);
MotorSpeed(BREAK,BREAK);
Msleep(500);
MotorSpeed(10,10); //kurze Pause
Msleep(1);
MotorDir(FWD,FWD); //Kleines Stück vor
MotorSpeed(95,120);
Msleep(1100);
MotorSpeed(BREAK,BREAK);
clearLCD();
writeStringToLCD("Close Gripper");
for (i=15; i<85; i+=2) servo(i); //Greifer zumachen
MotorSpeed(10,10); //Kurze Pause
Msleep(1);
MotorDir(RWD,RWD); //Kleines Stück zurück
MotorSpeed(120,120);
Msleep(500);
MotorSpeed(BREAK,BREAK);
clearLCD();
writeStringToLCD("Turn right");
MotorSpeed(0,135); //Vierteldrehung nach links
Msleep(1000);
MotorSpeed(BREAK,BREAK);
clearLCD();
writeStringToLCD("Open Gripper");
for (i=75; i>17; i-=2) servo(i); //Greifer aufmachen
MotorSpeed(10,10); //Kurze Pause
Msleep(1);
MotorDir(RWD,RWD); //Kleines Stück zurück
MotorSpeed(120,120);
Msleep(500);
MotorSpeed(BREAK,BREAK);
clearLCD();
writeStringToLCD("Turn left");
MotorSpeed(135,0); //Vierteldrehung nach rechts
Msleep(1000);
MotorSpeed(BREAK,BREAK);
MotorSpeed(10,10); //Kurze Pause
Msleep(1);
clearLCD();
writeStringToLCD("That's it!");

MotorSpeed(155,0);
BackLED(OFF,ON);
clearLCD();
IRData(sensors);
writeStringToLCD("**NACH RECHTS**");
writeIntegerToLCD(sensors[0]);
writeStringToLCD("*Wert*");
writeIntegerToLCD(sensors[1]);
}
else
{
StatusLED(GREEN);
BackLED(ON,ON);
MotorDir(FWD,FWD);
MotorSpeed(155,165);
clearLCD();
IRData(sensors);
writeStringToLCD("***GERADEAUS***");
writeIntegerToLCD(sensors[0]);
writeStringToLCD("*Wert*");
writeIntegerToLCD(sensors[1]);
}
}
}

}


Du kannst dir sicher die Servoschnipsel rauspflücken.

m.a.r.v.i.n
21.01.2010, 22:00
Hallo m.a.r.v.i.n,
habs einfach mal so gemacht (efuse="FF", hfuse="D1", lfuse="EF") - funktioniert :-)
Nochmals vielen Dank!
btw.:kennst Du ein vernünftiges Tutorial zum Thema "fuses"?
Hallo Tuxi-Halle,
Ein Tutorial gibt es im RN-Wissen (http://www.rn-wissen.de/index.php/AVR#Die_Fusebits).

Ich habe es bei meiner NIBObee auch genauso gemacht. Die Fuses vom mega16 eingelesen und auf den mega644 übertragen.

pinsel120866
22.01.2010, 09:00
Hallo,

nachdem die IR-Abstandsmessung gut funktioniert, will ich die PINs der 4 Schalter verwenden. Ich habe vor die Schalter abzulöten und die Leitungen der IR-Erweiterung dort anzubringen.

Ich habe nur bis jetzt nicht herausgefunden an welcher der 4 Lötpunkte pro Schalter ich die Leitung anlöten kann.

Kann mir bitte jemand weiterhelfen?

radbruch
22.01.2010, 10:12
Hallo

Die Widerstände der Taster R46 bis R49 befinden sich direkt neben X1 bzw. X4. Da die Seiten der Widerstände, die an den X-Steckern liegen, auch die Anschlüsse zum Kontroller sind, habe ich einfach je zwei 2er-Stiftleisten an die Widerstände angelötet. Beim Löten hatte ich die neuen Stifte mit einem Sockel an X1/X4 angesteckt, so habe ich das Rastermass eingehalten und kann die zusätzlichen Pins jeweils zusammen mit X1/X4 verwenden.

Das habe ich so bei meinem parallelen LCD angewendet, die Taster am LCD hängen dabei neben den D4-D7 am LCD auch parallel zu den orginalen Fühlertasten:
http://radbruch.bplaced.net/robot/nibobee/lcd/nibobee-lcd4_klein.jpg (http://radbruch.bplaced.net/robot/nibobee/lcd/nibobee-lcd4.jpg) http://radbruch.bplaced.net/robot/nibobee/nibobee-x4-erweiterung_klein.jpg (http://radbruch.bplaced.net/robot/nibobee/nibobee-x4-erweiterung.jpg)
Aus: https://www.roboternetz.de/phpBB2/viewtopic.php?p=477739#477739
und https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=476664#476664

Die Tastenfunktion meiner LCD-Lib unterscheidet nicht zwischen den neuen LCD-Tasten und den orginalen Sens-Tastern:

uint8_t lcd_getkeys(void)
{
uint8_t keys=0;
el;
DDRC &= ~0b11110010; // LCD-Pins auf Eingang mit PullUp
PORTC |= 0b11110010;
delay(1);

if(PINC & (1<<PC1)) keys |= 16;
if(PINC & (1<<PC4)) keys |= 8;
if(PINC & (1<<PC5)) keys |= 4;
if(PINC & (1<<PC6)) keys |= 2;
if(PINC & (1<<PC7)) keys |= 1;

PORTC &= ~0b11110010; // nanu ???
DDRC |= 0b11110010; // LCD-Pins auf Ausgang und low
return(~keys & 0b11111);
}


Meine bee hat nun AAs als Stromversorgung, weil die AAAs mit dem LCD zu schnell zusammenbrechen (unter 4,6V wird meine bee vom Programmer nicht mehr erkannt!). Die Ladefunktion hatte ich eh nie genutzt, deshalb habe ich die drei Jumper durch Brücken ersetzt. Leider fehlen ein paar Millimeter Platz zwischen den Radkästen:
http://radbruch.bplaced.net/robot/nibobee/nibobee-mit-AAs_klein.jpg (http://radbruch.bplaced.net/robot/nibobee/nibobee-mit-AAs.jpg)

Gruß

mic


Edit: http://www.roboter.cc/index.php?option=com_kunena&func=view&catid=3&id=961&Itemid=20#1062

radbruch
24.01.2010, 19:30
Hallo

Nun habe ich mich endlich auf die Odometry gestürzt und diese auch gleich etwas gepimpt. Mechanische Änderung sind je 4 zusätzliche Löcher in den Codescheibenritzeln, softwaremäßig habe ich odometry.c der Lib ersetzt.

Durch die zusätzlichen Löcher sind die Abstände der Löcher in den Coderitzeln gleichmäßiger, deshalb werden die Odometryzähler nun bei erkanntem Pinchange des entsprechenden Eingangs erhöht. Das ergibt mit 16 Zählimpulsen pro Coderadumdrehung eine deutliche Verbesserung gegenüber den vier Impulsen der orginalen Odometry. Die Impulse werden nur aufsteigend und drehrichtungsunabhängig gezählt. Gleichzeitig wird die Differenz der Seiten seit dem letzen Zählerreset gebildet. Die neuen Funktionen dafür sind:

int odometry_reset(void); // Zähler zurücksetzen
int odometry_get_left(void); // linken Zähler auslesen
int odometry_get_right(void); // rechten Zähler auslesen
int odometry_get_difference(void); // Zählerdifferenz auslesen, positiv bedeutet links>rechts

Desweiteren habe ich eine (in der Library nicht verwendete) Overflow-ISR am Timer1 eingeklinkt. Diese wird mit 15MHz/1022= ca. 15kHz aufgerufen und bildet die Basis für einfache Zeit- und Geschwindigkeitsfunktionen:

void Sleep(uint8_t); // Pause in 1/15000 Sekunden
void Msleep(uint16_t); // Pause in 1/1000 Sekunden
void delay(uint16_t); // ohne delay.h, verwendet Msleep()
uint32_t gettime(void); // Millisekunden seit dem Systemstart (als 32bit-Wert)
int speed_get_left(void); // 1000 minus Anzahl der Overflow-Ticks zwischen zwei positiven Flanken links
int speed_get_right(void); // dito rechts

Maxwerte für die Geschwindigkeitsmessung mit Startwert 1000 sind bei meiner Bee ca. 900 (also 100 Ticks zwischen den Löchern), bei orginalen Coderitzeln muss man die Werte selbst ermitteln. Mein aktueller Arbeitscode dazu:


// nibobee Odometry- und Motorfunktionen 24.1.01 mic

// Modifizierte Odometry mit 8 Löchern in den Ritzeln und Pinchange-Interrupt
// ergibt 16 Flanken pro Umdrehung des Coderitzels.

// Zusätzlich zur Library ist für den Timer1 eine Overflow-ISR eingeklingt die
// mit ca. 15kHz die Zeitbasis für Sleep(), Msleep() und gettime() liefert.
// Außerdem misst diese ISR die Anzahl der Timer1-Overflows zwischen zwei positiven
// Flanken der Odometrysensoren als umgekehrtes Mass für die Geschwindigkeit.

#include <nibobee/iodefs.h>
#include <nibobee/led.h>
#include <nibobee/motpwm.h>

// Variblen
volatile uint8_t count15kHz;
volatile uint32_t count_ms; // 32bit-Zähler!
volatile uint16_t odometry_left=0, odometry_right=0;
volatile int16_t odometry_difference=0;
volatile uint16_t speed_left=0, speed_right=0, speed_left_tmp=1000, speed_right_tmp=1000;
int16_t motor_pwm_left, motor_pwm_right;
uint32_t stopwatch1, stopwatch2;

// Funktionen
void Sleep(uint8_t pause); // ca. 1/15000 Pause blockierend
void Msleep(uint16_t pause); // ca. 1/1000 Pause blockierend
inline void delay(uint16_t pause) { Msleep(pause); }
uint32_t gettime(void); // Millisekunden seit Systemstart als 32bit-Wert
void odometry_reset(void); // Odometryzähler zurücksetzen
int odometry_get_left(void); // Odometryzähler auslesen
int odometry_get_right(void);
int odometry_get_difference(void); // Zählerunterschied seit dem letzten odo_reset
int speed_get_left(void); // Geschwindigkeit auslesen
int speed_get_right(void);

#include "lcd_lib.c" // Hier muss man die eigene LCD-Lib einbinden
int main(void)
{
led_init();
motpwm_init();
TIMSK |= (1 << TOIE1); // Die Overflow-ISR misst die Geschwindigkeit der Antriebe
enable_interrupts();
lcd_init();
lcd_writeString(" Nibobee mit LCD");

led_set(0,1);
Msleep(2000); // wait4programmer
lcd_writeStringAt(0,3,"Bitte Taste druecken");
while(!lcd_getkeys()) {PORTB ^= (1<<PB0); Msleep(100);}
led_set(0,0);

// Odometry: enable int0 and int1 on pinchange
MCUCR = (1<<ISC10) | (1<<ISC00); // Interrupt bei Pinchange
GICR |= (1<<INT1) | (1<<INT0); // Int0 und Int1 freigeben

lcd_cls();
lcd_writeString(" Odometrywerte");
lcd_writeStringAt(0,2,"Sp/PWM Li:");
lcd_writeStringAt(0,3,"Sp/PWM Re:");

motor_pwm_left=motor_pwm_right=300;
stopwatch1=stopwatch2=gettime();

while(1)
{
odometry_reset();
while((odometry_get_left()+odometry_get_right()) < 998) // Sollposition 1000
{
motpwm_setLeft(motor_pwm_left); motpwm_setRight(motor_pwm_right);
if((odometry_get_left()+odometry_get_right()) < 900) // Verzögerungspunkt
{
if(gettime() > stopwatch1)
{
stopwatch1=gettime()+20; // alle 20 Millisekunden ausführen
if(odometry_difference > 0)
{
motor_pwm_left--;
motor_pwm_right++;
}
else
{
motor_pwm_left++;
motor_pwm_right--;
}
}
}
else
{
motor_pwm_left=motor_pwm_right=200; // Einfahrgeschwindigkeit
}

if(gettime() > stopwatch2)
{
stopwatch2=gettime()+300;
lcd_writeIntegerAt(11,2,speed_get_left(), 10);
lcd_writeString("/");
lcd_writeInteger(motor_pwm_left, 10);
lcd_writeString(" ");
lcd_writeIntegerAt(11,3,speed_get_right(), 10);
lcd_writeString("/");
lcd_writeInteger(motor_pwm_right, 10);
lcd_writeString(" ");
}
}
motpwm_stop();
Msleep(200);
lcd_writeStringAt(0,1,"L ");
lcd_writeInteger(odometry_get_left(), 10);
lcd_writeString(" R ");
lcd_writeInteger(odometry_get_right(), 10);
lcd_writeString(" S ");
lcd_writeInteger(odometry_get_difference(), 10);
lcd_writeString(" ");

motor_pwm_left=motor_pwm_right=300;
while(!lcd_getkeys()) {PORTB ^= (1<<PB0); Msleep(100);}
}
return(0);
}
ISR(INT0_vect)
{
// static uint8_t flag=0; // nur jedes zweite Loch zählen für orginale bee
odometry_left++;
odometry_difference++;
if(PIND & (1<<PD2)) // if(flag++)
{
speed_left=(speed_left+speed_left_tmp)/2; // unterschiedliche Lochabstände ausgleichen
speed_left_tmp=1000;
// flag=0;
}
PORTB ^= (1<<PB0); // Kontrolle mit LED0
}
ISR(INT1_vect)
{
//static uint8_t flag=0;
odometry_right++;
odometry_difference--;
if(PIND & (1<<PD3)) // if(flag++)
{
speed_right=(speed_right+speed_right_tmp)/2;
speed_right_tmp=1000;
// flag=0;
}
PORTB ^= (1<<PB3); // Kontrolle mit LED3
}
ISR(TIMER1_OVF_vect)
{
static uint8_t count_ms_temp=15;

if(speed_left_tmp) speed_left_tmp--;
if(speed_right_tmp) speed_right_tmp--;
//PORTB ^= (1<<PB2); // Kontrolle mit LED2

if(count15kHz) count15kHz--;
if(!count_ms_temp--) {count_ms++; count_ms_temp=15;}
}
void Sleep(uint8_t pause) // ca. 1/15000 Pause blockierend
{
count15kHz=pause;
while(count15kHz);
}
void Msleep(uint16_t pause) // ca. 1/1000 Pause blockierend
{
while(pause--) Sleep(15);
}
uint32_t gettime(void) // Millisekunden seit Systemstart als 32bit-Wert
{
uint32_t temp32;
cli();
temp32=count_ms;
sei();
return(temp32);
}
void odometry_reset(void)
{
cli();
odometry_left=odometry_right=odometry_difference=0 ;
sei();
}
int odometry_get_left(void)
{
uint16_t temp16;
cli();
temp16=odometry_left;
sei();
return(temp16);
}
int odometry_get_right(void)
{
uint16_t temp16;
cli();
temp16=odometry_right;
sei();
return(temp16);
}
int odometry_get_difference(void)
{
uint16_t temp16;
cli();
temp16=odometry_difference;
sei();
return(temp16);
}
int speed_get_left(void)
{
uint16_t temp16;
cli();
temp16=speed_left;
sei();
return(temp16);
}
int speed_get_right(void)
{
uint16_t temp16;
cli();
temp16=speed_right;
sei();
return(temp16);
}


Soweit, so gut, das funktioniert alles zufriedenstellend. Aber wie kann ich nun die Geschwindigkeiten der Motoren regeln? Alle meine Anläufe die diversen Reglergrößen anzupassen scheiterten bisher kläglich. Selbst einen popeligen P-Regler kann ich nicht umsetzen, weil ich nicht weiß, wie ich die Abtastzeit und die Stellgröße (möglichst ohne float) an meine bee anpassen kann. Hier finde ich den Einstieg nicht, vielleicht kann mir das mal jemand erklären.

Gruß

mic

Sebas
30.10.2010, 20:57
Hallo
ich bin mal so dreist und hole diesen thread aus der Versenkung.

Ich hab mit meinem Bienchen mittlerweile auch schon allerhand unsinn angestellt und möchte ihn jetzt auch Hardware seitig umbauen.
Gut gefiel mir die idee die taster durch ir dioden zu ersetzen, aber mir ist nicht so ganz klar wie ich das machen muss.
drum die frage ob mir das mal einer erklären kann?

danch würd ich gerne ein kleinen arm auf meine bienchen bauen, dafür bräuchte ich drei so mini servos kann ich die überhaupt alle ansteuern?
und geht des einigermassen lkeicht? ich hab mich bisher nur mit den standard funktionen beschäftigt
was haltet ihr von diesen Servos (http://cgi.ebay.de/ws/eBayISAPI.dll?ViewItem&item=280567615371&ssPageName=STRK:MEWAX:IT)?
mfg Sebastian

radbruch
01.11.2010, 09:23
Hallo

Das wurde hier mal vorgeschlagen, aber nie umgesetzt:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=476661#476661

Daraus ist dann eine IR-Abstandmessung für die bee geworden die wir hier zusammengebastelt haben:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?t=52115

Mehrere Servos anzuschliesen und anzusteuern ist kein Problem mit der bee. Als Basis könntest du diese Servo-ISR verwenden:
https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=474468#474468

Für mehrere Servos sind die AAAs der Biene zu schwach. Mit AAs könnte sie den geplanten Arm auch besser ausbalancieren:
http://radbruch.bplaced.net/robot/nibobee/nibobee-mit-AAs_klein.jpg (https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=482057#482057)

Gruß

mic

Sebas
01.11.2010, 13:40
vielen dank ich lese es mir gleich mal durch
den thread mit der abstandsmessung hab ich bei meiner suche gar nicht gefunden, muss ich wohl noch weng üben;-)
bei den servos ist irgendwie der link verschwunden bzw wurde durch den link ins rn wissen ersetzt hier nochmal
was meint ihr dazu
http://cgi.ebay.de/ws/eBayISAPI.dll?ViewItem&item=280567615371&ssPageName=STRK:MEWAX:IT

mister_g84
26.11.2010, 16:37
Hallo,

ich möchte auch ein LCD über I²C betreiben. Nur leider klappts nicht so richtig und ich finde den Fehler einfach nicht. Die BGX1 Lib is eingefügt und dann hab ich den Code einfach kopiert. Trotzdem kommt diese Fehlermeldung.



../lcdi2c.c: In function 'lcd_writePCF8574':
../lcdi2c.c:174: error: 'i2c_size' undeclared (first use in this function)
../lcdi2c.c:174: error: (Each undeclared identifier is reported only once
../lcdi2c.c:174: error: for each function it appears in.)
../lcdi2c.c: In function 'lcd_pushNibble':
../lcdi2c.c:186: error: 'i2c_size' undeclared (first use in this function)
make: *** [lcdi2c.o] Error 1
Build failed with 4 errors and 0 warnings...



Dann hab ich "i2c_size" einfach mal auskommentiert um zu schauen ob noch mehrere Fehler kommen. Dann kam folgendes



D:\programme\nibobee\lib\libnibobee_bgx1.a(i2cmast er.o): In function `i2c_init':
i2cmaster.c:(.text.i2c_init+0x16): undefined reference to `nibobee_initialization'
i2cmaster.c:(.text.i2c_init+0x1c): undefined reference to `nibobee_initialization'
make: *** [Elsy_NiBoBee.elf] Error 1
Build failed with 2 errors and 0 warnings...


Wäre dankbar für einen Tipp....
Danke im Voraus

workwind
26.11.2010, 17:20
Die BGX1 Bibliothek (libnibobee_bgx1.a) muss noch dazugelikt werden!

Linker-Option: -l nibobee_bgx1

mister_g84
26.11.2010, 19:05
Nach etwa einer 1 stündigen suche bin ich noch immer nicht weiter. Wie linke ich die denn dazu?
Und wieso hab ich mit den anderen Libs keine Probleme?

workwind
26.11.2010, 21:58
Ich nehme an Du verwendest AVRStudio? Hast Du schon mal das Tutorial zum NIBObee durchgearbeitet?

mister_g84
27.11.2010, 17:09
Ja ich verwende das AVRStudio.
Ich hab auch das Tutorial durchgearbeitet. Hat auch alles funktioniert.
Nur das mit der BGX1 Lib funktioniert nicht. Hab auch schon ein neues Projekt erstellt aber es bleibt das gleiche Problem. Es wird wohl nchit viel sein...
Auf Seite 16 steht ja, dass man die Reihenfolge beachten soll. Hab das so wie im Tutorial gemacht und am Schluss die BGX1 hinzugefügt. Also wirds daran ja nicht liegen

mister_g84
28.11.2010, 11:37
Hallo,

ich habe mal ins Makefile geschaut und da steht folgendes:


## Libraries
LIBS = -lnibobee_base -lnibobee_line -lnibobee_utils -lnibobee_bgx1


Also müsste die BGX1 gelinkt sein oder?!?
Meiner Meinung liegts doch eher an der i2cmaster.h. Dort ist die Variable "i2c_size" deklariert und diese Headerdatei ist auch eingebunden. Trotzdem kennt er diese Variabel nicht.....

mister_g84
16.12.2010, 16:03
Hallo,

das LCD funktioniert mittlerweile einwandfrei. Weiss auch nicht genau, wo der Fehler mit der Lib lag...
Habe nun ein anderes Problem. Ich bentutze ein LCD mit dem HD44780. Schreiben und so weiter auf das Display funktioniert auch. Nur die Funktion lcd_setCursor(0,1); funktioniert nicht. Wenn ich sie aufrufe und danach was schreiben möchte erscheint nichts auf dem Display.

aurikeL
01.01.2011, 16:08
Hallo Roboternetz,

dieser Beitrag soll den alten ersetzen, da dieser u.a. nicht wirklich gut formuliert war. 8-[

Ich würde gerne mit meiner NIBObee die Helligkeit von einem Gegenstand ermitteln, der vor meiner Biene steht.
Es gibt ein Video bei youtube, welches einen ASURO zeigt, der genau das macht und sich abhängig von der Helligkeit bewegt: "Müll sortierender ASURO (http://www.youtube.com/watch?v=RBySxcFqP4o)".
Leider wird das Verfahren nicht genauer erläutert, aber ich dachte, dass es über Infrarot geht (so wie z.B. bei den Liniensensoren), weswegen ich im Folgenden 3 Alternativen aufführen möchte und um eure Beurteilung dieser bitte.

1) Liniensensoren nachbauen
Auf die Liniensensoren habe ich bereits oben schon verwiesen, allerdings möchte ich dies nun spezifizieren. Da die Liniensensoren ebenfalls die Helligkeit des Untergrunds messen, dachte ich, dass man ggf. mit einem ähnlichen oder gleichen Aufbau die Helligkeit eines Objektes messen könnte.
Konkret war meine Überlegung: eine IR-LED sowie einen IR-Transistor zu verwenden und zur Messung dann die Spannung am Ausgang des Transistors zu messen (geht das?).

2) Sharp Entfernungssensor GP2D120
Daneben bin ich mehrfach auf die Sensorreihe von Sharp gestoßen, mit denen man ja eig. Entfernungen bestimmen kann. Könnte ich mit einem von diesen auch die Helligkeit ermitteln? Rabenauge hat an dieser Stelle (http://www.robotikportal.de/phpBB2/viewtopic.php?p=504151) bereits etwas über die Verwendung von einem Sharp-Sensor an der NIBObee geschrieben.

3) Verwendung eines IR-Empfängers
Außerdem hab ich an einigen Stellen gesehen, dass ein IR-Empfänger verwendet wurde, Beispiel: von Pinsel120866 (https://www.roboternetz.de/phpBB2/viewtopic.php?t=52115&postdays=0&postorder=asc&start=0). In dem Link wird ein IR-Empfänger + 2 IR-LEDs zur Abstandmessung verwendet.

Da ich neben dem Programmiertutorial zur NIBObee noch nicht viel Erfahrung gesammelt habe, denke ich, dass die 3. Möglichkeit rausfällt, da diese am schwierigsten zu programmieren ist.
Bei Möglichkeit 1 bin ich mir allerdings nicht sicher, ob eine IR-LED und ein IR-Transistor reicht - könnt ihr dazu genaueres sagen? (das stellt eig. mein Hauptanliegen dar)
Möglichkeit 2 möchte ich erstmal unkommentiert lassen.

Liebe Grüße und ein frohes neues Jahr
Max.

Edit 1:
Möglichkeit 2 fällt raus:

Farbunabhängig ermittelt die Auswertelektronik die Entfernung und gibt sie über Analogsignal aus.
Damit bleiben noch Möglichkeit 1 und 3 offen, wobei ich 1 bevorzuge. Bei Möglichkeit 1 bin ich mir aber nicht sicher, wie diese umsetzen muss:
Reicht es, wenn ich die IR-LED & den Vorwiderstand an + und - eines Ports anschließe und die Kathode des IR-Transistor an das analoge Signal eines Ports (wo muss ich die Anode anschließen), damit ich diesen über analog_getValue() abfragen kann?

workwind
03.01.2011, 17:10
@aurikeL:
Das reicht fast, Du benötigst 2 Widerstände. Einen als Vorwiderstand für die IR-LED (180 Ohm) und einen als Strom/Spannungswandler für den Fototransistor (2,2 kOhm).
Im Schaltplan zur NIBObee (http://download.nicai-systems.com/nibo/nibobee_schematic_1_07.pdf) auf Seite 1 ist die Schaltung für die Liniensensoren abgebildet (gestrichelter Kasten).
Passende IR-LEDs und Fototransitoren findest Du hier: http://www.nibo-roboter.de/wiki/NIBObee/Ersatzteile

Die Schaltung kannst Du an X1 (2 analoge Eingänge) oder X2 bzw. X3 (jeweils 1 analoger Eingang) anschliessen.
Die IR-LED kannst Du auch schaltbar an einem Port-Ausgang betreiben, sie benötigt keinen extra Treiber.

aurikeL
08.01.2011, 20:44
Mit dem Ziel, dass die Biene Farben (minimal 2) erkennen kann - sind die beiden oberen Beiträge entstanden. Daneben war ich mehrmals im #roboternetz.de IRC-Chat, in dem ich auf Schumi gestoßen, der mich eine große Hilfe war. Einen besonderen Dank an ihn - an die anderen, die mir geholfen haben, aber auch! =D>

Das Resultat ist nun folgendes (leider in schlechter Qualität):
http://www.youtube.com/watch?v=Y2hlnTpRI9s

Der Aufbau ist folgender:


LED1: [AVR]--[R]--[+LED-]--[VCC]
LED2: [AVR]--[R]--[+LED-]--[VCC]
LED3: [AVR]--[R]--[+LED-]--[VCC]
Sensor: [+5V]--[LDR]--+--[R]--[VCC]
[AVR]-----------|


Ein grüner Gegenstand wird z.T. falsch erkannt, allerdings verwende ich auch grüne Legosteine - die sind etwas dunkel.

Ein Link zum Aufbau: http://img718.imageshack.us/img718/5309/img20110108193606.jpg

Edit: ein Grund für die oben genannten Ungenauigkeiten sind, dass z.T. Licht direkt von der LED auf den Fotowiderstand fällt - deswegen auch die Papiere, allerdings sind diese nicht wirklich gut. Ich muss morgen mal meinen Schrumpfschlauch suchen, aber den muss ich irgendwie verlegt haben (gestern hab ich ihn nicht gefunden).

Edit2: Anbei noch mein Code (ich bin für Verbesserungen offen - ob der "Dummyreadout" so notwendig ist, sei an dieser Stelle dahingestellt):


#define StatusLEDs_on PORTB |= (1 << PB1) | (1 << PB2);
#define StatusLEDs_off PORTB &= ~((1 << PB1) | (1 << PB2));

#include <nibobee/iodefs.h>
#include <nibobee/led.h>
#include <nibobee/delay.h>
#include <nibobee/analog.h>
#include <nibobee/sens.h>
#include <avr/io.h>

// Aufbau:
// Farbe1: [PA0]--[R]--[+LED-]--[GND]
// Farbe2: [PA1]--[R]--[+LED-]--[GND]
// Farbe3: [PA2]--[R]--[+LED-]--[GND]
// Sensor: [+5V]--[LDR]--+--[R]--[GND]
// Sensor: [PA3]---------|

uint16_t getLightValue() {
int Value = 0;
int8_t i;

// Auslesen
for (i = 0; i < 11; i++) {
Value = Value + analog_getValue(ANALOG_EXT3);
delay(50);
} // for

return(Value / i);

} // getValue()

int main()
{
uint16_t grValue, blValue, reValue;
int8_t i;
led_init(); // LED initialisieren
analog_init(); // Analoge Eingaenge initialisieren
sens_init(); // Fuehler initialisieren
enable_interrupts(); // Interrupts aktivieren
DDRA |= 0b00000111; // PINs als Ausgaenge schalten
DDRB |= 0b00000110; // PINs als Ausgaenge schalten

// Dummyreadout
for (i = 0; i < 11; i++) {
grValue = analog_getValue(ANALOG_EXT3);
delay(50);
}

while (1 == 1) {
StatusLEDs_on;
while ((sens_getLeft() != 0) | (sens_getRight() != 0)) {
StatusLEDs_off;

// Farbmessungen
// 1. gruen
PORTA = 0b00000001; // LED anschalten
delay(500); // 0,5 Sek. warten
grValue = getLightValue(); // Wert des Sensors abfragen

// 2. rot
PORTA = 0b00000010; // LED anschalten
delay(500); // 0,5 Sek. warten
reValue = getLightValue() - 25; // Wert des Sensors abfragen

// 3. blau
PORTA = 0b00000100; // LED anschalten
delay(500); // 0,5 Sek. warten
blValue = getLightValue() - 75; // Wert des Sensors abfragen

// Auswertung
if ((grValue > reValue) & (grValue > blValue)) {
// gruener Gegenstand
PORTA = 0b00000001; // gruene LED an
} else if ((reValue > grValue) & (reValue > blValue)) {
// roter Gegenstand
PORTA = 0b00000010; // rote LED an
} else if ((blValue > grValue) & (blValue > reValue)) {
// blauer Gegenstand
PORTA = 0b00000100; // blaue LED an
} else {
// keine Erkennung
PORTA = 0b00000111; // alle LEDs an
} // if
} // while - Fuehler
} // while - Endlosschleife
return 0;
}

Die 0,5 Sek Wartezeit sind wahrs. viel zu hoch dimensioniert, allerdings stört mich die Wartezeit momentan nicht, weshalb ich bisher keinen Grund sehe, diese zu reduzieren.