PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Fehlersuche Impulse zählen und auswerten



zetgun
13.07.2010, 20:36
Hi,
ich habe das Gefühl ich sehe wieder den Wald vor lauter Bäumen nicht. Ich hab nun schon mehrmals über den Code geschaut, mehrere Pausen gemacht...aber ich blicks nicht.
Aber wozu gibts eine nette Community :)

Ich habe eine Nibobee welche zwei Antriebsmotoren hat und an jedem einen Odometrysensor, welcher über Interrupts eine Variable hoch bzw. runter zählt.
Dies wollte ich nun ausnutzen um beide Motoren mit der selben Drezahl drehen zu lassen. Sprich gleich viele Impulse pro bestimmter Zeit. Hier 10 Impulse pro 100ms (14 Impluse pro 100ms entsprechen ca. 100% PWM).

Um die 100ms zu erreichen habe ich einen Timer, der jede ms "time_odo" incrementiert. Wenn dieser >=100 (falls die 100 verpasst) werden die Impulse vom rechten und linken Sensor eingelesen und mit der Vorgabe abgeglichen und dann das Motor-PWM incrementiert oder decrementiert. Zur Kontrolle noch ein paar LEDs ansteuern, timer_odo wieder auf 0 und fertig.

Leider habe ich aber nun da Problem das, dass rechte Rad sich langsamer dreht als das Linke und ich nicht verstehe warum.
Leider habe ich auch noch kein Display / UART und kann mir somit die Werte nicht rausgeben. (Ist aber bestellt)


#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
#include <nibobee/motpwm.h>
#include <nibobee/odometry.h>
#include <nibobee/sens.h>
#include <nibobee/delay.h>
#include <nibobee/iodefs.h>

// Prototypen
void LED_init(void);
void LED_set(int8_t led0, int8_t led1, int8_t led2, int8_t led3);
void Timer0_init(void);

// globale Variable
volatile uint16_t time_odo = 0;

/*************
Main
**************/

int main(void)
{
// IO's init
sens_init();
Timer0_init();
LED_init();
odometry_init();
motpwm_init();

// Variable
int8_t odo_tick_l = 10; // 14Ticks in 100ms => 90% PWM
int8_t odo_tick_r = 10;
int16_t odo_left = 0;
int16_t odo_right = 0;
int16_t speed_l = 0;
int16_t speed_r = 0;

// Interrupts aktivieren
sei();

delay(500);
odometry_reset();

while(1)
{

if(time_odo >=100) // Alle 100ms
{
cli(); // Odo-Sensoren einlesen, damit right nicht weiterzählt => Interrupts aus
odo_left = odometry_getLeft(1); // Linker Sensor in "odo_left" und dann reset des Senors
odo_right = odometry_getRight(1); // Rechter Sensor in "odo_right" und dann reset des Senors
sei(); // Interrupts wieder an

// Left
if(odo_left < odo_tick_l)
{
speed_l +=5;
LED_set(0,1,2,2);
}
else if(odo_left > odo_tick_l)
{
speed_l -=5;
LED_set(1,0,2,2);
}
else LED_set(1,1,2,2);

// Right
if(odo_right < odo_tick_r)
{
speed_r +=5;
LED_set(2,2,1,0);
}
else if(odo_right > odo_tick_r)
{
speed_r -=5;
LED_set(2,2,0,1);
}
else LED_set(2,2,1,1);

time_odo =0;
}

// Motoren mit PWM-Werten füttern
motpwm_setLeft(speed_l);
motpwm_setRight(speed_r);
}
return 0;
}

/*************
Funktionen
*************/

// *** LED ***
void LED_init(void)
{
DDRB |= (1<<PB0) | (1<<PB1) | (1<<PB2) | (1<<PB3);
}

void LED_set(int8_t led0, int8_t led1, int8_t led2, int8_t led3)
{
// Hier steht die LED ansteuerung, wird aber nicht gebraucht zum Code verstehen
}

// *** Timer0 ***
void Timer0_init(void)
{
TCCR0 = (1<<WGM01); // Timer im CTC-Modus
TCCR0 |= (1<<CS00) | (1<<CS01); // Prescaler auf 64
OCR0 = 234; // um ca. 1ms zu erreichen
TIMSK |= (1<<OCIE0); // Interrupt "TIMER0_COMP_vect" aktivieren
}

/*************
Interrupts
*************/

ISR (TIMER0_COMP_vect)
{
time_odo++;
}

Ich hoffe ihr könnt einen Fehler entdecken...Ich seh das Problem leider nicht.

greez

radbruch
13.07.2010, 21:15
Hallo

So auf den ersten Blick:


// Left
if(odo_left < odo_tick_l)
{
if(speed_l < 1019) speed_l +=5; // Maxwert 1023?
LED_set(0,1,2,2);
}
else if(odo_left > odo_tick_l)
{
if(speed_l > 4)speed_l -=5; // eher unwahrscheinlich
LED_set(1,0,2,2);
}
else LED_set(1,1,2,2);
(Ungetestet)

Können die Motoren innerhalb 1ms die Drehzahl anpassen?

Gute Kommentare, deshalb großes Lob von mir :)

Gruß

mic

zetgun
13.07.2010, 21:51
Hi,
danke für deine Antwort. Da du im Code nach Fehlern gesucht hast gehe ich davon aus, das mein Ansatz nicht ganz falsch sein kann. :)

Wiso kommst du auf 1ms zum anpassen der Drezahl? Durch "if(time_odo >=100)" rufe ich nur alle 100ms den Abgleich auf. Oder?
Wenn ich es richtig seh, hast du in dem Code nur Begrenzugen zugefügt. Diese werden aber nie erreicht (habe ich schon mal mit den Leds anzeigen lassen). Zudem werden diese in der Funktion "motpwm_setXXX()" auch noch überprüft.

gruß

radbruch
13.07.2010, 22:19
Hallo


Wieso kommst du auf 1msWeil ich nach dem Ausrechnen der Timerfrequenz (1001,6Hz) die 100 vergessen hatte. Sorry.


das mein Ansatz nicht ganz falsch sein kannMein Ansatz war ein anderer, ich habe den zeitlichen Abstand zwischen zwei Löchern gemessen:

https://www.roboternetz.de/phpBB2/zeigebeitrag.php?p=482547#482547

Keine Ahnung, welcher Ansatz besser ist und zum Ziel führt. Ich habe an dieser Stelle abgebrochen...

Gruß

mic

zetgun
17.07.2010, 17:35
Hi,
ich habe nun meine UART gebaut und habe festgestellt, dass beide Odometry-Sensoren die gleichen Werte bringen, aber die PWM-Werte um ca. 1/4 auseinanderliegen. Deshalb die Rechtskurven. Wenn ich die PWM von Hand einstell, damit er geradeaus fährt sind es aber weit weniger.

Ich habe die Räder auch schon langsamer von Hand gedreht, aber die Sensoren erfassen alle Übergänge (immer 20 Pulse pro Umdrehung).

Kann es noch was damit zu tun haben, dass der INT0 (linkes Rad) eine höhere Prio als der INT1 (rechts Rad) hat?

Hier mal ein kurzer Auszug der erfassten Daten:


odo_L odo_R PWM_L PWM_R
10 10 710 530
10 11 710 525
10 10 710 525
10 12 710 520
10 11 710 515
10 12 710 510
11 11 705 505
10 10 705 505
10 10 705 505
10 10 705 505
10 10 705 505
10 12 705 500
10 7 705 505
10 10 705 505
10 8 705 510
10 12 705 505
10 10 705 505
10 11 705 500
10 11 705 495
10 9 705 500
10 11 705 495
10 12 705 490


Irgendwo muss doch ein Fehler sein...

gruß

zetgun
17.07.2010, 17:53
Hat sich erledigt. War ein Hardwaredefekt.
Hab den OP der die Sensoren auswertet mal getauscht und schon funktionierts...
Ich liebe Bauteile die ESD-Schäden oder ähnliches haben. ](*,)

gruß

Besserwessi
17.07.2010, 18:06
Ob der Sencor an Int0 oder int1 hängt sollte nicht wesentlich sein, es sein denn der µC wäre völlig überlastet. Das wird hier aber nicht der Fall sein.

Der rechte Motor scheint nicht ganz so stabil zu sein. Die Schwankungen sind auch nicht symetrisch um den Sollwert und dadruch kommt im Mittel mehr als 10 für den Odometiresensor raus. Das Problem sind die Wert außerhalb von 9 -11: auch wenn der Sensor z.B. 13 zurückgiebt, wird der PWM Wert nur um 5 reduziert, genauso als hätte man 11 gehabt.

Der unterschiedliche PWM Wert könnte z.B. durch die andere Drehrichting des Motors entstehen, oder durch Unterschiede in der Reibung im Getreibe. Das sollte aber ein gute Regelung kompensieren können.

Eine Lösung wäre ein besserer Regelungsalgorithmus. Es kommt darauf an, dass auch die Summe der bisher zurückgelegten Schritte stimmt, nicht nur die momentane Geschwindigkeit. Eine einfache Idee wäre eine direkte Proportionalregelung: also statt der Schritte um +-5 den PWM wert um z.B. 3 * (odo_soll - odo_ist) zu verändern. Damit werden im PWM wert die Abweichungen aufaddiert und die Fehler können sich nicht unbegrenzt aufsummieren. Der kleinere Faktor von z.B. 3 eventuell für eine bessere Stbilität.