Forum: Mikrocontroller und Digitale Elektronik Arduino Genuino 101 - Erfahrungen?


von Holger S. (xenophon)


Lesenswert?

Hallo,

es gibt ja die neuen Prozessoren von Intel, sollen kompatibel sein mit 
dem Arduino/Genuino Uno.

Nur sehr viel schneller. 10xgrößerer Speicher, 32 Mhz Taktrate und so 
weiter.

Mein Blick ist drauf gefallen, weil mein Arduino Uno mit einer Steuerung 
so an seiner Leistungsgrenze herumeiert, er ist einfach nicht sehr 
schnell.

Kann jemand aus eigener ERfahrung zu diesem Bord etwas sagen?

Insbesondere was Kompatiblität und SPeed angeht?

Würde ja andere Mitleser vielleicht auch interessieren.

Xenophon

von Peter S. (petersieg)


Lesenswert?

Hmm. Den ich habe hat meine ich 400MHz und riesig viel Ram und Flash. 
Ich nutze ihn aber aktuell als Linux System.
Als Arduino hatte ich ihn nur kurz mal getestet und wie kompatibel er 
wirklich ist..?
Muesste man ggf. mal ausprobieren..
Letzlich laeuft hier ein Linux System, das den Arduino Code ablaufen 
laesst..
Peter

von Zweifler (Gast)


Lesenswert?

Holger S. schrieb:
> es gibt ja die neuen Prozessoren von Intel, sollen kompatibel sein mit
> dem Arduino/Genuino Uno.
>
> Nur sehr viel schneller. 10xgrößerer Speicher, 32 Mhz Taktrate und so
> weiter.

Da gibt es noch viele Zwischenstufen, siehe Arduino MEGA2560, Arduino 
Due, STM32-Arduino o. ä.

Holger S. schrieb:
> Mein Blick ist drauf gefallen, weil mein Arduino Uno mit einer Steuerung
> so an seiner Leistungsgrenze herumeiert, er ist einfach nicht sehr
> schnell.

Hier sollte man sich fragen, ob das Programm/Sketch nicht noch durch 
wenige gezielte Eingriffe laufzeitoptimiert werden kann. Dazu muss man 
aber wissen, was bremst. Deine Aussage erweckt den Eindruck, als ob Du 
das nicht wüßtest, was wiederum darauf schließen läßt, dass da 
erhebliche Defizite bestehen und Optimierungspotential besteht.

Zeig doch mal Deinen Sketch.

von Holger S. (xenophon)


Lesenswert?

Zweifler schrieb:
> Hier sollte man sich fragen, ob das Programm/Sketch nicht noch durch
> wenige gezielte Eingriffe laufzeitoptimiert werden kann. Dazu muss man
> aber wissen, was bremst. Deine Aussage erweckt den Eindruck, als ob Du
> das nicht wüßtest, was wiederum darauf schließen läßt, dass da
> erhebliche Defizite bestehen und Optimierungspotential besteht.
>
> Zeig doch mal Deinen Sketch.


Kann ich heute abend nachreichen.

Ich weiß aber, was bremst. Es sind analogRead(), pulseIn() und 
Servo.write.

: Bearbeitet durch User
von Martin K. (maart)


Lesenswert?

Holger S. schrieb:

> Ich weiß aber, was bremst. Es sind analogRead(), pulseIn() und
> Servo.write.

delay (1000) bremst auch.

von Einer K. (Gast)


Lesenswert?

Holger S. schrieb:
> Es sind analogRead(),
Der ADC kann nebenläufig arbeiten.

Martin K. schrieb:
> pulseIn()
Kann evtl. mit Hilfe eines Timers auch nebenläufig gemacht werden.

von Stefan F. (Gast)


Lesenswert?

Bedenke, dass so ein AVR Mikrocontroller wesentlich mehr leistet, als 
ein C64 oder ein Gameboy, und die hatten ganze Videospiele ausgeführt!

Nutze die Gelegenheit, zu lernen, wie man performante Programme 
schreibt. Das Gelernte wird auch auf größeren Systemen hilfreich sein.

Oder muss das Projekt schnell fertig werden?

von Max123 (Gast)


Lesenswert?

101:
Ein PIN-doggeln braucht auch ohne delay() eine Milisekunde. Das
läuft offensichtlich über Linux.
Mich würde interessieren, wie man ein Programm direkt am 101 ausführt.

von Holger S. (xenophon)


Lesenswert?

Himmelherrgottsakra, ich stell da doch kein delay() rein! ;)

Wenn es das gäbe, würde ich eher das Gegenteil reinsetzen! ;)

Ich stell hier mal den Kern der Loop-Schleife rein. Darin ist alles 
enthalten, was Problem machen kann:
1
void loop() 
2
{
3
    if (zaehler_sensoren==0)
4
    {
5
        
6
        if (digitalRead(pin_sensor1)==LOW) sensordurchgang1=millis();
7
        if (digitalRead(pin_sensor2)==LOW) sensordurchgang2=millis();   
8
         if (sensordurchgang1>sensordurchgang2)vorlauf=sensordurchgang1-sensordurchgang2; else vorlauf=0;
9
         zsensor++; //zaehlt anzahl Zugriffe
10
         zaehler_sensoren=TAKT_SENSOREN;
11
    }
12
    else zaehler_sensoren --;
13
 
14
    if (zaehler_sender==0)
15
    {
16
        kanal1=pulseIn(pin_kanal1,HIGH);
17
        kanal2=pulseIn(pin_kanal2,HIGH);       
18
         zkanal++;
19
         zaehler_sender=TAKT_SENDER;
20
    }
21
    else zaehler_sender  --;
22
    if (zaehler_steuerung==0)
23
    {
24
        
25
          regler_1.write(90);
26
          regler_2.write(90); 
27
         zsteuerung++;
28
29
30
         zaehler_steuerung=TAKT_STEUERUNG;
31
    }
32
    else zaehler_steuerung --;

Erklärung:

Die Sensoren müssen häufig gemessen werden, ca. 400-500/sec. Für die 
Fahrtregler reichen 5-6/Sec.

Daher sind die I/O Funktionen in Schleifen gepackt. Die Frequenz für die 
Funktionen entspricht dem Kehrwert der Schleifen.

TAKT_SENSOREN=3000
TAKT_SENDER = 30000
TAKT_STEUERUNG=30000

Die Sensoren werden damit 10mal so oft abgefragt wie die Sendersignale.

Der ARduino macht mit diesem Grundgerüst ca. 140.000 
Programmdurchläufe/sec, die Sensoren werden ca. 400/sec abgefragt 
(Untergrenze), Sender 4-5 mal/sec.

Das Programm ist noch nicht fertig, daher wird die Frequenz von 140 kHz 
wohl noch abfallen. Bzgl. der Sensoren ist es an der Grenze.

Was würde das schnell machen?

Assembler für die Input-Abfragen

oder maschinennahe C-Befehle (z. B. PORT).

Dazu habe ich aber keinen Code gefunden, den man annähernd verwenden 
könnte, und mit Assembler und PORT muß man sich in der 
Prozessor-Architektur auskennen, was bei mir nicht der Fall ist.

Wäre die Hardware insgesamt ca. 10x schneller, gäbe es keine Probleme.

: Bearbeitet durch User
von Kaj (Gast)


Lesenswert?

Ich hab mal den Code etwas formatiert (fuer den geneigten Leser), das 
aber nur nebenbei:
1
void loop()
2
{
3
    if (zaehler_sensoren == 0)
4
    {
5
        if (digitalRead(pin_sensor1) == LOW)
6
        {
7
            sensordurchgang1 = millis();
8
        }
9
10
        if (digitalRead(pin_sensor2) == LOW)
11
        {
12
            sensordurchgang2 = millis();
13
        }
14
15
        if (sensordurchgang1 > sensordurchgang2)
16
        {
17
            vorlauf = sensordurchgang1 - sensordurchgang2;
18
        }
19
        else
20
        {
21
            vorlauf = 0;
22
        }
23
24
        zsensor++; //zaehlt anzahl Zugriffe
25
        zaehler_sensoren = TAKT_SENSOREN;
26
    }
27
    else
28
    {
29
        zaehler_sensoren--;
30
    }
31
32
    if (zaehler_sender == 0)
33
    {
34
        kanal1 = pulseIn(pin_kanal1, HIGH);
35
        kanal2 = pulseIn(pin_kanal2, HIGH);
36
        zkanal++;
37
        zaehler_sender = TAKT_SENDER;
38
    }
39
    else
40
    {
41
        zaehler_sender--;
42
    }
43
44
    if (zaehler_steuerung == 0)
45
    {
46
        regler_1.write(90);
47
        regler_2.write(90);
48
        zsteuerung++;
49
        zaehler_steuerung = TAKT_STEUERUNG;
50
    }
51
    else
52
    {
53
        zaehler_steuerung--;
54
    }
55
}

Holger S. schrieb:
> Die Sensoren müssen häufig gemessen werden, ca. 400-500/sec.
Dann nimm einen Timerinterrupt der alle 2ms ausloest.

Holger S. schrieb:
> Dazu habe ich aber keinen Code gefunden
Einfach mal ins Datenblatt von dem uC schauen: 
http://ww1.microchip.com/downloads/en/DeviceDoc/Atmel-42735-8-bit-AVR-Microcontroller-ATmega328-328P_Datasheet.pdf

In Kapitel 18 "I/O-Ports" findest du alles, was du brauchst, inkl. 
Codebeispiele fuer C und ASM, um I/O Pins anzusprechen.

Die Kapitel 16, 19, 20, 21, 22 und 28 koennten ebenfalls von interesse 
fuer dich sein.

Holger S. schrieb:
> Wäre die Hardware insgesamt ca. 10x schneller, gäbe es keine Probleme.
Der ATmega328P kann mit bis zu 20MHz laufen. Auf den Arduinoboards ist 
standardmaessig ein 16MHz Quarz verbaut. Wenn du also den Quarz 
austauscht...

von Ralph S. (jjflash)


Lesenswert?

Kaj schrieb:
> Wenn du also den Quarz
> austauscht...

... wird sein Bootloader nicht mehr funktionieren !

von Helmut H. (helmuth)


Lesenswert?

Ralph S. schrieb:
> ... wird sein Bootloader nicht mehr funktionieren !

... und abgesehen davon wird dann der eigentliche Engpass auch nicht 
schneller durchlaufen:
pulseIn() waits for the pin to go HIGH, starts timing, then waits for 
the pin to go LOW and stops timing.

Wie lang dauert denn ein pulseIn? Kommen da Servo-Signale mit 20ms?

Arduino F. schrieb:
>> pulseIn()
> Kann evtl. mit Hilfe eines Timers auch nebenläufig gemacht werden.

: Bearbeitet durch User
von Holger S. (xenophon)


Lesenswert?

Helmut H. schrieb:
> Ralph S. schrieb:
>> ... wird sein Bootloader nicht mehr funktionieren !
>
> ... und abgesehen davon wird dann der eigentliche Engpass auch nicht
> schneller durchlaufen:
> pulseIn() waits for the pin to go HIGH, starts timing, then waits for
> the pin to go LOW and stops timing.
>
> Wie lang dauert denn ein pulseIn? Kommen da Servo-Signale mit 20ms?
>
> Arduino F. schrieb:
>>> pulseIn()
>> Kann evtl. mit Hilfe eines Timers auch nebenläufig gemacht werden.

PulseIn() liest den Sender aus. Die Signale werden gemessen am 
Empfängereingang.

Die Messdauer ist 20 ms + x (ca. 21.2 ms).

Würde man pulseIn() einfach in die Loop-Schleife packen, würde er nichts 
anderes tun als diese Funktion auszuführen, wobei die Performance des 
Programms um 98 Prozent auf 2 Prozent absackt.

Wie gezeigt, reduziere ich die Zugriffe im Programm aber auf 5 
Zugriffe/Sec., so daß die Killerwirkung von pulseIn() damit praktisch 
aufgehoben ist.

Die Sensoren wurden getauscht von PNP auf NPN. Wie sich das zeitlich 
auswirkt, muß ich noch messen.

Insgesamt aber ist der Uno mit 500 Messungen am Sensor und 5 am Sender 
bereits an der OBergrenze dessen, was er leisten kann, und das Programm 
ist noch nicht komplett.

Eine schnellere Hardware wäre hier schon wünschenswert.

Ich hab den Genuino 101 mal bestellt, aus Neugier. Wg. Kompotibilität, 
Treiberproblemen etc. bzw. wenn man mal eine wirklich schnelle Schaltung 
baut.

Diese Schaltung kommt, wenn sie fertig ist, aus Platzgründen auf einen 
Arduino Nano. Es sei denn, es würde so nicht funktionieren.

: Bearbeitet durch User
von aSma>> (Gast)


Lesenswert?

Das hier ist widerum ein super Beispiel contra Arduino Jünger. Man kommt 
mit der Workframe ans Limit und anstatt es mithilfe Interrupts und 
Baremetal es zu lösen wird ein größerer µC geholt. Hust hust.

Mach mal digitalRead weg. Das bremst dich aus.

Weitere Tipps wurden dir schon gegeben.

von Einer K. (Gast)


Lesenswert?

aSma>> schrieb:
> Mach mal digitalRead weg. Das bremst dich aus.

Hier (m)eine Arduino Lib für schnelle Portzugriffe:
Beitrag "Welche AVR besitzen die PIN Toggle Fähigkeit?"

von Holger S. (xenophon)


Lesenswert?

aSma>> schrieb:
> Das hier ist widerum ein super Beispiel contra Arduino Jünger. Man kommt
> mit der Workframe ans Limit und anstatt es mithilfe Interrupts und
> Baremetal es zu lösen wird ein größerer µC geholt. Hust hust.
>
> Mach mal digitalRead weg. Das bremst dich aus.
>

Mit digitalRead werden die Sensoren ausgelesen. Meßzugriffe mindestens 
500/sek.

Den Tipp, das wegzumachen, kann ich irgendwie nicht ernst nehmen.

Machst du Scherze?

Woher bekomme ich dann die Sensor-Signale?

von Helmut H. (helmuth)


Lesenswert?

Das PulseIn dauert auch mit einem 40 EUR Quark-Mikrocontroller worst 
case 20+x ms
https://www.mikrocontroller.net/articles/Modellbauservo_Ansteuerung#Signalaufbau

Dabei ist es mit Pin Change Interrupt im Arduino Framework so einfach zu 
vermeiden:
http://www.benripley.com/diy/arduino/three-ways-to-read-a-pwm-signal-with-arduino/

von Peter D. (peda)


Lesenswert?

Holger S. schrieb:
> kanal1=pulseIn(pin_kanal1,HIGH);
>         kanal2=pulseIn(pin_kanal2,HIGH);

Holger S. schrieb:
> Wäre die Hardware insgesamt ca. 10x schneller, gäbe es keine Probleme.

Du irrst, die Hardware ist völlig unschuldig, es liegt allein an der 
Programmierung.

pulseIn ist nämlich blockierend, wie es in der Beschreibung steht:
"For example, if value is HIGH, pulseIn() waits for the pin to go 
HIGH, starts timing, then waits for the pin to go LOW and stops 
timing."

Schreib das um als Interrupt und schon rennt Dein Programm wie blöde.
Entweder ganz profan mit externen Interrupts oder mit Input-Capture des 
Timers.
Beim ATmega328 kann man das Input-Capture über den ADC-MUX und analog 
Komparator auf bis zu 8 Inputs umschalten, d.h. 8 Signale ganz ohne 
Warten messen (PC0..5, PB0, PD7) bzw. 10 beim SMD-Gehäuse (+ ADC6, 
ADC7).

von Stefan K. (stefan64)


Lesenswert?

Holger S. schrieb:
> Machst du Scherze?

Du sollst die Sensoren schon einlesen, aber nicht mit digitalRead(). Das 
ist zwar sehr praktisch für den Anfang, aber nicht besonders schnell. 
Wobei ich glaube, dass Dein Bottleneck nicht dort liegt, siehe den Post 
von Helmut.

Insgesamt sollte diese Aufgabenstellung einen ATmega zu höchstens 10% 
auslasten. Sogar mit Arduino.

Gruß, Stefan

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

aSma>> schrieb:
> Mach mal digitalRead weg. Das bremst dich aus.

Ich konnte keine Angaben dazu finden, wie lange das dauert.
Aber selbst, wenn ich 20 Takte ansetzte, wären das immer noch 800.000 
digitalRead/s. Das sollte daher auch nicht der Flaschenhals sein.

Was machen und wie lange dauern die beiden regler_X.write?
Und mehr ist doch in dem kleinen Progrämmchen nicht drin.

von Stefan K. (stefan64)


Lesenswert?

Nimm einfach die von Helmut vorgeschlagene Lib:

Helmut H. schrieb:
> Dabei ist es mit Pin Change Interrupt im Arduino Framework so einfach zu
> vermeiden:
> 
http://www.benripley.com/diy/arduino/three-ways-to-read-a-pwm-signal-with-arduino/

für alle Deine 4 Eingänge und schon ist Deine loop() praktisch leer. Und 
da die pin-change-Interrupts nur wirklich dann aufgerufen werden, wenn 
tatsächlich Pin Changes erfolgen, ist sogar digitalRead() nicht mehr 
notwendig und Dein Uno wird fast arbeitslos.

Gruß, Stefan

: Bearbeitet durch User
von Holger S. (xenophon)


Lesenswert?

@stefan @helmut u. a.

Vielen Dank für die guten Tipps!

Die Interrupts scheinen es wirklich zu bringen!

Das kannte ich bisher nicht.

WErde das heute abend ausprobieren und berichte dann wieder.

Xenophon

: Bearbeitet durch User
von Markus (Gast)


Lesenswert?

Library für ultrschnellen Pinzugriff auf dem Arduino:
https://github.com/mmarchetti/DirectIO

von Stefan F. (Gast)


Lesenswert?

Gewöhne Dir an, keine blockierenden Funktionen zu benutzen (dazu gehört 
auch delay()).

Das ist der kardinalfehler Nummer 1 in der Mikrocontroller 
Programmierung - ganz besonders im Arduino Umfeld weil dieses blöde 
Framework an allen Ecken und Kanten blockierende Funktionen 
bereitstsellt.

So sind z.B. beinahe alle Webserver im Arduino Umfeld nicht dazu fähig, 
mehrere HTTP Requests parallel abzuarbeiten, insbesondere wenn der 
HTTP-GET Request auf mehrere TXP Segmente aufgeteilt ist.

Aber auch viele Android Programme scheitern an solchen Konstrukten. Sie 
reagieren dann nicht auf Eingaben, wo sie es sollten und ziehen außerden 
noch den Akku unnötig schnell leer. Manche Android Apps stürzen ab, wenn 
die Netzwerk-Kommunikation länger als gewöhnlich dauert, und dadurhc zu 
lange in einer Warteschleife hängen.

Auch in Linux und Windows gelten blockierende Funktionen längst als 
No-Go.

Lerne, wie man ereignisgesteuerte Programme schreibt. Solche Programme 
warte niemals auf irgend etwas, sondern sie bearbeiten Ereignisse. Etwa 
so:
1
void loop()
2
{
3
   if (taste_gedrueckt()
4
   {
5
       reagiere_auf_Tastendruck();
6
   }
7
   if (signal_empfangen())
8
   {
9
       verarbeite_signal();
10
   }
11
   if (millis() >= mittagsPause)
12
   {       
13
       pausenklingel_aktivieren();
14
       // Nächste Mittagspause is morgen
15
       mittagsPause=millis()+24*60*60*1000;
16
   }
17
}

Bei Geräten mit Betriebsystem (wie dem ESP8266, Linux, Windows) stellst 
du auf diese Weise sicher, dass das System und andere Programme 
möglichst viel Rechenzeit ab bekommen und dass du selbst keine 
Rechenzeit in Warteschleifen verschwendest.

von Stefan F. (Gast)


Lesenswert?

Im falle deiner Singale und Interrupts bedeutet dies, dass du bei jedem 
Interrupt lediglich den zeitpunkt efasst und dann in der Hauptschleife 
mit den Messwerten arbeitest. Etwa so:

Bei Steigender-Flanke:
start=millis();

Bei fallender-Flanke:
ende=millis();
habeSignalGemessen=true;

und in der Hauptschleife:

if (habeSignalGemessen)
{
    unsigned long signalDauer=ende-start;
    // mach was draus
    habeSignalGemessen=false;
}

Und falls Dir der Millisekunden-Time rdazu nicht fein genug ist, dann 
verwendet einen anderen Timer, der z.B. in 1/10 Millisekunden hochzählt. 
Das kann der Chip ganz von alleine, man muss den Timer dazu nur 
initialisieren.

von Stefan F. (Gast)


Lesenswert?

Wenn du auf einem AVR 20ms wartest, verplemperst du 400.000 Befehle.
Wenn du auf einem PC 29ms wartest, verplemperst du 160.000.000 
Befehle(oder so ähnlich).

So oder so, hast du aber 20ms verplempert. Eine schnellere CPU ändert 
nichts an der Zeit, und löst somit dein Problem nicht.

von Holger S. (xenophon)


Angehängte Dateien:

Lesenswert?

Siegerehrung beim BOTTLENECK-Wettbewerb.


Abgeschlagen und völlig chancenlos auf dem letzten Rang:

digitalRead() mit 0 ms bei 100 Aufrufen


Zweiter und dennoch auch völlig chancenlos abgeschlagen:

Servo.write() mit 4 ms bei 100 Aufrufen.


Der absolute Champ, der die Konkurrenz in Grund und Boden gestampft hat:

pulseIn()

MIT SAGE UND SCHREIBE 69280 ms bei 100 Aufrufen.

Messanordnung: Alle Pins waren physisch belegt, das ist keine Messung an 
leeren Pins. Für den Sensor war ein NPN Sensor angeschlossen und aktiv, 
für den Sender eine Fernsteuerung mit Empfänger und für den Regler ein 
echter Fahrtregler.


Jetzt sagt Sherlock Holmes zu Dr. Watson:

Wir haben es hier nur mit einem üblen Kerl zu tun, die beiden anderen 
sind harmlos.


Aus dem, was ich jetzt durch die guten Tipps gelernt zu haben glaube, 
schließe ich, alles kann so bleiben, nur die beiden Aufrufe von 
pulseIn() müssen über Interrupt gesteuert werden.

Dafür würde sich die (programmiertechnisch) etwas einfachere Methode der 
attached Interrupts auf Pin 2 und 3 anbieten, bzw. würde die reichen, da 
die anderen Verdächtigen eben harmlos sind.

Jetzt müßte man nur noch außer dem Ereignis den PWM Wert des Signals 
auslesen. Wenn man dafür millis() braucht mit start und stop, kann ich 
nur sagen, der Aufruf der Funktion millis() ist auch zeitkritisch. Aber 
wenn man es nur aufruft, wenn es wirklich Sache ist, natürlich sehr viel 
weniger.

Das wär jetzt so der Plan.

Xenophon

Nachtrag:

Ich hab mir die PWM mal auf dem Oszi angeschaut. Signalwert ist die 
Flankenbreite.

Bild1: Frequenz des Gesamtsignals
Bild2: Sender Knüppel auf Anschlag
Bild2: Sender Knüppel Gegenseite

Flankenbreite zwischen 1000 und 2000 Mikrosekunden, plus/minus 
Überschüsse je nach Trimmhebel-Stellung. Beschriftung mit ms ist falsch, 
es muß heißen Mikrosekungen.

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Ich weiss nicht, wie genau du das Signal abtasten willst. Für normale 
Modellbau Servos genügen meiner Erfahrung nach 100 Werte für den ganzen 
Bereich (links bis rechts, feiner lassen sie sich ohnehin nicht 
ansteuern).

Also reicht ein 8bit Timer. Den auszulesen kostet beinahe gar nichts - 
nur einen Takt.

von Wolfgang (Gast)


Lesenswert?

Holger S. schrieb:
>> Mach mal digitalRead weg. Das bremst dich aus.
>
> Den Tipp, das wegzumachen, kann ich irgendwie nicht ernst nehmen.
Solltest du aber, wenn bei dir Prozessorleistung knapp ist.

> Machst du Scherze?
Hast du den Post Arduino Fanboy [1] nicht gelesen?

> Woher bekomme ich dann die Sensor-Signale?
Von den Ports natürlich. Hast du dir mal angesehen, was die 
Digitalread()-Funktion vom Arduino alles veranstaltet und wieviel Zeit 
das in Relation zu einem normalen Lesen vom Port dauert?

[1] Arduino F. schrieb:
> Hier (m)eine Arduino Lib für schnelle Portzugriffe:

von Holger S. (xenophon)


Lesenswert?

Stefan U. schrieb:
> Ich weiss nicht, wie genau du das Signal abtasten willst. Für normale
> Modellbau Servos genügen meiner Erfahrung nach 100 Werte für den ganzen
> Bereich (links bis rechts, feiner lassen sie sich ohnehin nicht
> ansteuern).
>
> Also reicht ein 8bit Timer. Den auszulesen kostet beinahe gar nichts -
> nur einen Takt.

100 Werte wären mehr als ausreichend.

Ganz glücklich wäre ich, wenn du als erfahrener mP Progger mir nur mal 
ein paar Beispielzeilen reinwerfen würdest, wie man den PWM-Wert des 
Signals am besten abcheckt.

Wie ich das jetzt sehe, spricht der Interrupt wahlweise an auf HIGH oder 
LOW, steigt dann bei Erreichen der Gegenflanke LOW bzw. bei HIGH wieder 
aus und man müßte dafür eine Zeitmessung selbst machen, weil der 
Interrupt das nicht zurückliefert.


Gruß Xenophon

von Forist (Gast)


Lesenswert?

Holger S. schrieb:
> sender_periode.png
> 1,99 MB
>
> sender_voll_rechts.png
> 2,4 MB
>
> sender_voll_links.png
> 2,21 MB

Hast du dich schon mal gefragt, was man wohl mit der USB-Buchse vorne 
links am Oszi anfangen kann?

Ich möchte fast wetten, dass dem dem Gerät darüber rattenscharfe und 
dazu auch noch handlich kleine PNG-Dateien zu entlocken sind und man 
nicht gezwungen ist, unter Mißachtung sämtlicher Hinweise beim Upload, 
Photos im dafür denkbar ungeeigneten PNG-Format zu posten.

von Holger S. (xenophon)



Lesenswert?

Forist schrieb:
> Holger S. schrieb:
>> sender_periode.png
>> 1,99 MB
>>
>> sender_voll_rechts.png
>> 2,4 MB
>>
>> sender_voll_links.png
>> 2,21 MB
>
> Hast du dich schon mal gefragt, was man wohl mit der USB-Buchse vorne
> links am Oszi anfangen kann?
>
> Ich möchte fast wetten, dass dem dem Gerät darüber rattenscharfe und
> dazu auch noch handlich kleine PNG-Dateien zu entlocken sind und man
> nicht gezwungen ist, unter Mißachtung sämtlicher Hinweise beim Upload,
> Photos im dafür denkbar ungeeigneten PNG-Format zu posten.


Mit den 2.x MB ist was falsch gelaufen. Das hab ich nicht gesehen.

Klar, daß man das auch kleiner liefern kann.

Ich werde mich bessern!  ;)

Xenophon

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Die AVR COntroller, die ich verwende können sowohl bei der steigenden 
als auch bei der fallenden Flanke einen Interrupt auslösen.

Zum Erfassen der Pulsbreiten gibt es reichlich konkreten Anleitungen im 
Netz

Ich brauchte 5 Sekunden, um diese Seite mit Google zu finden: 
http://www.camelsoftware.com/2015/12/25/reading-pwm-signals-from-an-rc-receiver-with-arduino/

Lies das und probiere es aus.

von Marco H. (damarco)


Lesenswert?

was würde die Sache schneller machen ?

A: ein besseres Programm
B: unter Einbeziehung der Möglichkeiten der Hardware
C: die Wahl der passenden Hardware.


Hierzu hilft es einen Plan zu machen was wann wie aufgerufen werden 
soll. Vom Timing schwierige Sachen lagert man auf die Hardware aus oder 
sorgt dafür das sie eingehalten werden. Dazu braucht das Programm eine 
Struktur und keinen zusammen gewurstelten Code.

Mit der Arduino Umgebung bist du schon mal schlecht beraten, da du kaum 
Kenntnis davon hast was da im Hintergrund passiert.

von Martin K. (maart)


Lesenswert?

Marco H. schrieb:
> Mit der Arduino Umgebung bist du schon mal schlecht beraten, da du kaum
> Kenntnis davon hast was da im Hintergrund passiert.

.....aber dafür ist es doch so schön einfach und schnell für die "Maker" 
zusammenkloppbar. ;-)

von Stefan F. (Gast)


Lesenswert?

Nach vielen gerede habe ich mir die Arduino IDE vor zwei Wochen mal 
angeschaut, mit dem ehrlichen Willen, damit ein echtes kleines 
Testprogramm zu schreiben.

Einen Tag später war ich wieder bei Netbeans.

Das Einzige, was mir an der Arduino IDE gefällt, ist der schnelle 
Einstieg, vor allem beim ESP8266. Ansonsten sehe ich nur Nachteile.

von Holger S. (xenophon)


Lesenswert?

Marco H. schrieb:
> was würde die Sache schneller machen ?
>
> A: ein besseres Programm
> B: unter Einbeziehung der Möglichkeiten der Hardware
> C: die Wahl der passenden Hardware.
>
>
> Hierzu hilft es einen Plan zu machen was wann wie aufgerufen werden
> soll. Vom Timing schwierige Sachen lagert man auf die Hardware aus oder
> sorgt dafür das sie eingehalten werden. Dazu braucht das Programm eine
> Struktur und keinen zusammen gewurstelten Code.
>
> Mit der Arduino Umgebung bist du schon mal schlecht beraten, da du kaum
> Kenntnis davon hast was da im Hintergrund passiert.

Hallo Marco,

ich besitze seit dem 11.4.2017 einen Arduino, gekauft bei ama__z0n

Zuvor hab ich noch niemals einen mC in der Hand gehabt oder mich damit 
beschäftigt oder wußte überhaupt, daß man sowas selbst programmieren 
kann.

Wir haben heute den 26.4.

Ich brauche nur eine Motorsteuerung für mein Modellboot und wollte nicht 
professioneller mC Programmierer werden.

Xenophon

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Marco H. schrieb:
> Mit der Arduino Umgebung bist du schon mal schlecht beraten

Kann man so nicht sagen, zum Einstieg ist es schon brauchbar.
Allerdings muß man berücksichtigen, daß die Arduino-Community eben kein 
professioneller Programmieranbieter ist, sondern viele Libs als Hobby 
entstehen. Daher kann man daran keine hohen Anforderungen stellen und 
sie können auch leicht viele Ressourcen verbrauchen.
Aber man kann es als Grundgerüst benutzen und kritische Funktionen 
anhand des Datenblattes besser implementieren. Oft findet man in der 
Community auch schon Beispiele dafür.

Auch muß man trotzdem erstmal das strukturierte Programmieren lernen, 
das nimmt einem auch kein anderes Tool ab. Ich hab auch mit den 
schlimmsten Spaghetticodemonstern angefangen, die ich nach einem Monat 
selber nicht mehr verstanden habe.

von Holger S. (xenophon)


Lesenswert?

Ich hab die Steuerung jetzt fertig. Die Motoren treiben auf jeder Seite 
3 Riemen an, mit denen sich das Schiff fortbewegt. Wenn die nicht 
synchron sind, schaukelt es elend hin und her. Mit dem Sender kann man 
das nicht koordinieren, daher mußte eine elektronische Regelung her. 
Wahl auf Arduino fiel, weil bei Ama__?zon "Bestseller". Millionen 
Fliegen können sich nicht irren. Oder?

https://www.youtube.com/watch?v=pRCdyDwQ8kY


Die pulseIn() Funktion hab ich in eine 30000er Zählschleife gepackt, die 
greift ca. 5x/Sekunde zu, kann keinen Schaden anrichten. Damit werden 
die Signale des Fernsteuerungs-Senders ausgelesen.

Die induktiven Näherungssensoren (NPN) werden mit einer Zählschleife von 
500 ausgelesen, macht ca. einige hundert Zugriffe /sec., reicht auch. 
Das Programm überschlägt keinen Durchlauf.

Der Arduino läuft mit einer einfachen Zählschleife mit 360 kHz 
(=Programmdurchläufe/Sek.).

Mit dem Programm bringt er ca. 100 kHz.

Also mein Projekt wäre soweit in Version 1.0 eigentlich fertig.

Trotzdem danke ich für die vielen Anregungen, man wird sich fortbilden 
müssen, um das Phänomen mP besser zu verstehen.

Xenophon

: Bearbeitet durch User
von Marco H. (damarco)


Lesenswert?

Mal ehrlich das kann nie funktionieren. Wenn du keine Ahnung hast vom µP 
warum löst du das nicht Analog ? Hierzu sollte es auch fertige Regler 
geben.

Du musst nicht nur den µP verstehen sondern auch wie Reglungen arbeiten. 
Des weiteren auch wie man sie Digital realisiert.

Die Aufgabe einen DC Motor synchron unter Belastung zu steuern ist für 
einen Anfänger schon recht hoch gegriffen.  Da sollte man auf fertige 
Lösungen zurückgreifen.

von Holger S. (xenophon)


Lesenswert?

Marco H. schrieb:
> Mal ehrlich das kann nie funktionieren.


Ich will nicht bestreiten, je mehr man von der Sache versteht, umso 
besser. Meine mC Laufbahn hat aber erst vor 3 Wochen begonnen.

Und daher ist die Frage nicht, wie man ein perfektes Programm schreibt, 
sondern ob das Programm die gestellte Aufgabe lösen kann.

Und das kann es definitiv.

Die Steuerung wurde heute nochmal überarbeitet und funktioniert 1a. Im 
Prinzip sind die Motoren schon aus dem Stand synchron.

Hier ist ein neues Video dazu von heute:

https://youtu.be/2Kb80-H4CDM


Wie ist das programmiert? Ohne Interrupts. Die wären wohl noch besser, 
muß ich mich aber erst einarbeiten. Programmstruktur:


Zählschleife Sensoren
    liest Sensoren aus digitalread()

Zählschleife Sender
    liest Sendersignal pulseIn()

Zählschleife Regler
    gibt Signal an den Fahrtregler  Servo.write()

Die Zählschleifen machen bei 0 für einen einzigen Zugriff auf, dann wird 
der Zähler hochgesetzt und muß neu runtergezählt werden. Dadurch kann 
man die Zugriffe takten.

Werte bei ca. 110 kHz:

Sensoren 500/sec
Sender 5/sec
Regler 5/sec

Die Sensoren überprüfen nicht die Motoren, sondern die Antriebe. Daher 
wäre es auch egal, wieviel Last auf die Mots kommt, oder ob der Antrieb 
Schlupf hat. Oder ob man eine Seite mit einer längeren Kette fahren 
will. Bleibt sich alles gleich.

Die gesamte Regelung findet mit 3 Programmzeilen statt, die hinter die 
Abfrage des linken Sensors gelegt wurden. Es sind die drei Zeilen, die 
hinter der Bedingung beide_voraus() stehen. Denn wenn nicht beide voraus 
stehen, bleibt die Regelung inaktiv.



          if (sensor_backbord==LOW)  // NPN Sensor schaltet auf Masse
          {
             durchgang_backbord=millis();  // höchster Zeitwert
             vorlauf=durchgang_backbord-durchgang_steuerbord;
             if (vorlauf>umlaufzeit)vorlauf=umlaufzeit;
               // Falls eine Messung durchrutscht
1
             if (beide_voraus()==TRUE)  // Sendersignal beide voraus
2
             {
3
                  if(vorlauf>TOLERANZ&&vorlauf<(umlaufzeit-TOLERANZ))
4
                  {
5
                    if (vorlauf<halbe_umlaufzeit) 
6
                                bremse_steuerbord((vorlauf));
7
                    else bremse_backbord(((umlaufzeit-vorlauf))  );
8
                    }
9
             }
10
          
11
          }

Halbe Umlaufzeit: der andere Antrieb läuft die halbe Umlaufzeit weg, 
danach kommt er ja aber wieder zurück. In der ersten Hälfte muß er 
stoppen, läuft er zurück, muß der andere Motor stoppen.

Also, es funktioniert prima. Was mich nicht daran hindern wird, mich 
weiter mit der mC Programmierung zu beschäftigen. Als nächstes wären mal 
die Interrupts dran.

Xenophon

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Jeder noch so kleine Arduino reicht auf jeden Fall aus, um mehrere 
Motoren zu regeln. Jetzt kristallisiert sich deutlich heraus, dass dein 
Problem defintiv nicht zu schwache Hardware ist, sondern an der Software 
liegt.

> Millionen Fliegen können sich nicht irren. Oder?

Genau. Schau Dir mal an, was Leute mit einem Asuro so alles anstellen. 
Der wird gerne verwendet, um genau das, was du brauchst, zu erlernen.

von Marco H. (damarco)


Lesenswert?

Das funktioniert trotzdem nicht. Da du die Belastung der Motoren nie mit 
so geringen feedback regeln kannst.  In der Praxis ist die Belastung 
unkalkulierbar. Dein Gefährt fährt sonst wo hin, nur nicht da hin wo es 
soll.

Selbst wenn die Motoren wirklich synchron sind, funktioniert das auch 
nicht ohne die Position des Bootes mit in die Reglung einzubeziehen.

Das Steuern ist auch viel zu grob um Abweichungen zu korrigieren, das 
gelingt auch nicht aus der Ferne.

Verstehe der Impuls für einen Umlauf ist viel zu grob im Verhältnis des 
Fehlers der sich aus den Schleifen ergibt. So das eine Reglung auf diese 
Art nicht möglich ist.  Immer dann wenn sich in deine Schleife eine 
Bedingung ändert, ändert sich auch das Zeitverhalten.

Vergleich das Problem mit einen quadcopter dessen Reglung ist ähnlich 
komplex. Das erfordert eine ganze Menge wissen damit dieses Ding so 
fliegt.

von Helmut H. (helmuth)


Lesenswert?

Holger S. schrieb:
> Also, es funktioniert prima. Was mich nicht daran hindern wird, mich
> weiter mit der mC Programmierung zu beschäftigen.

Finde ich gut dass du dich da durchgebissen hast und es so läuft wie du 
es dir vorstellst.

von Holger S. (xenophon)


Lesenswert?

Helmut H. schrieb:
> Holger S. schrieb:
>> Also, es funktioniert prima. Was mich nicht daran hindern wird, mich
>> weiter mit der mC Programmierung zu beschäftigen.
>
> Finde ich gut dass du dich da durchgebissen hast und es so läuft wie du
> es dir vorstellst.

Vielen Dank Helmut! Ich bin hier so niedergeknüppelt worden, da zählt 
das doppelt!  ;)

Aaaaaaaaaaaaaaaaaaaaaaaaaber:

Ich merk mir natürlich auch Kritik und arbeite dran. Daher habe ich 
jetzt das Programm modifiziert.

Die pulseIn() sind raus, statt dessen attachedInterrupt

Es geht ja darum, die Flankenbreite von 2 PWM SIgnalen zu bestimmen. Das 
sieht jetzt so aus:
1
volatile int sender_backbord=0;
2
volatile int sender_steuerbord=0;
3
volatile int prev_time1=0;
4
volatile int prev_time2=0;
5
6
attachInterrupt(0,steigend1,RISING);
7
attachInterrupt(1,steigend2,RISING);
8
9
void steigend1(){
10
  attachInterrupt(0,fallend1,FALLING);
11
  prev_time1=micros();
12
}
13
void fallend1(){
14
  attachInterrupt(0,steigend1,RISING);
15
  sender_backbord=micros()-prev_time1;
16
}
17
void steigend2(){
18
  attachInterrupt(1,fallend2,FALLING);
19
  prev_time2=micros();
20
}
21
void fallend2(){
22
  attachInterrupt(1,steigend2,RISING);
23
  sender_steuerbord=micros()-prev_time2;
24
}


Was ist nun der Effekt von der Sache?

Gemessen mit pulseIn() macht das Programm 110000 Programmdurchläufe/sec, 
ich sage dazu 110 kHz

pulseIn gegen die Interrupts ausgetauscht, beträgt die Frequenz 146 kHz.

Das ist ungefähr 40% schneller. NIcht sehr viel schneller.

Das zeigt, daß die ursprüngliche Programmierung, das pulseIn() in eine 
Zählschleife einzusperren, nicht soooooooo schlecht war.

Wir haben mit den Interrupts zwar jetzt das Signal alle 20 ms neu, und 
wenn man eine zeitkritische Steuerung hätte, wäre das prima.

Allerdings um die Bootsmotoren zu steuern, reichen mir 5 
Aktualisierungen pro sec. locker aus. Viel mehr kann man am Sender auch 
gar nicht anstellen. Wenn man allerdings einen Heli steuern müßte, wären 
die Interrupts Pflicht.

Was weitere Interrupt maximal bringen könnten, kann man messen.

Man klammert die fraglichen Funktionen einfach aus.

Dann läuft das Programm um soviel schneller, als dem Zeitaufwand durch 
diese Funktionen entspricht.

So kann ich also sagen, wenn ich die Sensoren (digitalread())auch noch 
mit Interrupts auslesen würde, daß dann die Performance von 146 auf 207 
kHz steigen würde. Das wär fast doppelt so schnell wie ganz ohne 
Interrupts, und man wüßte genau, daß keine Messung "durchflutscht".

Problem jetzt aber: attachedInterrupt() hat nur die Pins 2+3, und die 
sind bereits vergeben.

Also weiter zu PinChangeInterrupts. Die sollen aber nicht so schnell 
sein wie Attached.

Kann man beide Methoden parallel verwenden?



Xenophon

: Bearbeitet durch User
von Helmut H. (helmuth)


Lesenswert?

Holger S. schrieb:
> Gemessen mit pulseIn() macht das Programm 110000 Programmdurchläufe/sec,

Das sagt nicht viel, da das Ausmessen eines Pulse wie oben gezeigt über 
20 ms dauern kann.
Bei der Interrupt Lösung kostet das praktisch nichts. in sender_backbord 
oder _steuerbord steht immer der zuletzt gemessene Wert.

Wenn ich es richtig verstehe werden die Sensoren für die Lage der Riemen 
nur etwa alle zwei Sekunden angesprochen, Es bringt also nichts jetzt 
noch Digital-in zu beschleunigen. Eine ms-genaue Messung ist bei der 
relativ langsamen Mechanik sowieso nicht erforderlich.

Würde mal einen Ablauf skizzieren
* die Regelung greift nur bei Voller Fahrt Voraus und wird sofort 
abgeschaltet wenn dies nicht mehr der Fall ist.
* der Stellwert für die Motoren wird für einen Pull eingestellt. 
Dazwischen bringt eine Änderung nichts, da der aktuelle Wert der 
Riemenstellung nicht bekannt ist.
* Also Synchronisieren, d.h. die vorlaufende Seite wird angehalten bis 
das Signal der anderen Seite erkannt wurde
 Beide Motore volle Fahrt voraus
 Wenn ein Sensor anspricht, den entsprechenden Motor anhalten
 Wenn dann der andere Sensor anspricht, beide Motoren volle Fahrt voraus 
stellen
* Jetzt etwas Zeit totschlagen, damit die Sensoren sich wieder beruhigen

Das kann man via State-Machine oder mit Zustandsvariablen lösen.

Regelung
    Motoren links(backbord) und rechts(steuerbord) auf volle Fahrt.
    links_erkannt=FALSE
    rechts_erkannt=FALSE
    starte_pull=FALSE

    Schleife:
        Prüfe sender_*, ggf  Regelung beenden
// Beginn Sync
        Wenn starte_pull==FALSE:
            Wenn linker Sensor LOW:
                Wenn rechts_erkannt==TRUE:
                    starte_pull=TRUE
                Sonst:
                    links_erkannt=TRUE
                     Motor links Halt
            Wenn rechter Sensor LOW:
                Wenn links_erkannt==TRUE:
                    starte_pull=TRUE
                Sonst:
                    rechts_erkannt=TRUE
                    Motor rechts Halt
            Wenn starte_pull==TRUE:  // hier wird ein Pull gestartet
                Endezeit = aktuelle Zeit + z.B. 0.5 sec
                beide Motoren volle Fahrt voraus
// Ende Sync
// Zeit nach Sync
        Wenn starte_pull==TRUE
            Wenn aktuelle Zeit > Endezeit:
                starte_pull=FALSE
                links_erkannt=FALSE
                rechts_erkannt=FALSE

von Holger S. (xenophon)


Lesenswert?

Helmut H. schrieb:

> Wenn ich es richtig verstehe werden die Sensoren für die Lage der Riemen
> nur etwa alle zwei Sekunden angesprochen, Es bringt also nichts jetzt
> noch Digital-in zu beschleunigen.

Wie wahr, wie wahr.

Zunächst: um den Durchgang innerhalb dieser 2 Sekunden zu erwischen, muß 
man ca. 500mal/sec. die Sensoren an der Kette abfragen, weil die Kette 
mit ca. 250 mm/sec durchläuft.

Ich habe neben dem attachtedInterrupt() zur Messung der PWM-Signale des 
Senders nun noch einen PinModeChangeInterrupt für 2 Pins dazugenommen, 
um die Sensoren an der Kette einzulesen.

Darf man beide Interrupt-Methoden nebeneinander verwenden? Weiß ich 
nicht. Jedenfalls, es funktioniert, die Werte stimmen. Für den Durchgang 
der Sensoren liefert er Mikrosekunden zurück.

Für die Performance bringt das aber gar nichts. Mit digitalRead alle 
1/500 sec. macht das PRogramm 146 kHz, mit den zusätzlichen Interrupts 
für die Sensoren sind 152 KHz.

Wenn die Interrupts nichts kosten, müßte er (= der Chip) eigentlich ca. 
50 kHz schneller sein. Das ist die Differenz, wenn man im alten Programm 
die Sensoren komplett rausnimmt. Ist er aber nicht.

Während die ersten beiden Interrupts als Ersatz für pulseIn() ca. 45 kHz 
gebracht haben.

Jedenfalls, so bringt es nichts. Entweder hab ich falsch programmiert, 
oder die beiden Interrupt-Methoden nebeneinander behindern sich 
irgendwie, oder es bringt eben nichts (werde es wohl wieder 
herausnehmen). Hier ist der Code für die beiden zusätzlichen Interrupts:

1
#define PIN_SENSOR_BACKBORD 7
2
#define PIN_SENSOR_STEUERBORD 8
3
4
5
volatile unsigned long durchgang_backbord=0;
6
volatile int sensor_backbord=0;
7
volatile unsigned long durchgang_steuerbord=0;
8
volatile int sensor_steuerbord=0;
9
10
uint8_t latest_interrupted_pin;
11
12
void setup()
13
{
14
15
// .............. Auszug:
16
17
18
pinMode(PIN_SENSOR_BACKBORD,INPUT_PULLUP);
19
PCintPort::attachInterrupt(PIN_SENSOR_BACKBORD,&sensor_bb_fallend,FALLING);
20
pinMode(PIN_SENSOR_STEUERBORD,INPUT_PULLUP);
21
PCintPort::attachInterrupt(PIN_SENSOR_STEUERBORD,&sensor_stb_fallend,FALLING);
22
}
23
24
25
void sensor_bb_fallend() {
26
  latest_interrupted_pin=PCintPort::arduinoPin;
27
  durchgang_backbord = micros();
28
}
29
void sensor_stb_fallend() {
30
  latest_interrupted_pin=PCintPort::arduinoPin;
31
  durchgang_steuerbord = micros();
32
}

Gruß Xenophon

: Bearbeitet durch User
von Helmut H. (helmuth)


Lesenswert?

Holger S. schrieb:
> Zunächst: um den Durchgang innerhalb dieser 2 Sekunden zu erwischen, muß
> man ca. 500mal/sec. die Sensoren an der Kette abfragen, weil die Kette
> mit ca. 250 mm/sec durchläuft.

Ist ja kein Problem, das schafft die oben skizzierte Regelung mit 
digitalRead() locker.
Die Sensoren sind wahrscheinlich auch länger als 2 ms LOW wenn die Kette 
vorbeiläuft. Vielleicht kannst du das Signal mal auf dem Scope 
anschauen, ich befürchte es prellt, dann würden die Interrupts mehrfach 
aufgerufen.

NB: Wenn Du den Zeitpunkt eines Durchlaufs speichern willst, merke dir 
oben die micros();, z.B.
Wenn linker Sensor LOW:
  ...
              Sonst:
                    links_erkannt=TRUE
                    durchgang_backbord =  aktuelle Zeit
                    Motor links Halt

Natürlich kostet die Interruptverarbeitung auch Zeit, aber imho deutlich 
weniger als 1 ms und das hängt nicht von der Länge und Lage des zu 
messenden Signals ab. Zudem werden während des PulseIns() eventuell 
einkommende Sensorsignale nicht erkannt.

: Bearbeitet durch User
von Peter D. (peda)


Lesenswert?

Holger S. schrieb:
> Darf man beide Interrupt-Methoden nebeneinander verwenden?

Natürlich. Nur für den selben Pin wäre es quatsch.
Beim Pin-Change muß man aber selber die Flanke ermitteln mit einer 
Schattenvariable für den vorherigen Wert bzw. bei mehreren Pins je 
Interrupt auch noch den Pin.

Ich benutze keine Arduinos, kann also nicht einschätzen, was genau Dein 
Code macht.
Als ich 1997 mit AVRs angefangen habe, gabs lange noch keine Arduinos. 
Die alten Hasen kennen daher die Arduino-Libs nicht, sie machen alles 
bare-metal direkt nach Datenblatt. In der Registerbeschreibung steht ja 
kurz und knackig zusammengefaßt die Bedeutung jedes Bits.

Ich bin mir auch nicht sicher, ob die Doku zu den Arduino-Libs umfassend 
genug ist, bzw. ob man sie überhaupt versteht, ohne im Datenblatt 
gelesen zu haben.

von Stefan F. (Gast)


Lesenswert?

Die Doku von Arduino ist .... knapp. Viele Details erfährt man nur durch 
Ausprobieren oder Quelltext+Datenblatt lesen.

Deswegen halte ich auch nicht viel von ihnen.

Aber was die Arduino Jungs richtig gut hinbekommen haben, ist der 
schnelle Einstieg - vor allem beim ESP8266 war es für mich hilfreich.

von J. T. (chaoskind)


Lesenswert?

Klasse Projekt!!!  Nach den Videos der Mechanik bin ich auf das Video 
der Jungfernfahrt gespannt.

Ich hab mir auch mal ein "Böötchen" gebastelt und dort nahezu alles mit 
nem Atiny2313 gesteuert. Dein Ruderboot wurde es aber vermutlich 
stehenlassen. Ich hab da bei der Motorisierung wohl ein wenig 
übertrieben :D das gute Stück ist knapp 1m lang und mit 2mal 1.8kW 
(BLDC)bestückt. Wenn ich den Hebel schlagartig aufn Tisch leg, springt 
es komplett aus dem Wasser. Der Rumpf ist mir auch nicht wirklich gut 
als Gleiter gelungen. Aber beeindruckend ist das schon und die Motörchen 
brüllen ein infernalisches Duett. Evtl auch die Schrauben ich bin da 
nich vom Fach.

So genuch gefaselt, sorry fürs OT, und immer ne Handbreit Wasser untern 
Kiel

von Holger S. (xenophon)


Lesenswert?

Helmut H. schrieb:
> Die Sensoren sind wahrscheinlich auch länger als 2 ms LOW wenn die Kette
> vorbeiläuft. Vielleicht kannst du das Signal mal auf dem Scope
> anschauen, ich befürchte es prellt, dann würden die Interrupts mehrfach
> aufgerufen.

Das Prellen würde erklären, warum da kein Zugewinn in der Performance 
stattfindet.

Da werde ich mal nachschauen.

Andererseits sind die Interrupts mit PinModeChange ja softwaremäßig mit 
Library, plus daß der Port intern nochmal feststellen muß, welcher Pin 
ausgelöst hat,

zusammengefaßt wahrscheinlich um Längen langsamer als die hardwaremäßig 
fest eingebauten AtttachInterrupts.

Xenophon

von Holger S. (xenophon)


Lesenswert?

J. T. schrieb:
> Klasse Projekt!!!  Nach den Videos der Mechanik bin ich auf das Video
> der Jungfernfahrt gespannt.
>


Sie war schon im Wasser, aber ohne Synchronsteuerung.

Deshalb eiert sie mehr rum als daß sie rudert.

Mit der Fernsteuerung kriegt man es  nicht hin.

So sieht es bis jetzt aus (ohne Synchro):

Video ---------------------------------------------------

https://www.youtube.com/watch?v=F4RVWzIqqHU&t=3s

/Video -----------------------------------------------------


Xenophon

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

Danke für den Link, hab es auch grad so entdeckt :D.
Hab auch noch ein 2tes gefunden wo es im Wasser ist. Da stand ein Text 
von wegen "jetzt 2,5kg leichter".
Rein intuitiv hät ich gedacht, um so schwerer, um so weniger anfällig 
müsste es für das "rumgeeiere" sein. Was war da dein Gefühl? War es nach 
der Diät schlimmer oder besser?

Nebenbei bemerkt eiert es viieeel weniger als ich gedacht hätte. Ich 
hatte als lütter Steppke mal son Plastikboot mit Aufziehmotor, das hatte 
einen starren von Haus aus also synchronisierten "2-Ruder-Antrieb". Das 
war nur am Eiern. Da hat es gelangt wenn die Paddel aufgrund minimaler 
Wellen in der Badewanne nicht exakt gleichtief eingestochen haben, um 
das Ding gefühlt auf der Stelle drehen zu lassen.

Hast du den Rumpf auch selbst gebaut oder ist das was fertiges? Wenn da 
noch ein genauso schöner Aufbau draufkommt, echt top. Oder wolltest du 
deine schöne Rudermechanik offenlaufen lassen, so dass man sie auch im 
Betrieb bewundern kann? :D

MfG Chaos

von J. T. (chaoskind)


Lesenswert?

P.S.

Lässt sich an der Mechanik eigentlich einstellen, wie weit die Ruder 
auschlagen? Also dass die "Endrollen" quasi verschiebbar sind? Oder wär 
dass ganze dann zu aufwändig geworden? (Kettenspanner usw?)

von Holger S. (xenophon)


Lesenswert?

@chaoskind

Womit wir hier jetzt ganz vom Thema ab wären, aber was soll´s, ist ja 
Hobby.

Die nackte Rumpfschale ist aus ABS, den hab ich als Ersatzteil gekauft. 
Alles andere ist Eigenbau.

Selbstverständlich, wenn das Schiff fertig ist, ist von der 
Rudermechanik nichts mehr zu sehen. Da kommen geschlossene Decks drauf. 
Außerdem soll es ja ein Segelschiff werden, es kommt auch noch ein Rigg 
drauf. Das wär auch alles schon erledigt, wenn ich nicht so lange bei 
den Ruderantrieben hängen geblieben wäre.

Rudermechanik: Der innere Hebel ist begrenzt durch den Abstand 
Antrieb->Bordwand. Den kann man nicht vergrößern.

Die Bahn, welche die Ruder beschreiben, entspricht in Länge und Umfang 
dem Kettentrieb. Man kann die Kette in der Länge ändern (Abstand der 
Zahnräder) oder den Radius des Mitnehmers bezogen auf die Mitte der 
Zahnräder. Im Video ist die Höhe zu knapp, der Mitnehmer wurde daher im 
Radius vergrößert, also mehr nach außen gesetzt. Er sitzt jetzt Höhe 
Kette.

Zum Gewicht:

Alles Gewicht muß so weit wie möglich Mitte und Unten sitzen. Da braucht 
es Ballast. Daher hat es einen 2 kg schweren Kiel aus VA-Stahl. Das 
Gewicht oberhalb und seitlich verschlechtert die Stabilität. Mit den 11 
kg vorher war das Schiff überladen und träge. Es wäre, mit Segel drauf, 
bei der ersten Böe direkt abgesoffen. ;)

Daher wurden die (schweren) Zahriemenantriebe getauscht gegen 
Kettenantriebe, die ca. 1,5 kg leichter sind, sowie sonstwie noch 1 kg 
eingespart. Das kennt man vom Modellfliegen, Kampf um jedes Gramm, aber 
beim Schiff gilt das dann irgendwann auch.

Insgesamt bin ich kein Freund von ABS oder GFK. Wenn das alles so fertig 
ist, daß es läuft, werd ich das Ganze nochmal komplett mit einem 
Holzrumpf aufbauen.

Der ABS Rumpf dient jetzt nur als Arbeitsplattform.


-------------------------------------------------------------
Nun zu der Synchronsteuerung:

Nach der Hereinnahme der Interrupts lief die Regelung instabil. Das 
Programm machte sogar öfter mal den Totalabsturz, und das bei laufenden 
Motoren. Man stelle sich das mal im realen Betrieb vor!

Ich hab das jetzt alles nochmal neu programmiert und ganz ohne 
Interrupts. Die brauche ich nicht, weil:

Sendersignal abfragen alle 0,2 Sekunden = nicht zeitkritisch

Reglersignal geben alle 0,2 Sekunden = nicht zeitkritisch

Sensor abfragen 500x pro Sek. = nicht zeitkritisch

Ich brauch keine Signale, die alle 20 ms oder jede ms aktualisiert 
werden, wenn ich nur alle 200 ms drauf zugreife.

Dazu kommt, daß der Sensor prellt. Der Durchgang des Mitnehmers am 
Sensor dauert ca. 32 ms. In der Zeit greift das Programm mit Interrupts 
einen Haufen Prellsignale ab. Die müßte man dann softwaremäßig praktisch 
in eine Warteschleife packen oder sonderbehandeln, ich will jetzt nicht 
sagen delay(), aber z. B. Filtern, um den unerwünschten Speed wieder 
herauszukriegen. ALso man muß die schnellen Signale wieder langsam 
machen, das macht nicht wirklich Sinn.

Natürlich ist es ohne Interrupts möglich, daß mal ein Sensordurchgang 
nicht erfaßt wird. Das bemerkt man, wenn der Vorlauf der Antriebe größer 
wird als die Umlaufzeit. Ist aber kein Problem:

if (vorlauf<=umlaufzeit&&vorlauf>0) // bei Meßfehler nichts machen
  {
      dann mach was, nämlich regeln
  }


Ob die Instabilität letztlich von den Interrupts kam, weiß ich nicht. 
Ich weiß nur, jetzt ist sie weg.

Das Programm macht jetzt 100 kHZ mit den Parametern:

500 Zugriffe/sec. auf die Sensoren
5 Zugriffe/sec. auf Sender und Reglersignale.

Die Steuerung der Zugriffe erfolgt mit Zählschleifen, die einmal 
aufmachen und dann wieder neu herunterzählen.

Man könnte die Schleifen natürlich auch mit millis() takten, der Aufruf 
von millis() ist aber keine gute Idee, weil der die Performance nach 
unten drückt, aber kräftig. Es fast so schlimm wie pulseIn().

Das Programm funktioniert jetzt absolut fehlerfrei, keine 
Programmabstürze mehr.

Auf dem Arduino Nano. Der ist ja kein Rennpferd.

Mehr braucht es jetzt nicht, um das Problem zu lösen.

Xenophon

: Bearbeitet durch User
von Markus (Gast)


Lesenswert?

Wenn man bedenkt, dass Du am Anfang einen Arduino 101 mit 32Mhz nehmen 
wolltest und jetzt das Ganze doch mit einem 16Mhz Arduino läuft ...

Meiner Erfahrung nach braucht man für mechanische Regelungen sowieso 
keine hohen Abtastraten. Meistens reicht eine Zykluszeit von 10ms aus.

von J. T. (chaoskind)


Lesenswert?

Holger S. schrieb:
> Das
> Programm machte sogar öfter mal den Totalabsturz, und das bei laufenden
> Motoren. Man stelle sich das mal im realen Betrieb vor!

Da kann ich auch ne kleine Anekdote erzählen. Bei meinem ersten Boot, da 
hatte ich versucht, nen Fahrtregler selbst zu bauen, lief im trockenen 
alles wunderbar. Also ab aufn See. Langsam losgetuckert, dann knapp in 
der Mitte mal Vollgas gegeben. Abgestürzt. Zum Glück lag der See luv von 
mir :D. Nach ca ner halben Stunde kam es dann wieder angetrieben... Naja 
letzendlich hab ich eingesehen, dass ich es scheinbar nicht hinbekomme, 
den Motor so zu entstören, dass er bei Volllast nicht alles zudreckt, 
oder meinen Fahrtregler unempfindlicher zu bekommen, als das gute Stück 
mit Vollgas ins Ufer raste, auf nix reagierte, und der Motor dann in 
Flammen stand, als ich letzendlich am Boot ankam. :D Da hab ich dann 
doch auf nen fertigen Fahrtregler zurückgegriffen, muss ich eingestehen.

Holger S. schrieb:
> Das Programm funktioniert jetzt absolut fehlerfrei, keine
> Programmabstürze mehr.

Ja dann herzlichen Glückwunsch zu deinen rasanten 
Programmierfortschritten!!
Und wo is nun läuft, ist ja wirklich nicht so dramatisch, wenn wir ein 
wenig OT geworden sind ;)

Und ein Holzrumpf wäre definitiv Stilechter, da haste meine volle 
Unterstützung und Fürsprache :D ich bin auch kein Freund von ABS und Co. 
Meine sind alle aus Blech handgeformt. Schweinearbeit, und irgendwie 
auch gar nicht so einfach, das hinzubekommen, was man sich vorgestellt 
hat.

Ich würd mich freuen, wenn du hier weiter über den Verlauf von dem 
Projekt berichtest! Und dank dir, für die Zusammenfassung.

Frohes Basteln,
Chaos

: Bearbeitet durch User
von Stefan F. (Gast)


Lesenswert?

Ist meinem Vater schonmal mit einem Nitro R/C Auto passiert. Das knallte 
mit Vollgas am Ende von zwei Feldern gegen einen Bauernhof und brannte 
dort aus. Leider war das Spektakel so weit weg, dass niemand zuschauen 
konnte - außer der Bauer.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.