„doc/Arduino“ ändern
parent
b4e32782f6
commit
5eca2f642a
284
doc%2FArduino.md
Normal file
284
doc%2FArduino.md
Normal file
@ -0,0 +1,284 @@
|
|||||||
|
# Arduino
|
||||||
|
Hier befindet sich das gesamte Arduino-Projekt, zum iTender Proxy.
|
||||||
|
|
||||||
|
|
||||||
|
## Full-Code
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* Official proxy code for iTender GPIO Communication
|
||||||
|
**/
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include "HX711.h"
|
||||||
|
|
||||||
|
// Define the size of the JSON buffer
|
||||||
|
#define JSON_BUFFER_SIZE 256
|
||||||
|
|
||||||
|
// Create a JSON object for incoming messages
|
||||||
|
StaticJsonDocument<JSON_BUFFER_SIZE> incomingJson;
|
||||||
|
|
||||||
|
// Create a JSON object for outgoing messages
|
||||||
|
DynamicJsonDocument outgoingJson(JSON_BUFFER_SIZE);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
// Initialize serial communication
|
||||||
|
Serial.begin(9600);
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*resetFunc)(void) = 0; //declare reset function @ address 0
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
// Wait for a new line on the serial console
|
||||||
|
if (Serial.available()) {
|
||||||
|
// Read the incoming JSON message
|
||||||
|
DeserializationError error = deserializeJson(incomingJson, Serial);
|
||||||
|
if (error) {
|
||||||
|
// Handle error
|
||||||
|
} else {
|
||||||
|
// Extract the "type" and "data" fields from the JSON object
|
||||||
|
String id = incomingJson["id"];
|
||||||
|
int type = incomingJson["type"];
|
||||||
|
JsonVariant data = incomingJson["data"];
|
||||||
|
|
||||||
|
// Create a nested object in the root object
|
||||||
|
JsonObject outgoingData = outgoingJson.to<JsonObject>().createNestedObject("data");
|
||||||
|
|
||||||
|
outgoingData["success"] = true;
|
||||||
|
|
||||||
|
// Handle the message based on the "type" field
|
||||||
|
switch (type) {
|
||||||
|
case 1:
|
||||||
|
// Handle SET_PIN message
|
||||||
|
pinMode((int)data["pin"], OUTPUT);
|
||||||
|
if (data["mode"] == "DIGITAL") {
|
||||||
|
digitalWrite((int)data["pin"], data["value"]);
|
||||||
|
} else {
|
||||||
|
analogWrite((int)data["pin"], (data["value"] == 255) ? HIGH : LOW);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// Handle GET_VAL message
|
||||||
|
pinMode((int)data["pin"], INPUT);
|
||||||
|
int val;
|
||||||
|
if (data["mode"] == "DIGITAL") {
|
||||||
|
val = digitalRead((int)data["pin"]);
|
||||||
|
} else {
|
||||||
|
val = analogRead((int)data["pin"]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// Handle GET_SENSOR message
|
||||||
|
|
||||||
|
/*
|
||||||
|
(WEIGHT_VAL - NO_WEIGHT_VAL) / Sensitivitätsfaktor = Gewicht in Gramm
|
||||||
|
(WEIGHT_VAL - NO_WEIGHT_VAL) / (100g_val /100) ist die Formel zur Berechnung des Gewichts in Gramm nach der Kalibrierung mit einem 100 Gramm Gewicht.
|
||||||
|
100g_val /100 gibt den Sensitivitätsfaktor an, der angibt, wie viel sich der Sensorwert ändert, wenn sich das Gewicht um ein Gramm ändert.
|
||||||
|
Durch die Division von 100g_val durch 100 wird der Sensitivitätsfaktor berechnet, und durch die Division von (WEIGHT_VAL - NO_WEIGHT_VAL) durch den Sensitivitätsfaktor wird das Gewicht in Gramm berechnet.
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
(WEIGHT_VAL - NO_WEIGHT_VAL) / (100g_val /100) = Gewicht in Gramm
|
||||||
|
(2400 - 2000) / (2450 /100) = 80 Gramm
|
||||||
|
*/
|
||||||
|
// HX711 circuit wiring
|
||||||
|
const int LOADCELL_DOUT_PIN = (int) data["pin_dout"];
|
||||||
|
const int LOADCELL_SCK_PIN = (int) data["pin_sck"];
|
||||||
|
HX711 scale;
|
||||||
|
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
|
||||||
|
|
||||||
|
// Get the weight value from the scale
|
||||||
|
long weight_val = scale.get_units();
|
||||||
|
outgoingData["value"] = weight_val;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
resetFunc(); //call reset
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Handle unknown message type
|
||||||
|
outgoingData[""] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prepare the outgoing JSON message
|
||||||
|
outgoingJson["id"] = id;
|
||||||
|
outgoingJson["type"] = 0;
|
||||||
|
outgoingJson["data"] = outgoingData;
|
||||||
|
|
||||||
|
// Send the outgoing JSON message
|
||||||
|
serializeJson(outgoingJson, Serial);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
<br>
|
||||||
|
|
||||||
|
Das hier ist erstmal der gesamte Code.<br>
|
||||||
|
|
||||||
|
<hr>
|
||||||
|
|
||||||
|
## Einzelerklärung
|
||||||
|
```c
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include "HX711.h"
|
||||||
|
```
|
||||||
|
Dieser Teil importiert erstmal die Bibliotheken ArduinoJson und HX711.
|
||||||
|
ArduinoJson wird für den Austausch von Anfragen zwischen dem Arduino und dem Raspberry Pi über die Serielle-Verbindung genutzt.
|
||||||
|
HX711 ist die Bibliothek für die Wägezelle, welche verwendet wird um das Gewicht in gramm auszurechnen.
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Define the size of the JSON buffer
|
||||||
|
#define JSON_BUFFER_SIZE 256
|
||||||
|
|
||||||
|
// Create a JSON object for incoming messages
|
||||||
|
StaticJsonDocument<JSON_BUFFER_SIZE> incomingJson;
|
||||||
|
|
||||||
|
// Create a JSON object for outgoing messages
|
||||||
|
DynamicJsonDocument outgoingJson(JSON_BUFFER_SIZE);
|
||||||
|
```
|
||||||
|
Hier wird die Buffer-Größe definiert, welche angibt wie groß das JsonDocument sein kann, welches zwischen Raspberry Pi kommuniziert.
|
||||||
|
|
||||||
|
Die größe liegt hier bei 256-Bytes, welche derzeit ausreicht um die Anfragen vom Pi zu verarbeiten und zu beantworten.
|
||||||
|
|
||||||
|
Danach erstellen wir ein StaticJsonDocument-Objekt `incomingJson`, welches das eingehende JSON verarbeiten soll. Hier geben wir mit <> unsere Buffer-Größe an.
|
||||||
|
|
||||||
|
Zuletzt gibt es das DynamicJsonDocument `outgoingJson`, welches das ausgehende Json enthält.
|
||||||
|
|
||||||
|
|
||||||
|
```c
|
||||||
|
void setup() {
|
||||||
|
// Initialize serial communication
|
||||||
|
Serial.begin(9600);
|
||||||
|
}
|
||||||
|
|
||||||
|
void (*resetFunc)(void) = 0; //declare reset function @ address 0
|
||||||
|
```
|
||||||
|
|
||||||
|
Hier befinden sich zwei Funktionen. Zum einen die `void setup()`-Methode, welche ausgeführt wird, sobald der Arduino startet, zum anderen die eher merkwürdig aussehende `void (*resetFunc)...`-Methode.
|
||||||
|
|
||||||
|
In der `setup()` Methode haben wir nur die initalisierung der Seriellen Verbindung auf 9600-Baud. 9600 Baud gibt die Gewschwindigkeit der Übertragung zwischen Pi und Arduino an. Wir testen erstmal mit 9600, können aber bis 115200 erweitern.
|
||||||
|
|
||||||
|
Die `resetFunc` dient zum Neustart des Arduinos per Software. Es gibt leider keine restart Funktion oder ähnliches, weshalb wir uns hier das Prinzip eines Sektor-Schreibens zu nutze machen und eine Funktion auf Adresse 0 im Speicher des Arduinos liegen.
|
||||||
|
Er stürzt quasi kontrolliert ab und startet neu.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Danach beginnen wir den Loop, welcher automatisch ausgeführt wird, sobald
|
||||||
|
```c
|
||||||
|
void loop() {
|
||||||
|
if (Serial.available()) {
|
||||||
|
// Read the incoming JSON message
|
||||||
|
DeserializationError error = deserializeJson(incomingJson, Serial);
|
||||||
|
if (error) {
|
||||||
|
// Handle error
|
||||||
|
} else {
|
||||||
|
// Extract the "type" and "data" fields from the JSON object
|
||||||
|
String id = incomingJson["id"];
|
||||||
|
int type = incomingJson["type"];
|
||||||
|
JsonVariant data = incomingJson["data"];
|
||||||
|
|
||||||
|
// Create a nested object in the root object
|
||||||
|
JsonObject outgoingData = outgoingJson.to<JsonObject>().createNestedObject("data");
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Hier wird zuerst geprüft, ob Serielle Daten vorliegen.
|
||||||
|
Sollten Sie vorliegen "Deserialisieren" wir die JSON-Daten, welche gerade über die Serielle Verbindung gesendet werden.
|
||||||
|
|
||||||
|
Sollte es dabei einen Fehler geben, können wir diesen abfangen.
|
||||||
|
Derzeit würde die Anfrage vom Raspberry Pi -> Arduino einfach nach einer Sekunde eine Zeitüberschreitung erhalten, was im Prinzip das selbe ist wie, Arduino hat nicht geantwortet oder etwas stimmt nicht.
|
||||||
|
|
||||||
|
Falls erfolgreich speichern wir uns die Anfrage-ID, den Anfrage-Typ sowie ein data-Objekt in Typ `JsonVariant`.
|
||||||
|
Die ID ist die Anfrage-ID, welche für unsere Antwort verwendet werden muss. Ansonsten kann Antwort und Anfrage nicht zugeordnet werden.
|
||||||
|
|
||||||
|
Der Type ist der Typ der Anfrage. Es gibt GET_PIN, SET_PIN, GET_SENSOR und RESTART.
|
||||||
|
|
||||||
|
Danach wird ein outgoingData Objekt erzeigt, welches dazu dient, die ausgehenden Daten zu speichern und zu setzen.
|
||||||
|
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Handle the message based on the "type" field
|
||||||
|
switch (type) {
|
||||||
|
case 1:
|
||||||
|
// Handle SET_PIN message
|
||||||
|
pinMode((int)data["pin"], OUTPUT);
|
||||||
|
if (data["mode"] == "DIGITAL") {
|
||||||
|
digitalWrite((int)data["pin"], data["value"]);
|
||||||
|
} else {
|
||||||
|
analogWrite((int)data["pin"], (data["value"] == 255) ? HIGH : LOW);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
// Handle GET_VAL message
|
||||||
|
pinMode((int)data["pin"], INPUT);
|
||||||
|
int val;
|
||||||
|
if (data["mode"] == "DIGITAL") {
|
||||||
|
val = digitalRead((int)data["pin"]);
|
||||||
|
} else {
|
||||||
|
val = analogRead((int)data["pin"]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
// Handle GET_SENSOR message
|
||||||
|
|
||||||
|
/*
|
||||||
|
(WEIGHT_VAL - NO_WEIGHT_VAL) / Sensitivitätsfaktor = Gewicht in Gramm
|
||||||
|
(WEIGHT_VAL - NO_WEIGHT_VAL) / (100g_val /100) ist die Formel zur Berechnung des Gewichts in Gramm nach der Kalibrierung mit einem 100 Gramm Gewicht.
|
||||||
|
100g_val /100 gibt den Sensitivitätsfaktor an, der angibt, wie viel sich der Sensorwert ändert, wenn sich das Gewicht um ein Gramm ändert.
|
||||||
|
Durch die Division von 100g_val durch 100 wird der Sensitivitätsfaktor berechnet, und durch die Division von (WEIGHT_VAL - NO_WEIGHT_VAL) durch den Sensitivitätsfaktor wird das Gewicht in Gramm berechnet.
|
||||||
|
|
||||||
|
Beispiel:
|
||||||
|
(WEIGHT_VAL - NO_WEIGHT_VAL) / (100g_val /100) = Gewicht in Gramm
|
||||||
|
(2400 - 2000) / (2450 /100) = 80 Gramm
|
||||||
|
*/
|
||||||
|
// HX711 circuit wiring
|
||||||
|
const int LOADCELL_DOUT_PIN = (int)data["pin_dout"];
|
||||||
|
const int LOADCELL_SCK_PIN = (int)data["pin_sck"];
|
||||||
|
HX711 scale;
|
||||||
|
scale.begin(LOADCELL_DOUT_PIN, LOADCELL_SCK_PIN);
|
||||||
|
|
||||||
|
// Get the weight value from the scale
|
||||||
|
long weight_val = scale.get_units();
|
||||||
|
outgoingData["value"] = weight_val;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
resetFunc(); //call reset
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Handle unknown message type
|
||||||
|
outgoingData[""] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Es wird gestartet mit einem Switch-Statement.
|
||||||
|
Hier finden sich die einzelnen Types wieder, welche anstatt beispielsweise ENUM's wie GET_VALUE in Arduino nur Integer sind, welche diese repräsentieren.
|
||||||
|
|
||||||
|
|
||||||
|
In dem `case 1` (SET_PIN) befindet sich der Code um einen Arduino-Pin Digital und Analog auf einen Wert (data["value"] zu setzen.
|
||||||
|
|
||||||
|
In `case 2` (GET_PIN) wird ein Arduino-Pin Digital oder Analog ausgelesen.
|
||||||
|
|
||||||
|
Bei `case 3` (GET_SENSOR) wird ein HX711-Sensor abgefragt.
|
||||||
|
In die Anfrage-Daten kommen als Parameter `pin_dout` sowie `pin_sck` mit, danach wird ein Wagen-Objekt initalisiert und danach versucht auszulesen.
|
||||||
|
|
||||||
|
Bei `case 4` (RESTART) soll ein Reset des Arduinos ausgeführt werden. Wie oben erklärt wird die `resetFunc` ausgeführt.
|
||||||
|
|
||||||
|
Default sendet einfach leere Daten als Fehler zurück.
|
||||||
|
|
||||||
|
```c
|
||||||
|
// Prepare the outgoing JSON message
|
||||||
|
outgoingJson["id"] = id;
|
||||||
|
outgoingJson["type"] = 0;
|
||||||
|
outgoingJson["data"] = outgoingData;
|
||||||
|
|
||||||
|
// Send the outgoing JSON message
|
||||||
|
serializeJson(outgoingJson, Serial);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Zuletzt wird die outgoingJson-ID, -Type sowie die Daten gesetzt.
|
||||||
|
Das JSON wird nun serialized, also in Text-Gewandelt und dann über das Serial-Objekt gesendet.
|
||||||
|
|
||||||
|
```c+
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
Loading…
x
Reference in New Issue
Block a user