diff --git a/.gitignore b/.gitignore
index 34f6722..df77246 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,4 +24,5 @@ build
*.pytest_cache
photos
-venv
\ No newline at end of file
+venv
+myenv/
\ No newline at end of file
diff --git a/FLOAT/Images/Deploy_image.png b/FLOAT/Images/Deploy_image.png
deleted file mode 100644
index 9baa626..0000000
Binary files a/FLOAT/Images/Deploy_image.png and /dev/null differ
diff --git a/FLOAT/Images/sd_AM_inconsistency.png b/FLOAT/Images/sd_AM_inconsistency.png
deleted file mode 100644
index 616713a..0000000
Binary files a/FLOAT/Images/sd_AM_inconsistency.png and /dev/null differ
diff --git a/FLOAT/Images/sd_CS_ESPB_stale.png b/FLOAT/Images/sd_CS_ESPB_stale.png
deleted file mode 100644
index bb7193c..0000000
Binary files a/FLOAT/Images/sd_CS_ESPB_stale.png and /dev/null differ
diff --git a/FLOAT/Images/sd_CS_fresh.png b/FLOAT/Images/sd_CS_fresh.png
deleted file mode 100644
index 4c39489..0000000
Binary files a/FLOAT/Images/sd_CS_fresh.png and /dev/null differ
diff --git a/FLOAT/README.md b/FLOAT/README.md
deleted file mode 100644
index 2ad34f7..0000000
--- a/FLOAT/README.md
+++ /dev/null
@@ -1,148 +0,0 @@
-### INTRODUCTION AND CODE REQUIREMENTS
-
-By MATE requirements documentation (2023/2024), it is requested to send a test package to the CS (to be printed by the GUI), as soon as the FLOAT is in water.
-
-After it sends the package, the FLOAT can then start the first profile. During fall and rise, it measures pressure with a certain period (can be specified in milliseconds) and evaluates the depth from it with a 1/2 cm accuracy, writing it in a microSD every 5 seconds, together with the milliseconds elapsed from profile start and the team code, all encapsulated in a JSON format. The data file on the microSD is cleaned at every startup. To detect when to rise (when at the bottom) or send collected data to Control Station (once at the water level), so to detect when it is stationary, the FLOAT compares the last two measurements and if they are equal in a given range, then the FLOAT can be considered still.
-
-After the profile, when it is at water level, the FLOAT has to read data written on microSD and send it to the CS, one package per data line.
-
-The GUI running on the CS will then plot depth and pressure measured during last profile. It is necessary a second profile after that and the plot of the relative data to gain maximum points.
-
-The FLOAT has to send only data relative to the last completed profile to get the points for the plot.
-
-It is possible to activate the Auto Mode (hereinafter referred to as AM) that in case of connection loss with the CS, make the FLOAT to commit a profile autonomously, given that the already completed profiles are less then two. This way, in case of long lasting connection loss, the AM will make the FLOAT commit the number of profiles necessary to the competition, and not more.
-
-__________________________________________________________________________
-
-### GENERAL DESIGN
-
-##### BEHAVIOR
-
-The general idea is that the FLOAT provides some micro-services that the CS can activate by sending commands to it. Every command can be requested at any moment, with the only limit that a command can be accepted by the FLOAT only when the previous one has been completed (more info on command cycle later).
-
-The FLOAT has two main logical states: the command execution one, and the idle one in which it waits for the new command. In idle state, the FLOAT can have some data from last completed profile that can be sent to the CS.
-
-
-##### SOFTWARE AND HARDWARE DEPLOYMENT
-
-FLOAT code has to be deployed on two ESP32, one mounted on the FLOAT board (ESPA) together with the sensors and the power supply, and the other (ESPB)
-
-communicating with the Control Station via USB. The two ESP32 communicates via WiFi. The software on the two ESP32 is designed to work of regardless of the design of the GUI on the CS.
-
-The idea is to bring all the complexity on the ESPA and GUI, leaving no trace of logic on the ESPB.
-
-
-Deploy diagram:
-
-
-
-
-##### COMMAND LIFE-CYCLE
-
-A command life-cycle does not overlaps/interfere with the previous nor the next one: when the CS sends a command (and it arrives to the FLOAT), a feedback from the FLOAT should inform about the acceptance of the command and if this acknowledgement arrives within a given period (specified later), next command requests will be ignored until end of execution of the current one, signaled by an idle acknowledgement.
-If the acknowledgement doesn't arrive within that time span, the command commit can be considered failed: this could happen for WiFi connection failures or FLOAT electronics issues.
-
-When waiting for the command commit acknowledgement, other command requests will be ignored as well.
-
-As already mentioned, after command completion the FLOAT will try to send an idle acknowledgement to signal that it is listening for a new command: together with the idle state, this acknowledgement can also inform about the presence of new data on the microSD that has to be sent to the CS. After an idle acknowledgement is received, a new command can be accepted.
-
-To maintain consistency with the status stored on the ESPB, and hence with the GUI visuals, the FLOAT grants to send the acknowledgement signalling a command commit only when the commit can be given for sure.
-In the same way, if the acknowledgement fails to be sent due to connection issues, the command is not committed.
-
-
-")
-
-
-##### ESPB: ROLE, BEHAVIOR AND USAGE
-
-The ESPB role is only to make the CS task of continuously checking on the WiFi channel less resource consuming.
-
-In particular, ESPB receives commands from CS via USB only to forward them to the FLOAT via WiFi. At the same time, it can receive feedback and data from the FLOAT. In the latter case the ESPB will forward the packages on the USB channel, while using them to update an internal state accordingly. The only code that should trigger the update of the state stored on ESPB is the firmware on the FLOAT, via the data and the feedback sent to CS (more later). This is because no assumptions have to be done by other software on the commands completion and acceptance.
-
-The ESPB state should mirror the FLOAT state at each moment (more details later) and can be used by the GUI to give visual feedback to the user or to drive its internal logic. It can be requested to the ESPB by the CS at any moment with a specific command.
-The state info sent to the CS with this command also contains WiFi connection state info and AM activation state info.
-
-In general, the ESPB feedback could be stale when requested (for example because the CS could poll it with a low frequency), so to get fresh, real-time data the CS should listen on the USB channel for the FLOAT packages, after a command request or when waiting for command completion and retrieve the FLOAT current state directly by those packages.
-
-Periodic polling remains a legit choice in case the CS cannot exploit interrupts triggered by Serial connection, but notice that this solution leads to delayed GUI visual feedback with respect to the changes on the FLOAT state.
-
-In some cases, connection losses can undermine consistency between the feedback of the ESPB (either they are polled or real time) and the real current FLOAT state (consistency threats for each FLOAT state later).
-
-
-
-
-##### GLOSSARY
-
-- **Commit a command**: To accept a sent command. After commit, command execution and success is ideally granted.
-- **Complete a command**: To execute all the requirements requested by a command.
-
-
---------------------------------------------------------------------------
-
-
-### IMPLEMENTATION PARAMETERS
-
-##### FLOAT COMMANDS
-
-Table of FLOAT commands with relative effects and acknowledgements:
-
-| Cmd string | Cmd ESPA number | Cmd effects | ESPA ack string | ESPA ack effects on ESPB state |
-| :--------------: | :-------------: | ------------------------------------------------------------------------------------------------------------------------------------------------- | :-----------------------: | :---------------------------------------: |
-| GO | 1 | Performs a profile in which measures depth and pressure and saves them to microSD | GO_RECVD | status to 2 (command execution)
|
-| LISTENING | 2 | Requests data from last profile. If connection drops during sending, data is lost | Ack is data itself | status to 2 after first package arrival |
-| BALANCE | 3 | Moves the syriniges all the way down: usefull after pressure test, during which external pressure push syringes up | CMD3_RECVD | status to 2 |
-| CLEAR_SD | 4 | Clears data file on microSD | CMD4_RECVD | status to 2 |
-| SWITCH_AUTO_MODE | 5 | Toggles FLOAT Auto Mode
| SWITCH_AM_RECVD | status to 2 , AM activation state toggled |
-| SEND_PACKAGE | 6 | Requests a single test package to print on the GUI
| Ack is the package itself | status to 2 |
-| TRY_UPLOAD | 7 | Requests to activate the Elegant OTA server on the ESPA for OTA firmware uploading. After the upload FLAOT restarts | TRY_UPLOAD_RECVD | status to 2
|
-| STATUS | - | Requests stale status to ESPB. It will respond with a status string containing FLOAT state, WiFi connection state and AM current activation state | - | - |
-
-Once a command is completed, ESPA acknowledgement can be:
-
-| ESPA ack string | ESPA ack effects on ESPB state | ESPA state |
-| ----------------- | --------------------------------------- | ------------------------------------------- |
-| FLOAT_IDLE | status to 0 (idle) | Idle with no data to be sent |
-| FLOAT_IDLE_W_DATA | status to 1 (idle with data to be sent) | Idle with data from last profile to be sent |
-
-
-##### STATUS COMMAND: ESPB RESPONSE
-
-ESPB response to **STATUS** command is composed by three parts of information: ESPA state (stale), activation of the AM on the FLOAT and WiFi connection state. The WiFi connection state is detected with the sending of a test package, while the other states are kept consistent with the ones on the FLOAT by updating them after acknowledgements reception.
-
-- **ESPA state**:
-
-| ESPB state string | ESPB state number | State description |
-| :---------------: | :---------------: | --------------------------------------------------------------------------------------------------------------------- |
-| CONNECTED | 0 | The FLOAT is listening for new command. Previous command succeeded |
-| CONNECTED_W_DATA | 1 | The FLOAT is listening for new command and has some new data from last profile to be sent. Previous command succeeded |
-| EXECUTING_CMD | 2 | FLOAT is executing a command |
-| STATUS_ERROR | - | Internal error in reading the state number |
-
-> ==**WARNING:**==
-> If committing a profile automatically, the relative acknowledgement will likely fail due to connection loss. The profile is committed anyway as it is generated from connection loss in the first place, but the GUI may not have mean to detect it. So it will likely read an **inconsistent** **idle** **status** (CONNECTED or CONNECTED_W_DATA) until FLOAT is at water level with a stable WiFi connection. In the meantime the command commits will fail, for connection loss or because the FLOAT is underwater. Anyway WiFi connection state can be detected by the STATUS command, hence giving feedback on status consistency.
-> 
-
-- **AM state**:
-
-| ESPB state string | State description |
-| :---------------: | ------------------------------------------------------------------------- |
-| AUTO_MODE_YES | AM on FLOAT is activated |
-| AUTO_MODE_NO | AM on FLOAT is not activated: connection losses will not trigger profiles |
-
-- **WiFi connection state**:
-
-| ESPB state string | State description |
-| :---------------: | ------------------------------------------------------------ |
-| CONN_OK | WiFi connection is ok |
-| CONN_LOST | WiFi connection is currently down. ESPB state could be wrong |
-
-Example of ESPB state response: **CONNECTED_W_DATA | AUTO_MODE_NO | CONN_OK**
-
-
---------------------------------------------------------------------------
-
-### UTILITIES AND RESOURCES
-
-Links to Arduino library repositories:
-- ESPAsyncWebServer: https://github.com/dvarrel/ESPAsyncWebSrv
-- AsyncElegantOTA: https://github.com/ayushsharma82/AsyncElegantOTA
diff --git a/FLOAT/espA/espA.ino b/FLOAT/espA/espA.ino
deleted file mode 100644
index 90bf089..0000000
--- a/FLOAT/espA/espA.ino
+++ /dev/null
@@ -1,559 +0,0 @@
-/*
-*********************************************************************************************************
-* Code of the ESP32 on the FLOAT board (ESPA)
-*
-* Filename: EspA.ino
-* Version: 8.1.1
-* Developers: Fachechi Gino Marco, Gullotta Salvatore
-* Company: Team PoliTOcean @ Politecnico di Torino
-* Arduino board package: esp32 by Espressif Systems, v2.0.17
-*
-* Description:
-* The code has a switch in the main loop driven by a state
-* called status. The status is mainly modified by the packages
-* sended by the ESPB over the MAC layer.
-* The zero state is the idle one, in which
-* the FLOAT communicates to CS that it is listening and
-* waits for the next command to execute. The idle acknowledgement
-* is sended every CONN_CHECK_PERIOD milliseconds.
-* In case the microSD has some data to send, the acknowledgement
-* informs the CS of that, too.
-* If the ack fails to be delivered, the FLOAT can enter in Auto Mode
-* (hereinafter shortened to as AM), that commits automatically a profile.
-* The other states correspond to specific command routines, called when
-* their relative command arrives.
-* After a command completion, the FLOAT returns to idle phase.
-* The FLOAT should guarantee to send a command acknowledgement only when
-* the command success is sure. In the same way, if the acknowledgement sending
-* fails, the command is ignored to keep consistency with the ESPB.
-*********************************************************************************************************
-*/
-
-/** INCLUDES **/
-// Description | Version
-// |
-#include // Library needed if you are compiling on VSC PlatformIO plugin | /
-#include // Library for pressure sensor (Bar02) control over I2C | v1.1.1
-#include // Esp_now library for WiFi connections establishing and management | /
-#include // Layer for proper initialization and setting of ESP32 WiFi module | /
-#include // Library for I2C connection protocol interface, used by MS5837.h and RTClib.h | /
-#include // Library for SPI connection protocol interface, used by SD.h | /
-#include // An SDcard control interface | v1.2.4
-#include // Library for TCP connection protocol interface, used by ESPAsyncWebServer.h | v1.1.4
-#include // Library for creation of a web server running on ESP32 , used by AsyncElegantOTA.h | v2.10.8
-#include // Library for creation of the OTA web page for new firmware uploading | v2.2.8
-
-/** DEFINES **/
-#ifndef ESPA_INO
- #define ESPA_INO
-#endif
-
-#define OUTPUT_LEN 250 // Length of the output on the MAC layer
-#define FILE_NAME "/FLOAT_data.txt" // Name of the file containing FLOAT measurements
-// List of messages for the ESPA acknoledgements: CS has to be aware of these
-#define IDLE_ACK "FLOAT_IDLE"
-#define IDLE_W_DATA_ACK "FLOAT_IDLE_W_DATA"
-#define CMD1_ACK "GO_RECVD"
-#define CMD3_ACK "CMD3_RECVD"
-#define CMD4_ACK "CMD4_RECVD"
-#define CMD5_ACK "SWITCH_AM_RECVD"
-#define CMD7_ACK "TRY_UPLOAD_RECVD"
-
-/** I/O STRUCTS
- Structs containing message and command for communication over MAC.
- Must match the receiver (ESPB) structures.
- Necessary for esp_now library compliance.
-**/
-typedef struct output_message {
- char message[OUTPUT_LEN];
-} output_message;
-
-typedef struct input_message {
- uint8_t command = 0;
-} input_message;
-
-output_message output;
-input_message input;
-
-/** LIBRARY VARIABLES **/
-MS5837 sensor; // Object for Bar02 interfacing
-File myFile; // File object pointing to the microSD file currently modified
-esp_now_peer_info_t peerInfo; // Object containing info about the MAC peer we want to connect with
-AsyncWebServer server(80);
-// Esp_now constant for peer MAC address value. Replace with the MAC address of your receiver (ESPB)
-uint8_t broadcastAddress[] = {0xE4, 0x65, 0xB8, 0xA7E, 0x27, 0xAC};
-
-/** PROGRAM GLOBAL CONSTANTS **/
-const char* SSID = "Mi10"; // Name of the net the ESPA has to connect to for OTA firmware upload
-const char* PASSWORD = "ciao1234"; // Password for the net the ESPA has to connect to for OTA firmware upload
-const uint8_t DIR = 12; // Pin for motor direction driving
-const uint8_t STEP = 14; // Pin for motor tension driving (used as PWM)
-const uint8_t EN = 27; // Active-low pin for motor enabling
-const uint8_t MAX_PROFILES = 2; // Number of profiles to complete in order to gain maximum points
-const uint16_t ROT_TIME = 6300; // Motor rotation time necessary to empty/fullfill the syringes, expressed in ms
-const uint16_t STEP_FREQ = 300; // Frequency of the 50% duty cycle PWM used to drive the motor (STEP pin), expressed in Hz
-const uint16_t MEAS_PERIOD = 100; // Period between two consecutive measurements during immersion phase, expressed in ms
-const uint16_t WRITE_PERIOD = 5000; // Period between two consecutive writes to microSD during immersion phase, expressed in ms
-const uint16_t CONN_CHECK_PERIOD = 500; // Period between two consecutive acknoledgements during idle phase, expressed in ms
-const float FLOAT_LENGTH = 0.51; // Length of the FLOAT, measured form the very bottom to the pressure sensor top, expressed in m
-const float EPSILON = 0.01; // Error span in which two consecutive measures are considered equal, expressed in m
-
-/** PROGRAM GLOBAL VARIABLES **/
-uint8_t meas_cnt = 0; // Number of measurements occurred since the last write to microSD, must be reset before each profile
-uint8_t profile_count = 0; // Number of profiles committed since startup
-uint8_t auto_mode_active = 0; // 1 if AM is active, 0 otherwise
-uint8_t float_stopped = 0; // Set to 1 when the FLOAT is sensed to be stationary during immersion phase, must be reset before each profile
-uint8_t motor_stopped = 0; // Set to 1 after the motor finishes its rotation during immersion phase, must be reset before each profile
-uint8_t idle = 0; // 1 if in idle phase, 0 otherwise
-uint8_t auto_committed = 0; // During immersion phase, 1 if immersion has been triggered by AM, 0 otherwise
-int8_t send_result = -1; // Flag for sending-over-MAC logic, needed to handle sending failure
-int8_t status = 0; // Status of the FLOAT, drives the main switch and keeps track of the current phase
-uint16_t new_data = 0; // During idle phase, 1 if ready-to-send data is in microSD, 0 otherwise
-uint16_t file_read_ptr = 0; // Pointer to the location of the last read byte in the microSD data file
-uint16_t file_write_ptr = 0; // Pointer to the location of the last written byte in the microSD data file
-uint64_t time_ref = 0; // Time reference for writing on the microSD during immersion phase, updated at each profile start
-float atm_pressure = 0; // Stores the initial atmosphere pressure, needed for correct depth calculation
-float depth = 0; // Depth measured during immersion phase, writed in microSD and used to sense FLOAT stationarity, expressed in Pa
-float prevDepth = 0; // Depth of previous measurement, used during immersion phase to sense FLOAT stationarity, expressed in Pa.
-// Must be reset before each profile
-
-/** PROGRAM LOCAL FUNCTIONS **/
-/*
-*********************************************************************************************************
-* OnDataRecv()
-*
-* Description : Callback for data arrival on the MAC layer: receives a command during idle phase.
-* If the command in the input data struct is 0, the callback updates it with the
-* incoming command. The value in the struct will be reset to 0 after
-* the completion of the routine relative to the received command.
-* Meanwhile no other incoming command will be accepted.
-*
-* Argument(s) : mac : MAC address of the peer from which the data was received.
-*
-* incomingData : Struct containing incoming data. Data maximum length is 250 bytes.
-*
-* len : Length of the received data.
-*
-* Return(s) : none
-*********************************************************************************************************
-*/
-void OnDataRecv (const uint8_t * mac, const uint8_t * incomingData, int len) {
-
- if (input.command == 0) memcpy(&input, incomingData, sizeof(input));
-
-}
-
-/*
-*********************************************************************************************************
-* OnDataSent()
-*
-* Description : Callback for data sending on the MAC layer: it updates send_result flag to
-* inform other logics whether the sending of the last package went well or not.
-* The flag has to be cleared to -1 before each sending.
-*
-* Argument(s) : mac : MAC address of the peer to which the data was sended.
-*
-* status : Status of the sending. It evaluates to ESP_NOW_SEND_SUCCESS if it succeeded.
-*
-* Return(s) : none
-*********************************************************************************************************
-*/
-void OnDataSent (const uint8_t * mac, esp_now_send_status_t status) {
-
- if (status == ESP_NOW_SEND_SUCCESS) send_result = 1; // If sending succeeds sets the flag to 1
- else send_result = 0; // Otherwise sets it to 0
-
-}
-
-/*
-*********************************************************************************************************
-* send_message()
-*
-* Description : Function for message sending over the MAC layer: target peer is set during setup and
-* should be the CS (ESPB). In case of sending failure, signalled by the send_result flag,
-* the message is continously sended until it succeeds or
-* the max_conn_time milliseconds elapse.
-*
-* Argument(s) : message_str : Char array containing the message string.
-*
-* max_conn_time : Time that has to elapse before stopping to try the sending.
-* Expressed in milliseconds.
-*
-* Return(s) : 1 if sending succeeded, 0 if given time elapsed.
-*********************************************************************************************************
-*/
-uint8_t send_message (char * message_str, uint16_t max_conn_time) {
- memcpy(&output.message, message_str, sizeof(output.message)); // Message is copied in the output data struct
- uint64_t prec_time = millis(); // A time reference (ms elapsed from startup) is stored in prec_time
- while (true) { // [* sending sequence start]
- send_result = -1; // send_result flat is cleared
- esp_now_send(broadcastAddress, (uint8_t *) &output, sizeof(output)); // Tries to send the message over MAC layer
- while (send_result == -1); // Waits for OnDataSent callback to set send_result flag
- if(send_result) return 1; // If sending succeeds, function returns 1
- else if (millis() - prec_time > max_conn_time) return 0; // If sending failed and max_conn_time milliseconds elapsed from
- }// prec_time set, the function returns 0. Otherwise it starts again
-// the sending sequence from [* sending sequence start]
-}
-
-/*
-*********************************************************************************************************
-* f_depth()
-*
-* Description : Utility function that uses Stevino rule to calculate a depth value starting from
-* the pressure measured at setup and the last pressure value given by
-* the pressure sensor. It also adjusts the depth value by adding the FLOAT
-* length to it, in order to mock the position of the pressure sensor, which is
-* at the top of the robot.
-*
-* Argument(s) : none
-*
-* Return(s) : The depth value calculated, expressed in meters.
-*********************************************************************************************************
-*/
-float f_depth () {
- depth = (sensor.pressure(MS5837::Pa)-atm_pressure)/(997*9.80665); // Stevino rule to calculate depth.
-// Density: 997Kg/m^3 for fresh water, 1029Kg/m^3 for sea water
- return depth + FLOAT_LENGTH; // Adds the FLOAT length to the result
-}
-
-/*
-*********************************************************************************************************
-* write_SD()
-*
-* Description : Writes to the microSD mounted on the board. In particular it writes a single line
-* containing all the data needed by the CS, wrapped in a JSON format and terminated
-* by a new line. The write starts after the last written byte in the file. The
-* function finally updates the file_write_ptr pointer with the position
-* following the last written byte in the file (the new line). The data is mostly
-* provided by the sensor object which has to be updated before calling this
-* function, by calling sensor.read function.
-*
-* Argument(s) : none
-*
-* Return(s) : none
-*********************************************************************************************************
-*/
-void write_SD () {
- if (myFile) { // Checks if the file is open and the File pointer is valid
- myFile.seek(file_write_ptr); // Puts the file cursor on the position stored in file_write_ptr.
-// The following writes will start from that position
- // Writes company number,
- myFile.print("{\"company_number\":\"EX16\",\"pressure\":\"");
- // pressure as measured from the bottom of the FLOAT: the multiplication is for m to Pa conversion in water,
- myFile.print(sensor.pressure(MS5837::Pa) + (FLOAT_LENGTH*10000));
- myFile.print("\",\"depth\":\"");
- // depth value as calculated from f_depth function, in m,
- myFile.print(depth);
- myFile.print("\",\"temperature\":\"");
- // temperature in Celsius,
- myFile.print(sensor.temperature());
- myFile.print("\",\"mseconds\":\"");
- // milliseconds elapsed from the profile start
- myFile.print((millis() - time_ref));
- myFile.println("\"}");
- myFile.flush(); // Commits the writes
- file_write_ptr = myFile.position(); // Stores file cursor for next writes
- new_data = file_write_ptr - file_read_ptr; // Updates the new_data variable with the delta in bytes between
-// already-read data and the still-to-read one
- } //else Serial.println("write_SD(): error in opening file!");
-}
-
-/*
-*********************************************************************************************************
-* measure()
-*
-* Description : The function is called every MEAS_PERIOD ms during immersion phase. It's in charge
-* of stationarity detection and microSD writing. The write is performed by calling
-* the write_SD function every n times measure itself is called, where n is
-* the ratio between the period of the writes, WRITE_PERIOD, and the period with
-* which measure is called, MEAS_PERIOD, that is usually smaller. This works better
-* if the first is a multiple of the latter. The FLOAT is signalled as stationary
-* when two depth measurements in a row are equal within an EPSILON of error.
-*
-* Argument(s) : none
-*
-* Return(s) : none
-*********************************************************************************************************
-*/
-void measure () {
- sensor.read(); // Reads measurements of the Bar02 pressure sensor, updating the sensor object
- f_depth(); // Calculates depth value
- meas_cnt++;
- if (meas_cnt >= (WRITE_PERIOD / MEAS_PERIOD)) { // Checks if enough measurements occurred since the last write on microSD,
- write_SD(); // before writing again on it
- meas_cnt = 0;
- }
- //Serial.print("The just read depth is: ");
- //Serial.println(depth);
- if (motor_stopped) { // The logic activates only after the motor has stopped to be sure that the FLOAT is already moving
- if (prevDepth < depth + EPSILON && prevDepth > depth - EPSILON)
- float_stopped = 1; // If a measurement is equal to the previous in a range of double EPSILON,
-// it signals that the FLOAT is stationary by setting float_stopped flag
- }
- prevDepth = depth; // Updates previous depth measurement with the last one
-}
-
-/** SETUP **/
-void setup () {
- Serial.begin(115200); // Inits Serial Monitor
-
- pinMode(STEP, OUTPUT); // Pin assignment
- pinMode(DIR, OUTPUT);
- pinMode(EN, OUTPUT);
- digitalWrite(EN, HIGH); // Disables the motor until needed
-
- while (!SD.begin()) Serial.println("Failed to initialize SD card!"); // Inits microSD
- if (SD.exists(FILE_NAME)) SD.remove(FILE_NAME); // Clears data file
-
- WiFi.mode(WIFI_STA); // Sets device as a Wi-Fi Station
-
- if (esp_now_init() != ESP_OK) { // Inits esp_now
- Serial.println("Error initializing ESP-NOW");
- return;
- }
-
- esp_now_register_recv_cb(OnDataRecv); // Registers esp_now arrival callback
- esp_now_register_send_cb(OnDataSent); // Registers esp_now sending callback
-
- memcpy(peerInfo.peer_addr, broadcastAddress, 6); // Registers peer by passing peer object pointer
- peerInfo.channel = 0; // Channel selection
- peerInfo.encrypt = false;
-
- if (esp_now_add_peer(&peerInfo) != ESP_OK){ // Adds peer
- Serial.println("Failed to add peer");
- return;
- }
-
- sensor.setModel(1); // Inits Bar02 by specifing model,
- while (!sensor.init()) {
- Serial.println("Init failed!");
- Serial.println("Are SDA/SCL connected correctly?");
- Serial.println("Blue Robotics Bar02: White=SDA, Green=SCL");
- delay(5000);
- }
- sensor.setFluidDensity(997); // and operative density in Kg/m^3 (freshwater, 1029 for seawater)
- sensor.read();
- atm_pressure = sensor.pressure(MS5837::Pa); // Stores pressure value at water level for depth calculation, in Pa
-}
-
-/** MAIN SWITCH **/
-void loop () {
- switch (status) {
- case 0: // Idle
- {
- uint8_t result;
-
- auto_committed = 0;
-
- if (!idle) input.command = 0; // If not already waiting for a command (1st idle loop), resets the command.
-// This check is necessary as the new command can arrive
-// right after the CONN_CHECK_PERIOD timer triggers. Reset
-// is necessary for the new command detection
- if (new_data != 0) result = send_message(IDLE_W_DATA_ACK, 5000); // If there are data to be sent to CS, sends an acknowledgement
-// with that information to the ESPB
- else result = send_message(IDLE_ACK, 5000); // Otherwise signals only that is waiting for the next command
-
- if (result) { // Checks for acknowledgement success
- idle = 1; // Sets the idle flag: while is set the FLOAT is considered
-// waiting for a new command by all the logic. Like for commands
-// routines, the FLOAT is set in idle only if the ack arrives
- uint64_t prec_time = millis(); // Stores a time reference for the CONN_CHECK_PERIOD timer
-
- while ((millis() - prec_time < CONN_CHECK_PERIOD) && input.command == 0); // Waits for a new command to arrive or for CONN_CHECK_PERIOD
-// milliseconds to elapse
- status = input.command; // Copies the input struct command into the status driving the
-// main switch. If the time elapsed, the command may be 0
- } else if (profile_count < MAX_PROFILES && auto_mode_active) { // If the acknowledgement failed, AM is active and the FLOAT
-// committed less then MAX_PROFILES profiles, immersion is
-// committed automatically
- auto_committed = 1; // Signals to other logics that the next profile has been
-// committed automatically. Flag has to be cleared after
-// each command completion
- status = 1; // Sets immersion status, committing a profile
- }
- if (status != 0) idle = 0; // If a command has been committed, signals to other logics
-// that the FLOAT exited idle phase.
- }// Otherwise, the case 0 repeats remaining in idle
- break;
- case 1: // Profile commit and measuring
- {
- myFile = SD.open(FILE_NAME, FILE_WRITE); // Opens file in write mode, or creates it if non existing.
-// File pointer is now at 0
- if (!myFile) /*Serial.println("idle: error in opening file!")*/;
- else {
- uint8_t result;
-
- result = send_message(CMD1_ACK, 1000); // If file succeeds to open, tries to send an acknowledgement to CS
- if (result || auto_committed) { // If ack arrived or AM committed the profile, starts immersion phase
- uint64_t prec_time_rot = millis(); // Stores time reference for motor rotation timer
- uint64_t prec_time_meas = millis(); // Stores time reference for measurement period timer
-
- prevDepth = 0;
- meas_cnt = 0;
- time_ref = millis(); // Stores time reference for the entire profile. Used in microSD writing
- profile_count++; // Increases the global counter of committed profiles
- file_read_ptr = file_write_ptr; // If old profile data is written on microSD, discards it
-
- for (int i=0; i<2; i++) { // Logic repeats two times: one for descending phase and the other for ascending phase
- float_stopped = 0;
- motor_stopped = 0;
- digitalWrite(DIR, i); // Sets DIR pin with the needed rotation direction. In this case is 0 and then 1
- analogWriteFrequency(STEP_FREQ); // Sets analog PWM generator frequency to STEP_FREQ
- analogWrite(STEP, 127); // Sets the duty cycle of the generated PWM to 50%
- digitalWrite(EN, LOW); // Enables motor
- while(!float_stopped || !motor_stopped) { // Waits for the motor and the FLOAT to stop
- if (millis() - prec_time_meas > MEAS_PERIOD) { // Every MEAS_PERIOD ms reads from the sensor and tries to detect if FLOAT
-// stopped. It also writes to microSD every WRITE_PERIOD ms
- prec_time_meas = millis(); // Resets the MEAS_PERIOD timer for next measurement
- measure(); // measure function will set the float_stopped flag when detects stationarity
- }
- if (millis() - prec_time_rot > ROT_TIME) { // When ROT_TIME milliseconds elapse from prec_time_rot set,
- analogWrite(STEP, 0); // stops the motor (duty cycle at 0%),
- analogWriteFrequency(1000); // resets the PWM generator frequency,
- digitalWrite(EN, HIGH); // and disables the motor
- motor_stopped = 1; // Sets motor stop flag
- }
- }
- prec_time_rot = millis(); // Resets ROT_TIME timer for the ascending phase
- }
-
- myFile.println("STOP_DATA"); // Adds a profile-data terminator to the file
- myFile.flush(); // Commits the write
- file_write_ptr = myFile.position(); // Stores file cursor for next writes
- new_data = file_write_ptr - file_read_ptr; // Updates the new_data variable with the delta in bytes between
-// already-read data and the still-to-read one
- myFile.close(); // Closes file
- }
- }
- status = 0; // Returns to idle
- }
- break;
- case 2: // Data sending // The command doesn't need an acknowledgement as
- {// the sended data already works as ack
- myFile = SD.open(FILE_NAME, FILE_READ); // Opens file in read mode, or creates it if non existing
- if (!myFile) /*Serial.println("sending data: error in opening file!")*/;
- else {
- uint8_t result = 1;
- int line_len = 0;
-
- myFile.seek(file_read_ptr); // Starts to read after the last read byte
- while (myFile.available()) { // Tries to read until it reaches end of file
- delay(50); // Slowing down sending rate to match CS reading speed
-// (USB buffer is small in ESPB-CS connection)
- char line[OUTPUT_LEN];
-
- line_len = myFile.readBytesUntil('\n', line, OUTPUT_LEN); // Reads from microSD until encounters a new line, while copying
-// into char array line. New line character is not copied
- for(int i=line_len; isend(200, "text/plain", "Hi! I am ESP32.");
- });
- AsyncElegantOTA.begin(&server); // Starts the ElegantOTA server on the ESPA
- server.begin();
- Serial.println("HTTP server started");
- }
- status = 0;
- }
- break;
- //case 8: // New command routine
- // {
- // uint8_t result;
- //
- // result = send_message(CMD8_ACK, 1000);
- // if (result) {
- // // Insert here your code
- // }
- // status = 0; // Returns to idle
- // }
- // break;
- default: // Default case
- Serial.println("No command recognized, returning to idle...");
- status = 0;
- break;
- }
-}
\ No newline at end of file
diff --git a/FLOAT/espB/espB.ino b/FLOAT/espB/espB.ino
deleted file mode 100644
index b691765..0000000
--- a/FLOAT/espB/espB.ino
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
-*********************************************************************************************************
-* Code of the ESP32 attached to CS (ESPB)
-*
-* Filename: EspB.ino
-* Version: 8.1.1
-* Developers: Fachechi Gino Marco, Gullotta Salvatore
-* Company: Team PoliTOcean @ Politecnico di Torino
-* Arduino board package: esp32 by Espressif Systems, v2.0.17
-*
-* Description:
-* The ESPB main loop is a broker driven by two buffers, USB and WiFi one, filled by two callbacks.
-* When a command arrives from the CS, the code sends it to the FLOAT or
-* feedbacks the CS with the system state (that may be stale).
-* While doing the latter, the ESPB tries to send a dummy package:
-* if sending fails, it also reports the loss of connection to the CS. Part of the feedback
-* to the CS is also the current activation state of the Auto Mode (AM), as it is on the FLOAT.
-* When data arrives from the FLOAT, the ESPB updates the system state accordingly
-* and forwards the data to the CS, as a real time feedback.
-*********************************************************************************************************
-*/
-
-/** INCLUDES **/
-// Description | Version
-// |
-#include // Library needed if you are compiling on VSC PlatformIO plugin | /
-#include // Esp_now library for WiFi connections establishing and management | /
-#include // Layer for proper initialization and setting of ESP32 WiFi module | /
-#include // Library for I2C connection protocol interface, used by MS5837.h and RTClib.h | /
-
-/** DEFINES **/
-#ifndef ESPB_INO
- #define ESPB_INO
-#endif
-
-#define INPUT_LEN 250 // Length of the input on the MAC layer
-#define BUFFER_SIZE 20 // Chosen size in bytes of the Serial software buffer:
-// longer command and status strings are strongly discouraged
-// and the GUI running on the CS should be aware of this limit
-
-/** I/O STRUCTS
- Structs containing message and command for communication over MAC.
- Must match the receiver (ESPA) structures.
- Necessary for esp_now library compliance.
-**/
-typedef struct input_message {
- char message[INPUT_LEN];
-} input_message;
-
-typedef struct output_message {
- uint8_t command = 0;
-} output_message;
-
-output_message output;
-input_message input;
-
-/** LIBRARY VARIABLES **/
-esp_now_peer_info_t peerInfo; // Object containing info about the MAC peer we want to connect with
-// Esp_now constant for peer MAC address value. Replace with the MAC address of your receiver (ESPA)
-uint8_t broadcastAddress[] = {0x24, 0xDC, 0xC3, 0xA0, 0x3B, 0x38};
-
-/** PROGRAM GLOBAL CONSTANTS **/
-const uint16_t MAX_CONN_TIME = 100; // Time in ms that has to elapse before send_message function stops to try a sending
-
-/** PROGRAM GLOBAL VARIABLES **/
-uint8_t auto_mode_active = 0; // 1 if AM is active, 0 otherwise
-uint8_t serial_rdy = 0; // Flag for signaling that the Serial software buffer serialInput is full and ready to be consumed
-uint8_t message_rdy = 0; // Flag for signaling that a new message arrived on the MAC layer and is ready to be read
-int8_t send_result = -1; // Flag for sending-over-MAC logic, needed to handle sending failure
-int8_t status = 0; // State variable that is updated according to arriving messages and is used to feedback the CS when requested
-char serialInput[BUFFER_SIZE]; // Serial software buffer used to empty the hardware one as soon as a new command arrives
-
-/** PROGRAM LOCAL FUNCTIONS **/
-/*
-*********************************************************************************************************
-* OnDataRecv()
-*
-* Description : Callback for data arrival on the MAC layer: receives and manages the messages.
-* If the message_rdy flag is 0, the callback updates the message in the input data struct
-* with the incoming message and sets the flag. The flag will be reset to 0 after
-* the message has been consumed. Meanwhile no other incoming message will be accepted.
-*
-* Argument(s) : mac : MAC address of the peer from which the data was received.
-*
-* incomingData : Struct containing incoming data. Data maximum length is 250 bytes.
-*
-* len : Length of the received data.
-*
-* Return(s) : none
-*********************************************************************************************************
-*/
-void OnDataRecv (const uint8_t * mac, const uint8_t * incomingData, int len) {
-
- if (!message_rdy) {
- message_rdy = 1;
- memcpy(&input, incomingData, sizeof(input));
- }
-
-}
-
-/*
-*********************************************************************************************************
-* OnDataSent()
-*
-* Description : Callback for data sending on the MAC layer: it updates send_result flag to
-* inform other logics whether the sending of the last package went well or not.
-* The flag has to be cleared to -1 before each sending.
-*
-* Argument(s) : mac : MAC address of the peer to which the data was sended.
-*
-* status : Status of the sending. It evaluates to ESP_NOW_SEND_SUCCESS if it succeeded.
-*
-* Return(s) : none
-*********************************************************************************************************
-*/
-void OnDataSent (const uint8_t * mac, esp_now_send_status_t status) {
-
- if (status == ESP_NOW_SEND_SUCCESS) send_result = 1; // If sending succeeds sets the flag to 1
- else send_result = 0; // Otherwise sets it to 0
-
-}
-
-/*
-*********************************************************************************************************
-* send_command()
-*
-* Description : Function for command sending over the MAC layer: target peer is set during setup and
-* should be the FLOAT (ESPA). In case of sending failure, signalled by the send_result flag,
-* the message is continously sended until it succeeds or
-* the max_conn_time milliseconds elapse.
-*
-* Argument(s) : message_str : Char array containing the command code.
-*
-* max_conn_time : Time that has to elapse before stopping to try the sending.
-* Expressed in milliseconds.
-*
-* Return(s) : 1 if sending succeeded, 0 if given time elapsed.
-*********************************************************************************************************
-*/
-uint8_t send_command (uint8_t cmd_code, uint16_t max_conn_time) {
- output.command = cmd_code; // Command code is copied in the output data struct
- uint64_t prec_time = millis(); // A time reference (ms elapsed from startup) is stored in prec_time
- while (true) { // [* sending sequence start]
- send_result = -1; // send_result flat is cleared
- esp_now_send(broadcastAddress, (uint8_t *) &output, sizeof(output)); // Tries to send the code over MAC layer
- while(send_result == -1); // Waits for OnDataSent callback to set send_result flag
- if (send_result) return 1; // If sending succeeds, function returns 1
- else if (millis() - prec_time > max_conn_time) return 0; // If sending failed and max_conn_time milliseconds elapsed from time
- }// reference set, the function returns 0. Otherwise it starts
-// again the sending sequence from [* sending sequence start]
-}
-
-/*
-*********************************************************************************************************
-* serial_handler()
-*
-* Description : Callback function for Serial buffer management. If serialInput has already
-* been consumed, when new data arrives on the Serial channel, the function
-* takes up to 20 bytes from the hardware buffer, stopping at the new line
-* character, copies them into the serialInput char array and fills the rest with
-* string terminators. It also signals that the serialInput buffer is now ready to be
-* read by setting the serial_rdy flag, that will be cleared only after serialInput
-* consumption. Meanwhile all new data arrivals on Serial channel will be ignored.
-* The function should grant a certain level of reliability in case of multiple,
-* chained data arrivals, but remember that if the hardware buffer is full the new
-* data arrival will be lost on the channel. Moreover, a too high arrival rate
-* can lead to command losses even on the software side.
-*
-* Argument(s) : none
-*
-* Return(s) : none
-*********************************************************************************************************
-*/
-void serial_handler() {
- if (!serial_rdy) { // Checks if the flag is clear, hence serialInput is ready to be filled
- serial_rdy = 1; // Sets the serial_rdy flag, creating a lock on the serialInput array
-
- uint8_t buffer_index = 0;
- char c = Serial.read();
-
- while (c != '\n' && Serial.available()) { // While bytes are available on the channel and its not a new line
- serialInput[buffer_index++] = c; // Empties the harware buffer into the serialInput buffer
- c = Serial.read();
- }
- for(int i=buffer_index; i
+
+
+
+
+
+
+## Overview
+The ROV’s software stack is built around three integrated components: NEXUS, Oceanix, and STM Nucleo firmware. NEXUS, running on the control station, delivers real-time video, telemetry, and control to the pilot. Oceanix, hosted on a Raspberry Pi 5, handles mission logic, sensor fusion, and dynamic thrust allocation. The STM Nucleo executes low-level motor and actuator control via lightweight firmware, offering additional GPIOs with PWM support at very low cost. These components communicate via MQTT, I²C and a custom serial protocol, ensuring modularity, low latency, and robustness.
+The decision to adopt the Raspberry Pi 5 over alternatives like the NVIDIA Jetson Nano was driven by its efficiency, lower power consumption, and cost-effectiveness. While the Jetson’s GPU acceleration benefits AI workloads, our architecture prioritizes real-time control, sensor polling and network communication (tasks where the Pi 5's CPU is more than sufficient). Similarly, the STM Nucleo adds PWM-capable GPIOs and supports a modular architecture at minimal cost. This design allows us to upgrade sensors or control logic with minimal effort, supporting rapid development and scalability.
-
+
-## Components
-The firmware for a specific component can be find in [this](firmware/) directory...
\ No newline at end of file
+
+## NEXUS
+NEXUS is implemented as a Flask‑based Python application that delivers a desktop‑style web interface to the ROV pilot. Within the browser window, operators see five live feeds from the Raspberry Pi 5. This year, we upgraded the streaming system to WebRTC, enabling GPU-accelerated rendering of the video directly in the browser. This allowed us to reduce latency by up to 200 ms and add real-time lens distortion correction for improved camera visualization, while fully leveraging the onboard H.264 encoding of the two front cameras. Alongside the video panels, dynamic charts visualize the ROV’s attitude (roll, pitch, yaw) and depth readings from the Bar02 sensor. Float functions are accessed through a dedicated section. Commands, from joystick movements to arm actuation, are serialized as JSON and sent over MQTT to Oceanix.
+
+## Oceanix
+Oceanix is our C++ application running on the Raspberry Pi 5, structured in an object‑oriented paradigm to isolate sensors, controllers and communication services. The Pi hosts a Mosquitto MQTT broker that relays messages between NEXUS, the debug tool and Oceanix itself. Joystick inputs arrive on the command topic, the resulting force and moment vectors feed a thrust allocation algorithm that computes individual PWM setpoints for eight thrusters.
+These setpoints are forwarded over a high‑speed UART link to the STM Nucleo board. Simultaneously, Oceanix polls the onboard IMU and Bar02 sensor at 200 Hz via I²C, combining accelerometer, gyroscope and pressure data in a complementary filter to estimate depth and attitude.
+
+## STM Nucleo
+On the NUCLEO‑L432KC board, a bare‑metal C application built on ST’s HAL libraries listens on UART for a continuous stream of PWM duty‑cycle values and servo positions sent by Oceanix at 100 Hz. Each packet includes a CRC to verify integrity; in the event of a CRC failure, the firmware retains the previous command until valid data resumes. Hardware timers generate PWM signals with 1 µs resolution, which drive optocouplers feeding our motor driver MOSFETs. For arm control, a specially designed packet is received to regulate the actuator and driver, including their speed and direction. The firmware’s emphasis on deterministic timing and minimal interrupt jitter guarantees that high‑frequency control loops run reliably, enabling both precise thrust control and smooth manipulator operation.
+
+## Helper
+For deeper analysis and tuning, we maintain a companion Python/Tk debug tool that connects via MQTT to display raw sensor dumps, per‑motor thrust values, live logs and adjustable control‑loop parameters such as controller gains. This app is divided into windows, is very good for lab testing since all essentials commands can be send to Oceanix, also statuses are printed along with real time plot for controller tuning, camera streamning can be tested and snapshot can be taken, also the configuration page edits the config.json on the Raspberry Pi.
+
+# Usage
+in rasp_setup all tutorial for setting up a new raspberry are contained, focusing on the handling of the camera also in general .
+usage.md contains instructions for EVA.
\ No newline at end of file
diff --git a/docs/Usage.md b/Usage.md
similarity index 100%
rename from docs/Usage.md
rename to Usage.md
diff --git a/docs/Software_SID.png b/docs/Software_SID.png
new file mode 100644
index 0000000..43f1918
Binary files /dev/null and b/docs/Software_SID.png differ
diff --git a/docs/cad.png b/docs/cad.png
new file mode 100644
index 0000000..c31c1f8
Binary files /dev/null and b/docs/cad.png differ
diff --git a/docs/eva.jpg b/docs/eva.jpg
deleted file mode 100644
index fb73060..0000000
Binary files a/docs/eva.jpg and /dev/null differ
diff --git a/docs/eva.png b/docs/eva.png
new file mode 100644
index 0000000..af31a62
Binary files /dev/null and b/docs/eva.png differ
diff --git a/rasp_setup/Camera static link.md b/rasp_setup/Camera static link.md
new file mode 100644
index 0000000..1813c9a
--- /dev/null
+++ b/rasp_setup/Camera static link.md
@@ -0,0 +1,121 @@
+## 🎯 **Goal**
+
+Instead of dealing with changing `/dev/video4`, `/dev/video6`, etc., we want:
+
+```bash
+/dev/camera-bottom
+/dev/camera-top
+/dev/camera-main
+/dev/camera-right
+/dev/camera-arm
+```
+
+that always point to the correct camera, based on which USB port it’s plugged into.
+
+---
+
+## 🧰 Prerequisites
+
+Make sure you have:
+
+* `v4l-utils` installed (for `v4l2-ctl`)
+* root access (`sudo`)
+
+If not already installed:
+
+```bash
+sudo apt update
+sudo apt install v4l-utils
+```
+
+---
+
+## 📝 Step 1: List Video Devices
+
+List your connected cameras and the video devices they expose:
+
+```bash
+v4l2-ctl --list-devices
+```
+
+You'll see output like:
+
+```
+HD USB CAMERA: HD USB CAMERA (usb-xhci-hcd.0-2.2):
+ /dev/video4
+ /dev/video5
+
+exploreHD USB Camera: exploreHD (usb-xhci-hcd.0-2.4):
+ /dev/video8
+ /dev/video9
+```
+
+exploreHD USB Cameras are managed by DWE OS that already uses static path, so ignore these cameras in this tutorial
+
+---
+
+## 🔍 Step 2: Find the `ID_PATH` for the Correct Device
+
+Pick the device that corresponds to the **stream you want to use** (e.g. `/dev/video4`), then run:
+
+```bash
+udevadm info /dev/video4 | grep ID_PATH
+```
+
+You'll get something like:
+
+```
+E: ID_PATH=platform-xhci-hcd.0-usb-0:2.2:1.0
+```
+
+Write that down — that's the stable ID of that USB port.
+
+Repeat this for all cameras you want to assign.
+
+---
+
+## 🧩 Step 3: Create a udev Rule File
+
+Create a new udev rules file:
+
+```bash
+sudo nano /etc/udev/rules.d/99-usb-cameras.rules
+```
+
+Add one line per camera, like this:
+
+```udev
+# Bottom camera
+SUBSYSTEM=="video4linux", ENV{ID_PATH}=="platform-xhci-hcd.0-usb-0:2.2:1.0", ATTR{index}=="0", SYMLINK+="camera-bottom"
+
+# Top camera
+SUBSYSTEM=="video4linux", ENV{ID_PATH}=="platform-xhci-hcd.0-usb-0:2.3:1.0", ATTR{index}=="0", SYMLINK+="camera-top"
+```
+
+📌 **Make sure you adjust the `ID_PATH` values** to the correct ones from your own system.
+the ATTR{index}=="0" is to make sure we are selecting the right interface of the camera, for the DWE camera the index is 2 to use H.264
+
+---
+
+## 🔄 Step 4: Reload udev and Trigger
+
+```bash
+sudo udevadm control --reload-rules
+sudo udevadm trigger
+```
+
+Then check:
+
+```bash
+ls -l /dev/camera-*
+```
+
+You should see:
+
+```
+/dev/camera-bottom -> video4
+/dev/camera-top -> video6
+...
+```
+
+🎉 Done!
\ No newline at end of file
diff --git a/rasp_setup/Camera tutorial.md b/rasp_setup/Camera tutorial.md
new file mode 100644
index 0000000..c2a02d0
--- /dev/null
+++ b/rasp_setup/Camera tutorial.md
@@ -0,0 +1,45 @@
+# Linux Camera Systems
+
+Cameras in Linux are seen as `/dev/video*`. They have different output formats and resolutions. To check the available formats, use the following command:
+
+```bash
+v4l2-ctl -d /dev/video0 --list-formats-ext
+```
+
+after the camera static link setup is best to use:
+
+```bash
+v4l2-ctl -d /dev/camera-main --list-formats-ext
+```
+also to check that the ATTR{index} is set up correctly.
+
+## Camera Formats Explained
+
+The formats can be MJPG or H264:
+
+- **MJPG (Motion JPEG)**: A series of JPEG images sent in sequence.
+ - Pros: Higher quality, widely supported
+ - Cons: Higher bandwidth usage, must be transcoded for efficient streaming
+ - Must be encoded to H264 for efficient network streaming
+ - May introduce lag on the client side due to decoding overhead
+ - To stream in MJPG use ustreamer, easy to set up and easy to work with, also with the snapshots
+
+- **H264**: A compressed video format
+ - Pros: Already compressed, lower bandwidth, ready for Real-Time Communication (RTC)
+ - Cons: May have slightly lower quality than MJPG at the same bitrate
+ - DWE cameras can output compressed H264 natively and are streamed directly with DWE OS 2
+
+## Camera Identification
+
+To understand which camera is associated with a specific `/dev/video*`, use the following command:
+
+```bash
+v4l2-ctl --list-devices
+```
+
+This script will list all video devices and their corresponding camera models/types.
+
+
+## Port Configuration and Janus Integration
+
+Both DWE_OS_2 and GStreamer streams should target `127.0.0.1` (localhost), which is where Janus is running. The port selected for each camera stream must match the corresponding port defined in the Janus streaming configuration file (`janus.plugin.streaming.cfg`). In NEXUS, the different camera streams are then identified and displayed using their respective IDs configured in Janus.
\ No newline at end of file
diff --git a/rasp_setup/Install Oceanix.md b/rasp_setup/Install Oceanix.md
new file mode 100644
index 0000000..fbec017
--- /dev/null
+++ b/rasp_setup/Install Oceanix.md
@@ -0,0 +1,92 @@
+To install Oceanix:
+
+1. Clone the Oceanix repository:
+ ```bash
+ git clone https://github.com/PoliTOcean/Oceanix.git
+ cd Oceanix
+ ```
+
+2. Source the install script:
+ ```bash
+ source install.sh
+ ```
+
+3. To use I2C, enable it:
+
+ * Open the Raspberry Pi configuration:
+ ```bash
+ sudo raspi-config
+ ```
+ * Navigate to `Interface Options` -> `I2C` -> `` to enable it.
+ * Reboot the Raspberry Pi for the changes to take effect:
+ ```bash
+ sudo reboot
+ ```
+
+4. Automatic Execution with Systemd
+
+To automatically start Oceanix as a service on boot, you can use systemd.
+
+* Create the `oceanix.service` file in `/etc/systemd/system/`:
+
+ ```bash
+ sudo nano /etc/systemd/system/oceanix.service
+ ```
+
+* Add the following content to the `oceanix.service` file:
+
+ ```
+ [Unit]
+ Description=Oceanix Service
+ After=network.target
+
+ [Service]
+ ExecStart=/usr/bin/chrt -f 99 /home/politocean/firmware/Oceanix/build/Oceanix
+ WorkingDirectory=/home/politocean/firmware/Oceanix/build
+ Restart=always
+ User=root
+ Environment=DISPLAY=:0
+ CPUSchedulingPolicy=fifo
+ CPUSchedulingPriority=99
+
+ [Install]
+ WantedBy=multi-user.target
+ ```
+
+* **Important:** Verify that the `ExecStart` and `WorkingDirectory` paths are correct for your Oceanix installation. The `User` should be the user that owns the Oceanix installation.
+
+* Enable the Oceanix service:
+
+ ```bash
+ sudo systemctl enable oceanix.service
+ ```
+
+* restart the Oceanix service:
+
+ ```bash
+ sudo systemctl restart oceanix.service
+ ```
+
+* Start the Oceanix service:
+
+ ```bash
+ sudo systemctl start oceanix.service
+ ```
+
+* Check the status of the Oceanix service:
+
+ ```bash
+ sudo systemctl status oceanix.service
+ ```
+
+* To stop the Oceanix service:
+
+ ```bash
+ sudo systemctl stop oceanix.service
+ ```
+
+* To disable the Oceanix service:
+
+ ```bash
+ sudo systemctl disable oceanix.service
+ ```
\ No newline at end of file
diff --git a/rasp_setup/README.md b/rasp_setup/README.md
new file mode 100644
index 0000000..eaabe88
--- /dev/null
+++ b/rasp_setup/README.md
@@ -0,0 +1,26 @@
+# Raspberry Pi Setup - EVA 2025
+
+This directory contains guides and instructions for setting up the Raspberry Pi for the EVA 2025 project.
+
+## Installation Overview
+
+1. **Camera Setup**:
+ * Configure camera(s) in Linux.
+ * Understand camera formats (MJPG, H264).
+ * Stream video using GStreamer or DWE OS.
+ * Integrate with Janus WebRTC server.
+
+2. **Janus WebRTC Server**:
+ * Install and configure Janus for video streaming.
+ * Set up streaming plugins.
+
+3. **Oceanix**:
+ * Install the Oceanix software.
+ * Enable I2C.
+ * Configure automatic execution using systemd.
+
+## Guides
+
+* [Camera tutorial](./Camera%20tutorial.md): Explains how cameras work in Linux.
+* [Streaming](./Streaming.md): Details how to set up camera streaming with GStreamer and Janus.
+* [Install Oceanix](./Install%20Oceanix.md): Provides instructions for installing Oceanix.
diff --git a/rasp_setup/Set static IP.md b/rasp_setup/Set static IP.md
new file mode 100644
index 0000000..8887162
--- /dev/null
+++ b/rasp_setup/Set static IP.md
@@ -0,0 +1,67 @@
+### **Step-by-Step Guide to Set a Manual IP (10.0.0.254) on "Wired connection 1"**
+
+#### **1. Check Existing Connections**
+First, verify the exact name of your wired connection:
+```bash
+nmcli connection show
+```
+Look for `"Wired connection 1"` (or similar).
+
+#### **2. Set a Static IPv4 Address**
+Run:
+```bash
+nmcli connection modify "Wired connection 1" \
+ ipv4.method manual \
+ ipv4.addresses "10.0.0.254/24" \
+ ipv4.gateway "10.0.0.1" \
+ ipv4.dns "8.8.8.8,8.8.4.4"
+```
+- `ipv4.method manual` → Disables DHCP, enables static IP.
+- `ipv4.addresses "10.0.0.254/24"` → Sets IP `10.0.0.254` with subnet `/24` (`255.255.255.0`).
+- `ipv4.gateway "10.0.0.1"` → (Optional) Sets default gateway.
+- `ipv4.dns "8.8.8.8,8.8.4.4"` → (Optional) Sets Google DNS.
+
+> **Note:**
+> - If you **only** need the IP (no gateway/DNS), just set `ipv4.method` and `ipv4.addresses`.
+
+#### **3. Restart the Connection**
+Apply changes by restarting the connection:
+```bash
+nmcli connection down "Wired connection 1" && nmcli connection up "Wired connection 1"
+```
+
+#### **4. Verify the New IP**
+Check if the IP was assigned correctly:
+```bash
+hostname -I
+```
+or:
+```bash
+nmcli connection show "Wired connection 1" | grep ipv4.addresses
+```
+
+#### **5. Test Network Connectivity**
+Ping your gateway (or another device on the network):
+```bash
+ping 10.0.0.1
+```
+If no response, check:
+- Firewall rules (`sudo ufw status`).
+- Correct gateway/DNS settings.
+
+---
+
+### **Troubleshooting**
+#### **Issue 1: "Connection 'Wired connection 1' not found"**
+- **Fix:** List all connections with `nmcli connection show` and use the **exact** name (case-sensitive).
+
+#### **Issue 2: IP Doesn’t Apply After Restart**
+- **Fix:** Reload NetworkManager:
+ ```bash
+ sudo systemctl restart NetworkManager
+ ```
+
+#### **Issue 3: No Internet Access**
+- **Fix:** Ensure:
+ - Gateway (`10.0.0.1`) is correct.
+ - DNS is set (`nmcli con mod "Wired connection 1" ipv4.ignore-auto-dns no` if needed).
diff --git a/rasp_setup/Streaming.md b/rasp_setup/Streaming.md
new file mode 100644
index 0000000..84a091b
--- /dev/null
+++ b/rasp_setup/Streaming.md
@@ -0,0 +1,88 @@
+# Setting up Camera Streaming with GStreamer and Janus WebRTC
+
+This tutorial outlines the steps to set up camera streaming using GStreamer and Janus.
+Gstreamer is used to stream the camera using RTP protocol in H.264 encoding to the control station. On the control station the Janus server create the WebRTC access point for all apps.
+Janus server is installed on the control station and not on the Raspberry Pi to avoid overloading it, while the latency remains the same.
+
+## Step 1: Install GStreamer on Raspberry Pi
+
+Install GStreamer and the necessary plugins on your Raspberry Pi:
+
+```bash
+sudo apt update
+sudo apt install -y gstreamer1.0-tools gstreamer1.0-plugins-base gstreamer1.0-plugins-good gstreamer1.0-plugins-bad gstreamer1.0-plugins-ugly
+```
+
+## Step 2: Install Janus on Control station
+
+Use the installation script you can find in scripts/ to install Janus from source. Download the install_janus.sh and the janus.plugin.streaming.jcfg file which contain the streaming configuration
+
+```bash
+cd scripts/
+chmod +x ./install_janus.sh && ./install_janus.sh
+```
+
+## Step 3: Install and Configure DWE OS 2
+
+DWE OS 2 provides an alternative method for streaming H.264 encoded video directly from compatible cameras. Streaming directly with DWE OS often caused unexpected lag, install it only for controlling camera parameters such as brighness ecc.
+
+First, install DWE OS using the following commands:
+
+```bash
+curl -s https://raw.githubusercontent.com/DeepwaterExploration/DWE_OS_2/main/install.sh | sudo bash -s
+```
+
+After installation, access the DWE OS interface by navigating to the Raspberry Pi's IP address in a web browser (e.g., `http://`). You should see the connected camera(s) listed.
+
+## Step 4: Configure the streaming pipeline
+
+Copy all the start_camera_stream_'camera'.sh scripts in a folder on the Raspberry Pi. If you execute manually and Janus is already configured you shoud see from janus that the camera stream are found. Remember to change the IP in the scripts to the Control Station LAN IP.
+The resolution, bitrate and framerate ensure that the streaing of the 5 cameras does not overload the Raspberry Pi. However can be changed with other supported resolution, you can see the list with v4l2-ctl -d "camera" --list-formats-ext (Camera tutorial).
+
+To launch directly the script:
+```bash
+chmod +x ./start_camera_stream_main.sh && ./start_camera_stream_main.sh
+```
+
+If the test is passed now configura automatic stream at startup with systemctl service.
+
+* Create the `camera_stream_main.service` file in `/etc/systemd/system/`:
+
+ ```bash
+ sudo nano /etc/systemd/system/camera_stream_main.service
+ ```
+
+* Add the following content to the `camera_stream_main.service` file:
+
+ ```
+ [Unit]
+ Description=Camera Stream Service
+ After=network.target
+
+ [Service]
+ ExecStart=/home/politocean/firmware/start_camera_stream_main.sh
+ Restart=always
+ RestartSec=5
+ User=root
+ Environment=DISPLAY=:0
+ Environment=XAUTHORITY=/home/pi/.Xauthority
+
+ [Install]
+ WantedBy=multi-user.target
+ ```
+
+* **Important:** Verify that the `ExecStart` path is correct: you must put the script absolute path.
+
+* Enable the service:
+
+ ```bash
+ sudo systemctl enable camera_stream_main.service
+ ```
+
+* restart (or start) the service:
+
+ ```bash
+ sudo systemctl restart camera_stream_main.service
+ ```
+
+ Repeat all the steps for each camera
diff --git a/rasp_setup/scripts/install_janus.sh b/rasp_setup/scripts/install_janus.sh
new file mode 100644
index 0000000..f2523e7
--- /dev/null
+++ b/rasp_setup/scripts/install_janus.sh
@@ -0,0 +1,116 @@
+#!/bin/bash
+set -e # Exit immediately if a command exits with a non-zero status.
+set -u # Treat unset variables as an error.
+
+SCRIPT_DIR=$(dirname "$0")
+
+# --- Configuration ---
+JANUS_GIT_URL="https://github.com/meetecho/janus-gateway.git"
+JANUS_VERSION="master" # Or a specific tag like "v1.x.x". If using a tag, adjust git pull logic below.
+JANUS_INSTALL_PREFIX="/opt/janus"
+JANUS_CONFIG_DIR="${JANUS_INSTALL_PREFIX}/etc/janus"
+JANUS_PLUGIN_DIR="${JANUS_INSTALL_PREFIX}/lib/janus/plugins"
+CUSTOM_STREAMING_CONFIG_SOURCE="${SCRIPT_DIR}/janus.plugin.streaming.jcfg"
+CUSTOM_STREAMING_CONFIG_DEST="${JANUS_CONFIG_DIR}/janus.plugin.streaming.jcfg"
+
+# --- Script Start ---
+echo "Starting Janus Gateway installation and setup script..."
+echo "Janus will be installed to: ${JANUS_INSTALL_PREFIX}"
+echo "Configuration files will be in: ${JANUS_CONFIG_DIR}"
+
+# 1. Install System Dependencies
+echo "Updating package list and installing dependencies..."
+sudo apt-get update
+sudo apt-get install -y --no-install-recommends \
+ git \
+ libmicrohttpd-dev \
+ libjansson-dev \
+ libssl-dev \
+ libsofia-sip-ua-dev \
+ libglib2.0-dev \
+ libopus-dev \
+ libogg-dev \
+ libcurl4-openssl-dev \
+ liblua5.3-dev \
+ libconfig-dev \
+ pkg-config \
+ gengetopt \
+ libtool \
+ automake \
+ build-essential \
+ cmake \
+ ninja-build \
+ libnice-dev \
+ libsrtp2-dev \
+ libwebsockets-dev \
+ libavutil-dev \
+ libavcodec-dev \
+ libavformat-dev \
+ ffmpeg
+ # Add doxygen and graphviz if docs are needed (and --disable-docs is removed from ./configure)
+ # doxygen graphviz
+
+# 2. Clone and Build Janus Gateway
+echo "Cloning/updating Janus Gateway repository..."
+# The script assumes it's run from a directory where 'janus-gateway' can be cloned.
+# For example, if install.sh is in /workspaces/NEXUS/tests/stream_video/JANUS/,
+# janus-gateway will be cloned to /workspaces/NEXUS/tests/stream_video/JANUS/janus-gateway/
+if [ -d "janus-gateway" ]; then
+ echo "Janus gateway directory exists. Changing to it and pulling latest changes for branch/tag '${JANUS_VERSION}'..."
+ cd janus-gateway
+ # If JANUS_VERSION is a specific tag, 'git pull' might not be what you want.
+ # You might need: git fetch origin && git checkout ${JANUS_VERSION}
+ git pull origin ${JANUS_VERSION}
+else
+ echo "Cloning Janus Gateway (branch/tag: ${JANUS_VERSION})..."
+ git clone --branch ${JANUS_VERSION} ${JANUS_GIT_URL}
+ cd janus-gateway
+fi
+
+echo "Configuring Janus Gateway..."
+./autogen.sh
+./configure --prefix=${JANUS_INSTALL_PREFIX} \
+ --enable-plugin-streaming \
+ --enable-websockets \
+ --disable-data-channels \
+ --disable-rabbitmq \
+ --disable-mqtt \
+ --disable-docs \
+ --disable-turn-rest-api \
+ --enable-post-processing \
+ # Add other --enable-plugin-* or --disable-plugin-* flags as needed.
+ # For example, to enable WebSockets: --enable-websockets (requires libwebsockets-dev)
+ # To enable DataChannels: --enable-data-channels (requires libusrsctp-dev)
+
+echo "Building Janus Gateway (this may take a while)..."
+make -j$(nproc)
+echo "Installing Janus Gateway..."
+sudo make install
+echo "Installing default Janus configurations..."
+sudo make configs # Copies default .cfg files to ${JANUS_CONFIG_DIR}
+
+# 4. Finalize Configuration (Optional)
+# At this point, Janus is installed, and default configs are in ${JANUS_CONFIG_DIR}.
+# You can add sed/awk commands here to modify janus.cfg or plugin-specific .jcfg files if needed.
+# For example, to enable specific features in janus.plugin.streaming.jcfg.
+
+cd ..
+# Copy custom janus.plugin.streaming.jcfg if it exists in the script's directory
+if [ -f "${CUSTOM_STREAMING_CONFIG_SOURCE}" ]; then
+ echo "Found custom streaming plugin configuration at '${CUSTOM_STREAMING_CONFIG_SOURCE}'."
+ echo "Copying to '${CUSTOM_STREAMING_CONFIG_DEST}'..."
+ sudo cp "${CUSTOM_STREAMING_CONFIG_SOURCE}" "${CUSTOM_STREAMING_CONFIG_DEST}"
+ echo "Custom streaming plugin configuration copied."
+else
+ echo "ERROR: Custom streaming plugin configuration not found. Please ensure the file exists at '${CUSTOM_STREAMING_CONFIG_SOURCE}'."
+ echo "Streaming will not work without this configuration."
+ echo "Please check the path and try again."
+ echo "Exiting..."
+ exit 1
+fi
+
+echo "Janus installation and configuration steps completed."
+echo "Default Janus configuration files are in: ${JANUS_CONFIG_DIR}"
+echo "Janus plugins (including janus_streaming.so if enabled) are in: ${JANUS_PLUGIN_DIR}"
+echo " "
+echo "[✓] All done! Janus Gateway is installed and configured."
diff --git a/rasp_setup/scripts/janus.plugin.streaming.jcfg b/rasp_setup/scripts/janus.plugin.streaming.jcfg
new file mode 100644
index 0000000..7b272a2
--- /dev/null
+++ b/rasp_setup/scripts/janus.plugin.streaming.jcfg
@@ -0,0 +1,60 @@
+camera1: {
+ type = "rtp"
+ id = 1
+ description = "main"
+ video = true
+ videoport = 5001
+ videopt = 100
+ videocodec= "h264"
+ videortpmap= "H264/90000"
+ videofmtp= "profile-level-id=42e01f;packetization-mode=1"
+ metadata= "{\"fisheye\": false, \"fisheyeSettings\": {\"fov\": {\"x\": 0, \"y\": 0}, \"lens\": {\"a\": 0.5, \"b\": 0.75, \"Fx\": 0.12, \"Fy\": 0.22, \"scale\": 0.8}}}"
+}
+camera2: {
+ type = "rtp"
+ id = 2
+ description = "right"
+ video = true
+ videoport = 5002
+ videopt = 100
+ videocodec= "h264"
+ videortpmap= "H264/90000"
+ videofmtp= "profile-level-id=42e01f;packetization-mode=1"
+ metadata= "{\"fisheye\": false, \"fisheyeSettings\": {\"fov\": {\"x\": 0, \"y\": 0}, \"lens\": {\"a\": 0.5, \"b\": 0.75, \"Fx\": 0.12, \"Fy\": 0.22, \"scale\": 0.8}}}"
+}
+camera3: {
+ type = "rtp"
+ id = 3
+ description = "top"
+ video = true
+ videoport = 5003
+ videopt = 100
+ videocodec= "h264"
+ videortpmap= "H264/90000"
+ videofmtp= "profile-level-id=42e01f;packetization-mode=1"
+ metadata= "{\"fisheye\": true, \"fisheyeSettings\": {\"fov\": {\"x\": 0, \"y\": 0}, \"lens\": {\"a\": 0.5, \"b\": 0.75, \"Fx\": 0.12, \"Fy\": 0.22, \"scale\": 0.8}}}"
+}
+camera4: {
+ type = "rtp"
+ id = 4
+ description = "bottom"
+ video = true
+ videoport = 5004
+ videopt = 100
+ videocodec= "h264"
+ videortpmap= "H264/90000"
+ videofmtp= "profile-level-id=42e01f;packetization-mode=1"
+ metadata= "{\"fisheye\": true, \"fisheyeSettings\": {\"fov\": {\"x\": 0, \"y\": 0}, \"lens\": {\"a\": 0.5, \"b\": 0.75, \"Fx\": 0.12, \"Fy\": 0.22, \"scale\": 0.8}}}"
+}
+camera5: {
+ type = "rtp"
+ id = 5
+ description = "arm"
+ video = true
+ videoport = 5005
+ videopt = 100
+ videocodec= "h264"
+ videortpmap= "H264/90000"
+ videofmtp= "profile-level-id=42e01f;packetization-mode=1"
+ metadata= "{\"fisheye\": false, \"fisheyeSettings\": {\"fov\": {\"x\": 0, \"y\": 0}, \"lens\": {\"a\": 0.5, \"b\": 0.75, \"Fx\": 0.12, \"Fy\": 0.22, \"scale\": 0.8}}}"
+}
diff --git a/rasp_setup/scripts/start_camera_stream_arm.sh b/rasp_setup/scripts/start_camera_stream_arm.sh
new file mode 100644
index 0000000..189ac80
--- /dev/null
+++ b/rasp_setup/scripts/start_camera_stream_arm.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+gst-launch-1.0 v4l2src device=/dev/camera-arm ! \
+ image/jpeg,width=800,height=600,framerate=30/1 ! \
+ jpegdec ! videoconvert ! x264enc \
+ tune=zerolatency bitrate=3000 speed-preset=superfast ! \
+ h264parse ! rtph264pay config-interval=1 pt=96 ! \
+ udpsink host=10.0.0.192 port=5005
diff --git a/rasp_setup/scripts/start_camera_stream_bottom.sh b/rasp_setup/scripts/start_camera_stream_bottom.sh
new file mode 100644
index 0000000..f5ee77f
--- /dev/null
+++ b/rasp_setup/scripts/start_camera_stream_bottom.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+gst-launch-1.0 v4l2src device=/dev/camera-bottom ! \
+ image/jpeg,width=1600,height=1200,framerate=15/1 ! \
+ jpegdec ! videoconvert ! x264enc \
+ tune=zerolatency bitrate=3000 speed-preset=superfast ! \
+ h264parse ! rtph264pay config-interval=1 pt=96 ! \
+ udpsink host=10.0.0.192 port=5003
diff --git a/rasp_setup/scripts/start_camera_stream_main.sh b/rasp_setup/scripts/start_camera_stream_main.sh
new file mode 100644
index 0000000..aa01cb0
--- /dev/null
+++ b/rasp_setup/scripts/start_camera_stream_main.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+gst-launch-1.0 v4l2src device=/dev/camera-main ! \
+ video/x-h264,width=1280,height=720,framerate=25/1 ! \
+ h264parse ! queue ! rtph264pay config-interval=10 pt=96 ! \
+ udpsink host=10.0.0.192 port=5001
\ No newline at end of file
diff --git a/rasp_setup/scripts/start_camera_stream_right.sh b/rasp_setup/scripts/start_camera_stream_right.sh
new file mode 100644
index 0000000..50a58d0
--- /dev/null
+++ b/rasp_setup/scripts/start_camera_stream_right.sh
@@ -0,0 +1,6 @@
+#!/bin/bash
+
+gst-launch-1.0 v4l2src device=/dev/camera-right ! \
+ video/x-h264,width=1280,height=720,framerate=20/1 ! \
+ h264parse ! queue ! rtph264pay config-interval=10 pt=96 ! \
+ udpsink host=10.0.0.192 port=5002
\ No newline at end of file
diff --git a/rasp_setup/scripts/start_camera_stream_top.sh b/rasp_setup/scripts/start_camera_stream_top.sh
new file mode 100644
index 0000000..12ad472
--- /dev/null
+++ b/rasp_setup/scripts/start_camera_stream_top.sh
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+gst-launch-1.0 v4l2src device=/dev/camera-top ! \
+ image/jpeg,width=1600,height=1200,framerate=15/1 ! \
+ jpegdec ! videoconvert ! x264enc \
+ tune=zerolatency bitrate=3000 speed-preset=superfast ! \
+ h264parse ! rtph264pay config-interval=1 pt=96 ! \
+ udpsink host=10.0.0.192 port=5004