diff --git a/doc%2FArduino.md b/doc%2FArduino.md new file mode 100644 index 0000000..7c73954 --- /dev/null +++ b/doc%2FArduino.md @@ -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 +#include "HX711.h" + +// Define the size of the JSON buffer +#define JSON_BUFFER_SIZE 256 + +// Create a JSON object for incoming messages +StaticJsonDocument 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().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); + } + } +} +``` +
+ +Das hier ist erstmal der gesamte Code.
+ +
+ +## Einzelerklärung +```c +#include +#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 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().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+ + } +} +``` \ No newline at end of file