„doc/Arduino“ ändern

Tobias Hopp 2023-01-23 10:21:04 +01:00
parent b4e32782f6
commit 5eca2f642a

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+
}
}
```