Forum: Mikrocontroller und Digitale Elektronik Kommunikation zwischen Arduino und Flugcontroller


von Thomas E. (rc_flyer)


Lesenswert?

Ich versuche gerade, Daten vom Arduino Uno über den Pixhawk an 
QGroundcontrol zu senden.
An Bord meines Flugzeugs habe ich zwei NTC-Sensoren und einen 
RPM-Sensor, um Temperatur und Geschwindigkeit (rpm) zu messen.
Ich denke, Mavlink ist der richtige Weg, um die Daten vom Arduino zu 
meinem Pixhawk und dann zu QGroundcontrol zu senden, oder was denkt ihr?

Dies ist mein Arduino-Code:
1
#include <Thermistor.h>
2
#include <NTC_Thermistor.h>
3
// wiring: https://funduino.de/nr-54-ntc-temperatursensor
4
const int Sensor_Pin1 = A0;
5
const int Sensor_Pin2 = A1;
6
const int signalPin = 2;
7
8
#define Referenzwiderstand   10000 // 
9
#define Nominalwiderstand     10000 // 
10
#define Nominaltemperatur    25 // 
11
#define BWert                3950 // 
12
13
Thermistor* thermistor1;
14
Thermistor* thermistor2;
15
16
volatile unsigned long startMicros = 0;
17
volatile bool firstEdgeDetected = false;
18
19
void setup() {
20
  Serial.begin(9600);
21
  
22
  pinMode(signalPin, INPUT);
23
  attachInterrupt(digitalPinToInterrupt(signalPin), handleInterrupt, RISING);
24
  
25
  thermistor1 = new NTC_Thermistor(Sensor_Pin1, Referenzwiderstand, Nominalwiderstand, Nominaltemperatur, BWert);
26
  thermistor2 = new NTC_Thermistor(Sensor_Pin2, Referenzwiderstand, Nominalwiderstand, Nominaltemperatur, BWert);
27
}
28
29
void loop() {
30
  double celsius1 = 0;
31
  double celsius2 = 0;
32
33
  for (int i = 0; i <= 999; i++) {
34
    celsius1 += thermistor1->readCelsius();
35
    celsius2 += thermistor2->readCelsius();
36
  }
37
38
  celsius1 /= 1000;
39
  celsius2 /= 1000;
40
41
  Serial.print("Temperatur1: ");
42
  Serial.print(celsius1);
43
  Serial.print(" °C");
44
  Serial.print(" Temperatur2: ");
45
  Serial.print(celsius2);
46
  Serial.println(" °C");
47
48
  delay(100);
49
}
50
51
void handleInterrupt() {
52
  if (!firstEdgeDetected) {
53
    startMicros = micros();
54
    firstEdgeDetected = true;
55
  } else {
56
    unsigned long endMicros = micros();
57
    firstEdgeDetected = false;
58
    
59
    unsigned long timeBetweenEdges = endMicros - startMicros;
60
    float frequency = 1000000.0 / timeBetweenEdges;
61
    Serial.print("Frequenz: ");
62
    Serial.print(frequency);
63
    Serial.println(" Hz");
64
  }
65
}

von Εrnst B. (ernst)


Lesenswert?

Das "Serial.print" im "handleInterrupt" ist sehr ungünstig. Berechne da 
lieber nur deine "frequency", und mach die Ausgabe mit zu den anderen 
Ausgaben in der loop().


Dann könnte man noch in die Details gehen, z.B. startMicros und 
firstEdgeDetected müssen nicht volatile sein, könnten stattdessen 
"static" in's handleInterrupt.

Und du könntest, wie bei den Temperaturen auch, für die Frequenz einen 
durchschnitt über die letzten X Takte bilden.

: Bearbeitet durch User
von Thomas E. (rc_flyer)


Lesenswert?

Εrnst B. schrieb:
> Das "Serial.print" im "handleInterrupt" ist sehr ungünstig. Berechne da
> lieber..

Vielen Dank für die Anmerkungen, ich werde das in meinem Code anpassen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Εrnst B. schrieb:
> Das "Serial.print" im "handleInterrupt" ist sehr ungünstig.
Weil erstens die Echtzeit kaputt gemacht wird und zudem die 
SIO-Übertragung aus der Mainloop durch den Interrupt unterbrochen werden 
kann.

> Berechne da lieber nur deine "frequency"
Schon die Float-Berechnung dürfte den sehr ins Stolpern bringen. Ich 
würde also nur die Differenz der beiden Zeitstempel wegspeichern und den 
Rest in der Mainloop berechnen.

In der Mainloop ist zudem noch ein Fehler, der sich *delay(100)* nennt. 
Aber dazu kommen wir später, wenn irgendwas zusätzlich "nebenher" 
gemacht werden muss.

: Bearbeitet durch Moderator
von Thomas E. (rc_flyer)


Lesenswert?

Lothar M. schrieb:
> *delay(100)*

Ja, die typische Arduino Problematik :D
Ich sehe ihr seid deutlich erfahrener als ich, mir ging es zunächst ein 
mal darum den Code zum laufen zu bringen, Daten zu generieren und alles 
in eine Mavlink Message zu packen, woran ich leider bisher scheitere

von Rainer W. (rawi)


Lesenswert?

Εrnst B. schrieb:
> Berechne da lieber nur deine "frequency", und mach die Ausgabe mit zu
> den anderen Ausgaben in der loop().

Die Auswertung der Messdaten hat in der ISR nichts zu suchen. Da 
frequency sowieso nur für die Ausgabe benötigt wird, kann die genau dort 
unmittelbar vor der Ausgabe erfolgen.
Da du immer nur den Abstand zweier aufeinander folgender Pulse 
auswertet, kann es dir passieren, dass der Wert für die Drehzahl 
deutlich instabil ist - hängt davon ab, in welchem Drehzahlbereich du 
dich bewegst.
Stabiler wird der Wert, wenn du die Zeit für mehrere Umdrehungen 
auswertet. Häufiger, als du die Daten ablesen kannst, brauchst du 
sowieso keinen neuen Wert zu messen/übertragen.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Thomas E. schrieb:
> mir ging es zunächst ein mal darum den Code zum laufen zu bringen
Das sollte man sich dann im Zuge der Weiterentwicklung aber auch im Kopf 
behalten. Und rechtzeitig vom urschleimigen "Ablaufprogrammieren" (= 
das, was weiter oben steht, wird zuerst ausgeführt) ins Programmieren 
mit Zustandsautomaten (= Programmteile werden abhängig von 
Systemzuständen ausgeführt) übergehen.

Beim zweiten Programmierstil ist kein delay() nötig (weil Zeiten über 
einen Zeitstempel verwaltet werden) und Funktionen können deshalb an 
jeder Stelle der Mainloop zum Programmablauf hinzugefügt werden. Die 
Mainloop (und alle ihre Unterprogramme) wird jedes Mal ohne jegliches 
Warten möglichst schnell durchlaufen. Im Idealfall einige tausend Mal 
pro Sekunde.

: Bearbeitet durch Moderator
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.