Kommunikation zwischen Arduino und Flugcontroller

OP #7512755
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
}
#7512763
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.

Moderator (Firma: Titel) Persönliche Seite #7512828
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.

#7512956
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.

Moderator (Firma: Titel) Persönliche Seite #7513187
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren