PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Asuro Steuerung für Dieselmotor



erik1563
18.08.2011, 22:45
Moin Moin!
Ich habe vor kurzem mal meinen Asuro wieder ausgegraben, weil ich gezwungen war mich wieder mit C zu beschäftigen. (Studium)<br>Ich habe vor mit Hilfe des Asuro und einem RC-Servo eine Drehzahlsteuerung für einen kleinen Dieselmotor zu bauen.<br>Ich hab heute den Tag über daran gearbeitet den Servo anzusteuern, funktioniert mittlerweile auch, aber ich scheitere daran den Servo über die IR Schnittstelle zu steuern
#include "asuro.h"

int main(void)
{
Init();
unsigned char l[3];
while(1) {
SerRead(l,3,0);
while(l > 0)
{

BackLED(ON,OFF);
Sleep(l);
BackLED(OFF,OFF);
Sleep(144);Sleep(144);Sleep(144);Sleep(144);Sleep( 144);Sleep(144);Sleep(144);Sleep(144);Sleep(144);S leep(144);
}
}
return 0;
}
Das ist das Programm.
Ziel ist es über das Terminal eine 3 stellige Nummer einzugeben, welche die Stellung des Servos verändert. Bisher sind das noch die direkten unsigned char Werte für Sleep() (ca 60-200 Linker und Rechter Anschlag vom Servo), später bastel ich das so um, das man einen Winkel angibt.
Was ist an meinem Progrämmchen verkehrt?
gruss Erik

radbruch
19.08.2011, 07:13
Hallo

Wenn du mit SerRead() Zeichen über die serielle Schnittstelle liest, dann sind das ascii-Zeichen. Die Codes für die Ziffern liegen dabei zwischen 0x30 für '0' und 0x39 für '9'. Man muss also 0x30 oder '0' vom ascii-Code abziehen um den Wert der Stelle zu erhalten. Um von drei gesendeten Zeichen auf eine dreistellige Zahl zu kommen verwendet man deshalb Formeln wie diese:

(Zeichen1 - '0') * 100 + (Zeichen2 - '0') * 10 + (Zeichen3 - '0')


BackLED(ON,OFF);
Sleep((l[0] - '0') * 100 + (l[1] - '0') * 10 + (l[2] - '0'));
BackLED(OFF,OFF);
Sleep(72);Sleep(144);Sleep(144);Sleep(144);Sleep(1 44);Sleep(144);Sleep(144);Sleep(144);Sleep(144);Sl eep(144); // 19ms Pause


l ist ein ungünstig gewählter Name für Variablen.

Gruß

mic

erik1563
19.08.2011, 15:46
Danke für die schnelle Antwort! Hat super funktioniert!
Ich hab den Tag weiter experimentiert und erst einmal versucht ein Bugrad mit dem Servo zu steuern:

http://www.youtube.com/watch?v=uFt6hllIRMU
klappt (http://www.youtube.com/watch?v=uFt6hllIRMUklappt) einigermaßen, aber ich habe Stromprobleme... wenn der Servo sich zu schnell bewegt bricht die Spannung zusammen und Asuro startet neu.
Naja zum spielen hats gereicht.
Nächster Schritt ist ein Drehzahlsensor für den Diesel zu baun.
Fals Interesse besteht halte ich euch gerne auf dem laufenden.

radbruch
19.08.2011, 15:58
Irgendwie erinnert mich das an meine eigenen Schandtaten:
http://www.youtube.com/watch?v=F45RU9yRXtI

Bei dir sieht das aber deutlich besser aus.

Interesse besteht immer ;)

erik1563
20.08.2011, 21:17
Hier noch einmal den Code zum Linienfolgenprogramm:

#include "asuro.h"

int main(void)
{
Init();
unsigned char l;
int data[2];
FrontLED(ON);
l=108;
Sleep(255);
Sleep(255);
MotorDir(FWD,FWD);
MotorSpeed(130,130);
int servo(unsigned char l) {

BackLED(ON,OFF);
Sleep(l);
BackLED(OFF,OFF);
Sleep(144);Sleep(72);Sleep(144);Sleep(144);Sleep(1 44);Sleep(144);Sleep(144);Sleep(144);Sleep(144);
return 0;}
while(1) {
LineData(data);
if(data [0] < data[1])
{l=l+4;
MotorSpeed(100,140);}
else if(data[0] == data[1])
{l=l;}

else
{l=l-4;
MotorSpeed(140,100);}
servo(l);


if(l > 120)
{l=120;}
else if(l < 80)
{l=80;}
else
{l=l;}
}
return 0;
}
Nun möchte ich meine Servofunktion so gestalten, das sie den PWM wie bei der MotorSpeed) Funktion funktioniert. Mit anderen Worten: Ich möchte der servo()Funktion einen Wert übergeben, der so lange ausgeführt wird, bis er geändert wird, damit der Servo einen Hebel gegen einen Federdruck halten kann.
Bisher ist das ja so, das der Servo zwar in der richtigen Stellung bleibt, wenn servo() nicht mehr while schleife andauernd ausgeführt wird, aber inaktiv ist und damit verdrahbar.
Lässt sich das mit dem Atmel umsetzen oder braucht man dafür multitaskting?

radbruch
21.08.2011, 09:51
Hallo

Multitasking können die AVRs natürlich nicht. Für Aufgaben, die quasi im Hintergrund ablaufen sollen, verwendet man deshalb die Timerfunktionen der AVRs. Hier wird die "klassische" Servoansteuerung beschrieben:
http://www.rn-wissen.de/index.php/Servo


#define SERVOPIN 7
#define SERVOPORT PORTD
#define DDRSERVO DDRD

volatile unsigned char servopos;

void servo_init()
{
TIMSK|=(1<<OCIE2);
TCCR2 |= (1<<WGM21) | (1<<CS20); //Prescale=1, CTC mode
OCR2 = F_CPU/100000; //alle 10µS ein IRQ
DDRSERVO|=(1<<SERVOPIN);
};

ISR(TIMER2_COMP_vect)
{
static int count;
if(count>servopos)SERVOPORT&=~(1<<SERVOPIN);
else SERVOPORT|=(1<<SERVOPIN);
if(count<2000)count++;
else count=0;
};

Wie funktioniert das? Der Timer wird so programmiert, dass er alle 10µs die Interruptserviceroutine (ISR) aufruft. Die Aufrufe werden in der ISR mitgezählt (count), der Zählerstand wird zwischen den Aufrufen gespeichert (static). Zusätzlich wird in der ISR der Zählerwert mit dem Wert für die Servoposition (servopos) verglichen und dem Ergebniss entsprechend der Servoausgang gesetzt oder gelöscht. Bei 10µs oder 0,01ms pro Aufruf ist nach 100 Aufrufen eine Millisekunde vergangen, nach 2000 sind es 20ms.

Alles klar soweit? Wie verwendet man das nun beim asuro? Man könnte Timer0 verwenden, denn der wird von der Library des asuro nicht verwendet. Oder man klinkt sich in den Timer1 ein der ja schon für die PWM-Ansteuerung der Antriebe genutzt wird:


#include "asuro.h"

volatile unsigned char servopos=40; // 40 ist ca. 1 ms

SIGNAL (SIG_OVERFLOW1)
{
static int count = 1;
if(count > servopos) BackLED(OFF,OFF); else BackLED(ON,OFF);
if(count < 780) count++; else count=1;
}

int main(void)
{
Init();
TIMSK |= (1 << TOIE1); // Timer1 Overflow-ISR einklinken für Servo

unsigned char l;
int data[2];
FrontLED(ON);
l=108;
Sleep(255);
Sleep(255);
MotorDir(FWD,FWD);
MotorSpeed(130,130);

while(1) {
LineData(data);
if(data [0] < data[1])
{l=l+4;
MotorSpeed(100,140);}
else if(data[0] == data[1])
{l=l;}

else
{l=l-4;
MotorSpeed(140,100);}
//servo(l);
servopos = l; // Servoposition setzen

if(l > 120)
{l=120;}
else if(l < 80)
{l=80;}
else
{l=l;}
}
return 0;
}ungetestet

Gruß

mic

erik1563
21.08.2011, 11:15
Das Programm funktioniert so leider nicht und mein Verständnis für die Elektronik und C reicht nicht aus um da nach nem Fehler zu suchen.
Der Servo zuckt hin und wieder, ich erkenne aber keine regelmäßigkeit.

radbruch
21.08.2011, 12:46
Oje, das war auch Schwachsinn. Der Timer1 "läuft" beim asuro mit 3,9kHz. Das ist viel zu wenig für eine brauchbare Servoansteuerung.

Besser sieht es mit Timer2 aus. Der läuft mit 36kHz, (wie immer der Hinweis: Bei der orginalen CD-Library sind es 72kHz) und läßt sich ähnlich einfach missbrauchen:


#include "asuro.h"

volatile unsigned char servopos=0, p=0; // p dauert ca. 20ms oder 1/50 Sekunde

SIGNAL (SIG_OUTPUT_COMPARE2)
{
static int count = 1;
if(count > servopos) BackLED(OFF,OFF); else BackLED(ON,OFF);
//if(count > servopos) PORTC &= ~(1<<PC4); else PORTC |= (1<<PC4);
if(count < (20*72)) count++; else {count=1; if(p) p--;} // 20ms bei 72kHz-Lib!
}

int main (void)
{

Init();
//DDRC |= (1<<PC4); // Tasteneingang auf Ausgabe setzen
TIMSK |= (1 << OCIE2); // Timer2 CompareMatch-ISR einklinken für Servo
OCR2 = 0x91; // duty cycle for 36kHz vorsichthalber OCR2 belegen

while(1)
{
StatusLED(RED);
servopos=70;
p=50; // eine Sekunde warten
while(p);

StatusLED(GREEN);
servopos=190;
p=50;
while(p);
}
return 0;
}getestet ;)

Dabei sollten die Werte wie bei der Sleep()-Ansteuerung sein. servopos=0 sendet keinen Impuls zum Servo.

Gruß

mic

[Edit]
Sehr knuffig:

#include "asuro.h"

volatile unsigned char servopos=0, p=0; // p dauert ca. 20ms oder 1/50 Sekunde

SIGNAL (SIG_OUTPUT_COMPARE2)
{
static int count = 1;
if(count > servopos) BackLED(OFF,OFF); else BackLED(ON,OFF);
//if(count > servopos) PORTC &= ~(1<<PC4); else PORTC |= (1<<PC4);
if(count < (20*36)) count++; else {count=1; if(p) p--;} // 20ms bei 36kHz-Lib!
}

int main (void)
{
unsigned char l[3];

Init();
//DDRC |= (1<<PC4); // Tasteneingang auf Ausgabe setzen
TIMSK |= (1 << OCIE2); // Timer2 CompareMatch-ISR einklinken für Servo
OCR2 = 0x91; // duty cycle for 36kHz vorsichthalber OCR2 belegen

while(1)
{
SerRead(l,3,0); // drei Ziffern einlesen (blockierend!)
servopos = (l[0] - '0') * 100 + (l[1] - '0') * 10 + (l[2] - '0');
}
return 0;
}

erik1563
21.08.2011, 15:13
wenn ich die programme compilen will kommt folgender fehler:
asuro.o: In function `__vector_3':
C:\Users\Erik\Desktop\asuro_src\ASURO_src\FirstTry/asuro.c:35: multiple definition of `__vector_3'
test.o:C:\Users\Erik\Desktop\asuro_src\ASURO_src\F irstTry/test.c:6: first defined here
make.exe: *** [test.elf] Error 1

radbruch
21.08.2011, 15:50
grrr

Welche Library verwendest du?

Mach mal ein Update auf 2.3 oder höher:

http://sourceforge.net/projects/asuro/files/AsuroLib/asuro%20lib%20V2.3/
(asuro.c und asuro.h austauschen)

Die aktuelle Lib:
http://sourceforge.net/projects/asuro/files/AsuroLib/AsuroLib%20V2.8.0/AsuroLib-v280rc1.zip/download

erik1563
21.08.2011, 20:56
danke funktioniert astrein!
ich werd mich morgen mal daran machen nen drehzahlsensor zu bauen und den servo ans gas hängen...

erik1563
01.09.2011, 12:28
Das Projekt läuft jetzt nicht mehr auf Basis eines Asuro, sondern auf einem Atmel Tiny13 Board. Weitere infos in Zukunft in diesem Thread: https://www.roboternetz.de/community/threads/54687-Atmel-Tiny-13V-als-Controller-f%FCr-einen-Dieselmotor?p=523641#post523641