From 1bc0f3d810e6ebe457e100e7152c378be66aa5cf Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Mon, 11 Nov 2024 14:41:27 +0100
Subject: [PATCH 01/14] [RIG] Update loadcell calibration

---
 src/RIGv2/Configs/SensorsConfig.h | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/RIGv2/Configs/SensorsConfig.h b/src/RIGv2/Configs/SensorsConfig.h
index 6348afffa..44b873702 100644
--- a/src/RIGv2/Configs/SensorsConfig.h
+++ b/src/RIGv2/Configs/SensorsConfig.h
@@ -123,13 +123,14 @@ constexpr float TANK_P1_MASS    = 6.916;
 // LC Vessel sensor calibration data
 // - 1.866kg V: 0.00027
 // - 5.050kg V: 0.00073
-// - 6.916kg V: 0.00100
+// - 6.916kg V: 0.00100000941
 constexpr float VESSEL_P0_VOLTAGE = 0.00027;
 constexpr float VESSEL_P0_MASS    = 1.866;
 constexpr float VESSEL_P1_VOLTAGE = 0.0010;
 constexpr float VESSEL_P1_MASS    = 6.916;
 */
 
+/*
 // LC Vessel sensor calibration data (post 07/09/2024)
 // - 0kg      V: 0.000630177
 // - 4.985kg  V: 0.000470017 (−31125.124875125 kg/v)
@@ -138,7 +139,15 @@ constexpr float VESSEL_P0_VOLTAGE = 0.000470017;
 constexpr float VESSEL_P0_MASS    = 4.985;
 constexpr float VESSEL_P1_VOLTAGE = 0.00030895;
 constexpr float VESSEL_P1_MASS    = 10.177;
+*/
 
+// LC Vessel sensor calibration data (post 08/11/2024, old flipping)
+// - 0kg      V: -0.009553
+// - 8.720kg  V: -0.010958 (−31125.124875125 kg/v)
+constexpr float VESSEL_P0_VOLTAGE = -0.009553;
+constexpr float VESSEL_P0_MASS    = 0.0;
+constexpr float VESSEL_P1_VOLTAGE = -0.010958;
+constexpr float VESSEL_P1_MASS    = 8.720;
 }  // namespace LoadCell
 
 namespace InternalADC
-- 
GitLab


From 946432821627cc7febc113804a1c2bd021f3da10 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Mon, 11 Nov 2024 14:42:40 +0100
Subject: [PATCH 02/14] [RIG] Update detach servo config for nitrogen use

---
 src/RIGv2/Actuators/Actuators.cpp   | 2 +-
 src/RIGv2/Configs/ActuatorsConfig.h | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/RIGv2/Actuators/Actuators.cpp b/src/RIGv2/Actuators/Actuators.cpp
index 26e294282..beedaff56 100644
--- a/src/RIGv2/Actuators/Actuators.cpp
+++ b/src/RIGv2/Actuators/Actuators.cpp
@@ -125,7 +125,7 @@ Actuators::Actuators()
         Config::Servos::FREQUENCY);
     infos[2].servo = std::make_unique<Servo>(
         MIOSIX_SERVOS_3_TIM, TimerUtils::Channel::MIOSIX_SERVOS_3_CHANNEL,
-        Config::Servos::SERVO2_MIN_PULSE, Config::Servos::SERVO2_MAX_PULSE,
+        Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
         Config::Servos::FREQUENCY);
     infos[3].servo = std::make_unique<Servo>(
         MIOSIX_SERVOS_4_TIM, TimerUtils::Channel::MIOSIX_SERVOS_4_CHANNEL,
diff --git a/src/RIGv2/Configs/ActuatorsConfig.h b/src/RIGv2/Configs/ActuatorsConfig.h
index bfa3ddf43..7d7fee299 100644
--- a/src/RIGv2/Configs/ActuatorsConfig.h
+++ b/src/RIGv2/Configs/ActuatorsConfig.h
@@ -72,7 +72,7 @@ constexpr bool FILLING_FLIPPED    = true;
 constexpr bool VENTING_FLIPPED    = true;
 constexpr bool MAIN_FLIPPED       = true;
 constexpr bool RELEASE_FLIPPED    = true;
-constexpr bool DISCONNECT_FLIPPED = false;
+constexpr bool DISCONNECT_FLIPPED = true;
 
 }  // namespace Servos
 
-- 
GitLab


From 62750bb9733f86a1a4d7220ee4765a61184adb4d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Tue, 26 Nov 2024 13:56:18 +0100
Subject: [PATCH 03/14] [RIGv2] Introduce initial Orion servos and new conrig
 buttons

---
 src/RIGv2/Actuators/Actuators.cpp       |  89 ++++++++++++++-----
 src/RIGv2/Actuators/Actuators.h         |   2 +-
 src/RIGv2/CanHandler/CanHandler.h       |   2 +-
 src/RIGv2/Configs/ActuatorsConfig.h     |   2 +-
 src/RIGv2/Configs/RadioConfig.h         |   2 +-
 src/RIGv2/Radio/Radio.cpp               | 110 +++++++++++++++++-------
 src/RIGv2/Radio/Radio.h                 |   2 +-
 src/RIGv2/StateMachines/TARS1/TARS1.cpp |  10 +--
 8 files changed, 156 insertions(+), 63 deletions(-)

diff --git a/src/RIGv2/Actuators/Actuators.cpp b/src/RIGv2/Actuators/Actuators.cpp
index beedaff56..cb671723e 100644
--- a/src/RIGv2/Actuators/Actuators.cpp
+++ b/src/RIGv2/Actuators/Actuators.cpp
@@ -132,7 +132,8 @@ Actuators::Actuators()
         Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
         Config::Servos::FREQUENCY);
     // This servo is currently unusable, due to it sharing the same timer as
-    // miosix, TIM5 infos[4].servo = std::make_unique<Servo>(
+    // miosix, TIM5
+    // infos[4].servo = std::make_unique<Servo>(
     //     MIOSIX_SERVOS_5_TIM, TimerUtils::Channel::MIOSIX_SERVOS_5_CHANNEL,
     //     Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
     //     Config::Servos::FREQUENCY);
@@ -142,10 +143,11 @@ Actuators::Actuators()
         Config::Servos::FREQUENCY);
     infos[6].servo = std::make_unique<Servo>(
         MIOSIX_SERVOS_7_TIM, TimerUtils::Channel::MIOSIX_SERVOS_7_CHANNEL,
-        Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
+        Config::Servos::SERVO2_MIN_PULSE, Config::Servos::SERVO2_MAX_PULSE,
         Config::Servos::FREQUENCY);
     // This servo is currently unusable, due to it sharing the same timer as
-    // servo 1 infos[7].servo = std::make_unique<Servo>(
+    // servo 1
+    // infos[7].servo = std::make_unique<Servo>(
     //     MIOSIX_SERVOS_8_TIM, TimerUtils::Channel::MIOSIX_SERVOS_8_CHANNEL,
     //     Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
     //     Config::Servos::FREQUENCY);
@@ -159,7 +161,7 @@ Actuators::Actuators()
         Config::Servos::FREQUENCY);
 
     ServoInfo* info;
-    info                     = getServo(ServosList::FILLING_VALVE);
+    info                     = getServo(ServosList::N2O_FILLING_VALVE);
     info->defaultMaxAperture = Config::Servos::DEFAULT_FILLING_MAX_APERTURE;
     info->defaultOpeningTime = Config::Servos::DEFAULT_FILLING_OPENING_TIME;
     info->limit              = Config::Servos::FILLING_LIMIT;
@@ -170,7 +172,7 @@ Actuators::Actuators()
     info->maxApertureKey     = CONFIG_ID_FILLING_MAX_APERTURE;
     info->unsafeSetServoPosition(0.0f);
 
-    info                     = getServo(ServosList::RELEASE_VALVE);
+    info                     = getServo(ServosList::N2O_RELEASE_VALVE);
     info->defaultMaxAperture = Config::Servos::DEFAULT_RELEASE_MAX_APERTURE;
     info->defaultOpeningTime = Config::Servos::DEFAULT_RELEASE_OPENING_TIME;
     info->limit              = Config::Servos::RELEASE_LIMIT;
@@ -181,7 +183,40 @@ Actuators::Actuators()
     info->maxApertureKey     = CONFIG_ID_RELEASE_MAX_APERTURE;
     info->unsafeSetServoPosition(0.0f);
 
-    info                     = getServo(ServosList::DISCONNECT_SERVO);
+    info                     = getServo(ServosList::N2O_VENTING_VALVE);
+    info->defaultMaxAperture = Config::Servos::DEFAULT_VENTING_MAX_APERTURE;
+    info->defaultOpeningTime = Config::Servos::DEFAULT_VENTING_OPENING_TIME;
+    info->limit              = Config::Servos::VENTING_LIMIT;
+    info->flipped            = Config::Servos::VENTING_FLIPPED;
+    info->openingEvent       = Common::Events::MOTOR_OPEN_VENTING_VALVE;
+    info->closingEvent       = Common::Events::MOTOR_CLOSE_VENTING_VALVE;
+    info->openingTimeKey     = CONFIG_ID_VENTING_OPENING_TIME;
+    info->maxApertureKey     = CONFIG_ID_VENTING_MAX_APERTURE;
+    info->unsafeSetServoPosition(0.0f);
+
+    info                     = getServo(ServosList::N2_FILLING_VALVE);
+    info->defaultMaxAperture = Config::Servos::DEFAULT_FILLING_MAX_APERTURE;
+    info->defaultOpeningTime = Config::Servos::DEFAULT_FILLING_OPENING_TIME;
+    info->limit              = Config::Servos::FILLING_LIMIT;
+    info->flipped            = Config::Servos::FILLING_FLIPPED;
+    info->openingEvent       = Common::Events::MOTOR_OPEN_FILLING_VALVE;
+    info->closingEvent       = Common::Events::MOTOR_CLOSE_FILLING_VALVE;
+    info->openingTimeKey     = CONFIG_ID_FILLING_OPENING_TIME;
+    info->maxApertureKey     = CONFIG_ID_FILLING_MAX_APERTURE;
+    info->unsafeSetServoPosition(0.0f);
+
+    info                     = getServo(ServosList::N2_RELEASE_VALVE);
+    info->defaultMaxAperture = Config::Servos::DEFAULT_RELEASE_MAX_APERTURE;
+    info->defaultOpeningTime = Config::Servos::DEFAULT_RELEASE_OPENING_TIME;
+    info->limit              = Config::Servos::RELEASE_LIMIT;
+    info->flipped            = Config::Servos::RELEASE_FLIPPED;
+    info->openingEvent       = Common::Events::MOTOR_OPEN_RELEASE_VALVE;
+    info->closingEvent       = Common::Events::MOTOR_CLOSE_RELEASE_VALVE;
+    info->openingTimeKey     = CONFIG_ID_RELEASE_OPENING_TIME;
+    info->maxApertureKey     = CONFIG_ID_RELEASE_MAX_APERTURE;
+    info->unsafeSetServoPosition(0.0f);
+
+    info                     = getServo(ServosList::N2_DETACH_SERVO);
     info->defaultMaxAperture = Config::Servos::DEFAULT_DISCONNECT_MAX_APERTURE;
     info->defaultOpeningTime = Config::Servos::DEFAULT_DISCONNECT_OPENING_TIME;
     info->limit              = Config::Servos::DISCONNECT_LIMIT;
@@ -202,15 +237,15 @@ Actuators::Actuators()
     info->maxApertureKey     = CONFIG_ID_MAIN_MAX_APERTURE;
     info->unsafeSetServoPosition(0.0f);
 
-    info                     = getServo(ServosList::VENTING_VALVE);
-    info->defaultMaxAperture = Config::Servos::DEFAULT_VENTING_MAX_APERTURE;
-    info->defaultOpeningTime = Config::Servos::DEFAULT_VENTING_OPENING_TIME;
-    info->limit              = Config::Servos::VENTING_LIMIT;
-    info->flipped            = Config::Servos::VENTING_FLIPPED;
-    info->openingEvent       = Common::Events::MOTOR_OPEN_VENTING_VALVE;
-    info->closingEvent       = Common::Events::MOTOR_CLOSE_VENTING_VALVE;
-    info->openingTimeKey     = CONFIG_ID_VENTING_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_VENTING_MAX_APERTURE;
+    info                     = getServo(ServosList::NITROGEN_VALVE);
+    info->defaultMaxAperture = Config::Servos::DEFAULT_MAIN_MAX_APERTURE;
+    info->defaultOpeningTime = Config::Servos::DEFAULT_MAIN_OPENING_TIME;
+    info->limit              = Config::Servos::MAIN_LIMIT;
+    info->flipped            = Config::Servos::MAIN_FLIPPED;
+    info->openingEvent       = 0;
+    info->closingEvent       = 0;
+    info->openingTimeKey     = CONFIG_ID_MAIN_OPENING_TIME;
+    info->maxApertureKey     = CONFIG_ID_MAIN_MAX_APERTURE;
     info->unsafeSetServoPosition(0.0f);
 }
 
@@ -328,7 +363,8 @@ void Actuators::closeAllServos()
         infos[idx].closeServo();
 
     getModule<CanHandler>()->sendServoCloseCommand(ServosList::MAIN_VALVE);
-    getModule<CanHandler>()->sendServoCloseCommand(ServosList::VENTING_VALVE);
+    getModule<CanHandler>()->sendServoCloseCommand(
+        ServosList::N2O_VENTING_VALVE);
 }
 
 bool Actuators::setMaxAperture(ServosList servo, float aperture)
@@ -366,7 +402,7 @@ bool Actuators::isCanServoOpen(ServosList servo)
     Lock<FastMutex> lock(infosMutex);
     if (servo == ServosList::MAIN_VALVE)
         return canMainOpen;
-    else if (servo == ServosList::VENTING_VALVE)
+    else if (servo == ServosList::N2O_VENTING_VALVE)
         return canVentingOpen;
     else
         return false;
@@ -423,7 +459,7 @@ void Actuators::setCanServoOpen(ServosList servo, bool open)
     Lock<FastMutex> lock(infosMutex);
     if (servo == ServosList::MAIN_VALVE)
         canMainOpen = open;
-    else if (servo == ServosList::VENTING_VALVE)
+    else if (servo == ServosList::N2O_VENTING_VALVE)
         canVentingOpen = open;
 }
 
@@ -436,18 +472,25 @@ void Actuators::inject(DependencyInjector& injector)
 
 Actuators::ServoInfo* Actuators::getServo(ServosList servo)
 {
+    // info[4] and info[7] are currently unavailable
     switch (servo)
     {
-        case FILLING_VALVE:
+        case N2O_FILLING_VALVE:
             return &infos[0];
-        case RELEASE_VALVE:
+        case N2O_RELEASE_VALVE:
             return &infos[1];
-        case DISCONNECT_SERVO:
+        case N2O_VENTING_VALVE:
             return &infos[2];
-        case MAIN_VALVE:
+        case N2_FILLING_VALVE:
             return &infos[3];
-        case VENTING_VALVE:
+        case N2_RELEASE_VALVE:
+            return &infos[5];
+        case N2_DETACH_SERVO:
             return &infos[6];
+        case MAIN_VALVE:
+            return &infos[8];
+        case NITROGEN_VALVE:
+            return &infos[9];
 
         default:
             // Oh FUCK
diff --git a/src/RIGv2/Actuators/Actuators.h b/src/RIGv2/Actuators/Actuators.h
index 58342d074..41cf009ff 100644
--- a/src/RIGv2/Actuators/Actuators.h
+++ b/src/RIGv2/Actuators/Actuators.h
@@ -26,7 +26,7 @@
 #include <RIGv2/CanHandler/CanHandler.h>
 #include <RIGv2/Registry/Registry.h>
 #include <actuators/Servo/Servo.h>
-#include <common/MavlinkLyra.h>
+#include <common/MavlinkOrion.h>
 #include <miosix.h>
 #include <scheduler/TaskScheduler.h>
 
diff --git a/src/RIGv2/CanHandler/CanHandler.h b/src/RIGv2/CanHandler/CanHandler.h
index 282d8eef9..0b8a305e5 100644
--- a/src/RIGv2/CanHandler/CanHandler.h
+++ b/src/RIGv2/CanHandler/CanHandler.h
@@ -26,7 +26,7 @@
 #include <RIGv2/Configs/CanHandlerConfig.h>
 #include <RIGv2/Sensors/Sensors.h>
 #include <common/CanConfig.h>
-#include <common/MavlinkLyra.h>
+#include <common/MavlinkOrion.h>
 #include <drivers/canbus/CanProtocol/CanProtocol.h>
 #include <utils/DependencyManager/DependencyManager.h>
 
diff --git a/src/RIGv2/Configs/ActuatorsConfig.h b/src/RIGv2/Configs/ActuatorsConfig.h
index 7d7fee299..bfa3ddf43 100644
--- a/src/RIGv2/Configs/ActuatorsConfig.h
+++ b/src/RIGv2/Configs/ActuatorsConfig.h
@@ -72,7 +72,7 @@ constexpr bool FILLING_FLIPPED    = true;
 constexpr bool VENTING_FLIPPED    = true;
 constexpr bool MAIN_FLIPPED       = true;
 constexpr bool RELEASE_FLIPPED    = true;
-constexpr bool DISCONNECT_FLIPPED = true;
+constexpr bool DISCONNECT_FLIPPED = false;
 
 }  // namespace Servos
 
diff --git a/src/RIGv2/Configs/RadioConfig.h b/src/RIGv2/Configs/RadioConfig.h
index 98830ac09..af1b8643e 100644
--- a/src/RIGv2/Configs/RadioConfig.h
+++ b/src/RIGv2/Configs/RadioConfig.h
@@ -22,7 +22,7 @@
 
 #pragma once
 
-#include <common/MavlinkLyra.h>
+#include <common/MavlinkOrion.h>
 
 namespace RIGv2
 {
diff --git a/src/RIGv2/Radio/Radio.cpp b/src/RIGv2/Radio/Radio.cpp
index 5e7bdc47a..f657b77f3 100644
--- a/src/RIGv2/Radio/Radio.cpp
+++ b/src/RIGv2/Radio/Radio.cpp
@@ -515,10 +515,18 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             tm.timestamp = TimestampTimer::getTimestamp();
 
             // Sensors
-            tm.loadcell_rocket  = sensors->getTankWeightLastSample().load;
-            tm.loadcell_vessel  = sensors->getVesselWeightLastSample().load;
-            tm.filling_pressure = sensors->getFillingPressLastSample().pressure;
-            tm.vessel_pressure  = sensors->getVesselPressLastSample().pressure;
+            tm.rocket_mass     = sensors->getTankWeightLastSample().load;
+            tm.n2o_vessel_mass = sensors->getVesselWeightLastSample().load;
+
+            tm.n2o_filling_pressure =
+                sensors->getFillingPressLastSample().pressure;
+            tm.n2o_vessel_pressure =
+                sensors->getVesselPressLastSample().pressure;
+
+            tm.n2_filling_pressure  = -1.f;  // TODO
+            tm.n2_vessel_1_pressure = -1.f;  // TODO
+            tm.n2_vessel_2_pressure = -1.f;  // TODO
+
             tm.battery_voltage = sensors->getBatteryVoltageLastSample().voltage;
             tm.current_consumption =
                 sensors->getServoCurrentLastSample().current;
@@ -540,15 +548,28 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             sdLogger.log(cpuStats);
 
             // Valve states
-            tm.filling_valve_state =
-                actuators->isServoOpen(ServosList::FILLING_VALVE) ? 1 : 0;
-            tm.venting_valve_state =
-                actuators->isServoOpen(ServosList::VENTING_VALVE) ? 1 : 0;
-            tm.release_valve_state =
-                actuators->isServoOpen(ServosList::RELEASE_VALVE) ? 1 : 0;
+            tm.n2o_filling_valve_state =
+                actuators->isServoOpen(ServosList::N2O_FILLING_VALVE);
+            tm.n2o_release_valve_state =
+                actuators->isServoOpen(ServosList::N2O_RELEASE_VALVE);
+            tm.n2o_detach_state = 0;  // TODO
+            tm.n2o_venting_valve_state =
+                actuators->isServoOpen(ServosList::N2O_VENTING_VALVE);
+
+            tm.n2_filling_valve_state =
+                actuators->isServoOpen(ServosList::N2_FILLING_VALVE);
+            tm.n2_release_valve_state =
+                actuators->isServoOpen(ServosList::N2_RELEASE_VALVE);
+            tm.n2_detach_state =
+                actuators->isServoOpen(ServosList::N2_DETACH_SERVO);
+            tm.n2_quenching_valve_state = 0;  // TODO
+            tm.n2_3way_valve_state      = 0;  // TODO
+
             tm.main_valve_state =
-                actuators->isServoOpen(ServosList::MAIN_VALVE) ? 1 : 0;
-            tm.nitrogen_valve_state = actuators->isNitrogenOpen() ? 1 : 0;
+                actuators->isServoOpen(ServosList::MAIN_VALVE);
+            tm.nitrogen_valve_state =
+                actuators->isServoOpen(ServosList::NITROGEN_VALVE);
+            tm.ignition_state = actuators->isNitrogenOpen();
 
             // Internal states
             tm.gmm_state    = getModule<GroundModeManager>()->getState();
@@ -600,7 +621,8 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             tm.main_valve_state =
                 actuators->isCanServoOpen(ServosList::MAIN_VALVE) ? 1 : 0;
             tm.venting_valve_state =
-                actuators->isCanServoOpen(ServosList::VENTING_VALVE) ? 1 : 0;
+                actuators->isCanServoOpen(ServosList::N2O_VENTING_VALVE) ? 1
+                                                                         : 0;
 
             // Can data
             CanHandler::CanStatus canStatus =
@@ -857,53 +879,81 @@ void Radio::handleConrigState(const mavlink_message_t& msg)
             lastManualActuation = currentTime;
         }
 
-        if (oldConrigState.filling_valve_btn == 0 &&
-            state.filling_valve_btn == 1)
+        if (oldConrigState.n2o_filling_btn == 0 && state.n2o_filling_btn == 1)
         {
-            // The filling switch was pressed
+            // The N2O filling switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
-            getModule<Actuators>()->toggleServo(ServosList::FILLING_VALVE);
+            getModule<Actuators>()->toggleServo(ServosList::N2O_FILLING_VALVE);
 
             lastManualActuation = currentTime;
         }
 
-        if (oldConrigState.quick_connector_btn == 0 &&
-            state.quick_connector_btn == 1)
+        if (oldConrigState.n2o_release_btn == 0 && state.n2o_release_btn == 1)
         {
-            // The quick conector switch was pressed
+            // The N2O release switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
-            getModule<Actuators>()->toggleServo(ServosList::DISCONNECT_SERVO);
+            getModule<Actuators>()->toggleServo(ServosList::N2O_RELEASE_VALVE);
 
             lastManualActuation = currentTime;
         }
 
-        if (oldConrigState.release_pressure_btn == 0 &&
-            state.release_pressure_btn == 1)
+        // TODO: n2o_detach_btn
+
+        if (oldConrigState.n2o_venting_btn == 0 && state.n2o_venting_btn == 1)
         {
-            // The release switch was pressed
+            // The N2O venting switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
-            getModule<Actuators>()->toggleServo(ServosList::RELEASE_VALVE);
+            getModule<Actuators>()->toggleServo(ServosList::N2O_VENTING_VALVE);
 
             lastManualActuation = currentTime;
         }
 
-        if (oldConrigState.venting_valve_btn == 0 &&
-            state.venting_valve_btn == 1)
+        if (oldConrigState.n2_filling_btn == 0 && state.n2_filling_btn == 1)
         {
-            // The venting switch was pressed
+            // The N2 filling switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
-            getModule<Actuators>()->toggleServo(ServosList::VENTING_VALVE);
+            getModule<Actuators>()->toggleServo(ServosList::N2_FILLING_VALVE);
 
             lastManualActuation = currentTime;
         }
 
-        if (oldConrigState.start_tars_btn == 0 && state.start_tars_btn == 1)
+        if (oldConrigState.n2_release_btn == 0 && state.n2_release_btn == 1)
+        {
+            // The N2 release switch was pressed
+            EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
+            getModule<Actuators>()->toggleServo(ServosList::N2_RELEASE_VALVE);
+
+            lastManualActuation = currentTime;
+        }
+
+        if (oldConrigState.n2_detach_btn == 0 && state.n2_detach_btn == 1)
+        {
+            // The N2 detach switch was pressed
+            EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
+            getModule<Actuators>()->toggleServo(ServosList::N2_DETACH_SERVO);
+
+            lastManualActuation = currentTime;
+        }
+
+        // TODO: n2_quenching_btn
+        // TODO: n2_3way_btn
+
+        if (oldConrigState.tars_btn == 0 && state.tars_btn == 1)
         {
             // The TARS switch was pressed
             EventBroker::getInstance().post(MOTOR_START_TARS, TOPIC_TARS);
 
             lastManualActuation = currentTime;
         }
+
+        if (oldConrigState.nitrogen_btn == 0 && state.nitrogen_btn == 1)
+        {
+            // The nitrogen switch was pressed
+            EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
+            getModule<Actuators>()->toggleServo(ServosList::NITROGEN_VALVE);
+
+            lastManualActuation = currentTime;
+        }
     }
 
     // Special case for disarming, that can be done bypassing the timeout
diff --git a/src/RIGv2/Radio/Radio.h b/src/RIGv2/Radio/Radio.h
index 26a32da17..582ee6d97 100644
--- a/src/RIGv2/Radio/Radio.h
+++ b/src/RIGv2/Radio/Radio.h
@@ -31,7 +31,7 @@
 #include <RIGv2/Sensors/Sensors.h>
 #include <RIGv2/StateMachines/GroundModeManager/GroundModeManager.h>
 #include <RIGv2/StateMachines/TARS1/TARS1.h>
-#include <common/MavlinkLyra.h>
+#include <common/MavlinkOrion.h>
 #include <interfaces-impl/hwmapping.h>
 #include <radio/MavlinkDriver/MavlinkDriver.h>
 #include <radio/SX1278/SX1278Lora.h>
diff --git a/src/RIGv2/StateMachines/TARS1/TARS1.cpp b/src/RIGv2/StateMachines/TARS1/TARS1.cpp
index 5b0f879d6..50a1f90d7 100644
--- a/src/RIGv2/StateMachines/TARS1/TARS1.cpp
+++ b/src/RIGv2/StateMachines/TARS1/TARS1.cpp
@@ -104,13 +104,13 @@ void TARS1::state_refueling(const Event& event)
             logAction(TarsActionType::WASHING);
 
             // Start washing
-            actuators->openServoWithTime(ServosList::VENTING_VALVE,
+            actuators->openServoWithTime(ServosList::N2O_VENTING_VALVE,
                                          Config::TARS1::WASHING_OPENING_TIME);
 
             // Wait a bit so that the servo don't actuate at the same time
             Thread::sleep(Config::TARS1::WASHING_TIME_DELAY);
 
-            actuators->openServoWithTime(ServosList::FILLING_VALVE,
+            actuators->openServoWithTime(ServosList::N2O_FILLING_VALVE,
                                          Config::TARS1::WASHING_OPENING_TIME);
 
             // After double the time we opened the valve, move to the next phase
@@ -127,7 +127,7 @@ void TARS1::state_refueling(const Event& event)
             logAction(TarsActionType::OPEN_FILLING);
 
             // Open the filling for a long time
-            actuators->openServoWithTime(ServosList::FILLING_VALVE,
+            actuators->openServoWithTime(ServosList::N2O_FILLING_VALVE,
                                          Config::TARS1::FILLING_OPENING_TIME);
 
             nextDelayedEventId = EventBroker::getInstance().postDelayed(
@@ -176,11 +176,11 @@ void TARS1::state_refueling(const Event& event)
             logAction(TarsActionType::OPEN_VENTING);
 
             // Open the venting and check for pressure stabilization
-            actuators->openServo(ServosList::VENTING_VALVE);
+            actuators->openServo(ServosList::N2O_VENTING_VALVE);
 
             // Calculate next check time based on the time the valve stays open
             unsigned int nextCheckTime =
-                actuators->getServoOpeningTime(ServosList::VENTING_VALVE) +
+                actuators->getServoOpeningTime(ServosList::N2O_VENTING_VALVE) +
                 Config::TARS1::PRESSURE_STABILIZE_WAIT_TIME * 5;
 
             nextDelayedEventId = EventBroker::getInstance().postDelayed(
-- 
GitLab


From 22dbef59214228f0647c7cbfb1e19bb53da264da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Wed, 27 Nov 2024 11:46:38 +0100
Subject: [PATCH 04/14] [RIGv2] Implement chamber valve control logic

---
 src/RIGv2/Actuators/Actuators.cpp             | 19 +++----
 src/RIGv2/Actuators/Actuators.h               | 13 ++---
 src/RIGv2/Configs/ActuatorsConfig.h           |  5 --
 src/RIGv2/Configs/GMMConfig.h                 |  6 ++-
 src/RIGv2/Radio/Radio.cpp                     | 22 +++++++-
 src/RIGv2/Registry/Registry.h                 |  2 +
 .../GroundModeManager/GroundModeManager.cpp   | 54 ++++++++++++++-----
 .../GroundModeManager/GroundModeManager.h     |  5 +-
 src/common/Events.h                           |  2 +
 9 files changed, 88 insertions(+), 40 deletions(-)

diff --git a/src/RIGv2/Actuators/Actuators.cpp b/src/RIGv2/Actuators/Actuators.cpp
index cb671723e..d2a92c244 100644
--- a/src/RIGv2/Actuators/Actuators.cpp
+++ b/src/RIGv2/Actuators/Actuators.cpp
@@ -408,12 +408,7 @@ bool Actuators::isCanServoOpen(ServosList servo)
         return false;
 }
 
-void Actuators::openNitrogen()
-{
-    openNitrogenWithTime(Config::Actuators::NITROGEN_OPENING_TIME);
-}
-
-void Actuators::openNitrogenWithTime(uint32_t time)
+void Actuators::openChamberWithTime(uint32_t time)
 {
     Lock<FastMutex> lock(infosMutex);
     long long currentTime = getTime();
@@ -422,13 +417,13 @@ void Actuators::openNitrogenWithTime(uint32_t time)
     nitrogenLastActionTs = currentTime;
 }
 
-void Actuators::closeNitrogen()
+void Actuators::closeChamber()
 {
     Lock<FastMutex> lock(infosMutex);
     nitrogenCloseTs = 0;
 }
 
-bool Actuators::isNitrogenOpen()
+bool Actuators::isChamberOpen()
 {
     Lock<FastMutex> lock(infosMutex);
     return nitrogenCloseTs != 0;
@@ -511,9 +506,9 @@ void Actuators::unsafeSetServoPosition(uint8_t idx, float position)
     sdLogger.log(data);
 }
 
-void Actuators::unsafeOpenNitrogen() { relays::nitrogen::low(); }
+void Actuators::unsafeOpenChamber() { relays::nitrogen::low(); }
 
-void Actuators::unsafeCloseNitrogen() { relays::nitrogen::high(); }
+void Actuators::unsafeCloseChamber() { relays::nitrogen::high(); }
 
 void Actuators::updatePositionsTask()
 {
@@ -571,12 +566,12 @@ void Actuators::updatePositionsTask()
     // Handle nitrogen logic
     if (currentTime < nitrogenCloseTs)
     {
-        unsafeOpenNitrogen();
+        unsafeOpenChamber();
     }
     else
     {
         nitrogenCloseTs = 0;
 
-        unsafeCloseNitrogen();
+        unsafeCloseChamber();
     }
 }
diff --git a/src/RIGv2/Actuators/Actuators.h b/src/RIGv2/Actuators/Actuators.h
index 41cf009ff..08b66c634 100644
--- a/src/RIGv2/Actuators/Actuators.h
+++ b/src/RIGv2/Actuators/Actuators.h
@@ -92,10 +92,11 @@ public:
     bool setOpeningTime(ServosList servo, uint32_t time);
     bool isServoOpen(ServosList servo);
     bool isCanServoOpen(ServosList servo);
-    void openNitrogen();
-    void openNitrogenWithTime(uint32_t time);
-    void closeNitrogen();
-    bool isNitrogenOpen();
+
+    // Chamber valve control
+    void openChamberWithTime(uint32_t time);
+    void closeChamber();
+    bool isChamberOpen();
 
     uint32_t getServoOpeningTime(ServosList servo);
     float getServoMaxAperture(ServosList servo);
@@ -114,8 +115,8 @@ private:
     ServoInfo* getServo(ServosList servo);
 
     void unsafeSetServoPosition(uint8_t idx, float position);
-    void unsafeOpenNitrogen();
-    void unsafeCloseNitrogen();
+    void unsafeOpenChamber();
+    void unsafeCloseChamber();
 
     void updatePositionsTask();
 
diff --git a/src/RIGv2/Configs/ActuatorsConfig.h b/src/RIGv2/Configs/ActuatorsConfig.h
index bfa3ddf43..74b5a06ac 100644
--- a/src/RIGv2/Configs/ActuatorsConfig.h
+++ b/src/RIGv2/Configs/ActuatorsConfig.h
@@ -76,10 +76,5 @@ constexpr bool DISCONNECT_FLIPPED = false;
 
 }  // namespace Servos
 
-namespace Actuators
-{
-static constexpr uint32_t NITROGEN_OPENING_TIME = 5000;  // 5s
-}
-
 }  // namespace Config
 }  // namespace RIGv2
diff --git a/src/RIGv2/Configs/GMMConfig.h b/src/RIGv2/Configs/GMMConfig.h
index cc02af3a0..93e60c045 100644
--- a/src/RIGv2/Configs/GMMConfig.h
+++ b/src/RIGv2/Configs/GMMConfig.h
@@ -33,8 +33,10 @@ namespace GroundModeManager
 
 constexpr uint32_t DEFAULT_IGNITION_WAITING_TIME = 3700;  // [ms]
 
-constexpr uint32_t MOTOR_COOLING_TIME = 1500;
-constexpr uint32_t NITROGEN_TIME      = 20000;  // 20s
+/// Delay between the main valve opening and the chamber valve opening
+constexpr uint32_t DEFAULT_CHAMBER_VALVE_DELAY = 500;
+// Time the chamber valve stays open
+constexpr uint32_t DEFAULT_CHAMBER_VALVE_TIME = 6000;
 
 }  // namespace GroundModeManager
 }  // namespace Config
diff --git a/src/RIGv2/Radio/Radio.cpp b/src/RIGv2/Radio/Radio.cpp
index f657b77f3..fe44a57c2 100644
--- a/src/RIGv2/Radio/Radio.cpp
+++ b/src/RIGv2/Radio/Radio.cpp
@@ -259,6 +259,26 @@ void Radio::handleMessage(const mavlink_message_t& msg)
             break;
         }
 
+        case MAVLINK_MSG_ID_SET_NITROGEN_TIME_TC:
+        {
+            // Chamber valve opening time
+            uint32_t timing = mavlink_msg_set_nitrogen_time_tc_get_timing(&msg);
+            getModule<GroundModeManager>()->setChamberTime(timing);
+
+            enqueueAck(msg);
+            break;
+        }
+
+        case MAVLINK_MSG_ID_SET_COOLING_TIME_TC:
+        {
+            // Chamber valve delay after main valve opening
+            uint32_t timing = mavlink_msg_set_cooling_time_tc_get_timing(&msg);
+            getModule<GroundModeManager>()->setChamberDelay(timing);
+
+            enqueueAck(msg);
+            break;
+        }
+
         default:
         {
             // Unrecognized packet
@@ -569,7 +589,7 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
                 actuators->isServoOpen(ServosList::MAIN_VALVE);
             tm.nitrogen_valve_state =
                 actuators->isServoOpen(ServosList::NITROGEN_VALVE);
-            tm.ignition_state = actuators->isNitrogenOpen();
+            tm.ignition_state = actuators->isChamberOpen();
 
             // Internal states
             tm.gmm_state    = getModule<GroundModeManager>()->getState();
diff --git a/src/RIGv2/Registry/Registry.h b/src/RIGv2/Registry/Registry.h
index 81164f317..1f9b99b61 100644
--- a/src/RIGv2/Registry/Registry.h
+++ b/src/RIGv2/Registry/Registry.h
@@ -43,6 +43,8 @@ enum ConfigurationKeys
     CONFIG_ID_IGNITION_TIME           = 11,
     CONFIG_ID_DEFAULT_OPENING_TIME    = 12,
     CONFIG_ID_DEFAULT_MAX_APERTURE    = 13,
+    CONFIG_ID_CHAMBER_TIME            = 14,
+    CONFIG_ID_CHAMBER_DELAY           = 15,
 };
 
 const char* configurationIdToName(Boardcore::ConfigurationId id);
diff --git a/src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.cpp b/src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.cpp
index 2b372417e..cfff1aaa0 100644
--- a/src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.cpp
+++ b/src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.cpp
@@ -47,6 +47,16 @@ void GroundModeManager::setIgnitionTime(uint32_t time)
     getModule<Registry>()->setUnsafe(CONFIG_ID_IGNITION_TIME, time);
 }
 
+void GroundModeManager::setChamberTime(uint32_t time)
+{
+    getModule<Registry>()->setUnsafe(CONFIG_ID_CHAMBER_TIME, time);
+}
+
+void GroundModeManager::setChamberDelay(uint32_t time)
+{
+    getModule<Registry>()->setUnsafe(CONFIG_ID_CHAMBER_DELAY, time);
+}
+
 State GroundModeManager::state_idle(const Event& event)
 {
     switch (event)
@@ -194,7 +204,11 @@ State GroundModeManager::state_disarmed(const Event& event)
 
         case TMTC_OPEN_NITROGEN:
         {
-            getModule<Actuators>()->openNitrogen();
+            uint32_t chamberTime = getModule<Registry>()->getOrSetDefaultUnsafe(
+                CONFIG_ID_CHAMBER_TIME,
+                Config::GroundModeManager::DEFAULT_CHAMBER_VALVE_TIME);
+
+            getModule<Actuators>()->openChamberWithTime(chamberTime);
             return HANDLED;
         }
 
@@ -227,7 +241,7 @@ State GroundModeManager::state_armed(const Event& event)
             getModule<CanHandler>()->sendEvent(CanConfig::EventId::ARM);
             getModule<Actuators>()->armLightOn();
             getModule<Actuators>()->closeAllServos();
-            getModule<Actuators>()->closeNitrogen();
+            getModule<Actuators>()->closeChamber();
             return HANDLED;
         }
 
@@ -248,7 +262,10 @@ State GroundModeManager::state_armed(const Event& event)
 
         case TMTC_OPEN_NITROGEN:
         {
-            getModule<Actuators>()->openNitrogen();
+            uint32_t chamberTime = getModule<Registry>()->getOrSetDefaultUnsafe(
+                CONFIG_ID_CHAMBER_TIME,
+                Config::GroundModeManager::DEFAULT_CHAMBER_VALVE_TIME);
+            getModule<Actuators>()->openChamberWithTime(chamberTime);
 
             // Nitrogen causes automatic disarm
             return transition(&GroundModeManager::state_disarmed);
@@ -289,7 +306,6 @@ State GroundModeManager::state_firing(const Event& event)
 
             // Disable all events
             EventBroker::getInstance().removeDelayed(openOxidantDelayEventId);
-            EventBroker::getInstance().removeDelayed(coolingDelayEventId);
 
             return HANDLED;
         }
@@ -307,7 +323,11 @@ State GroundModeManager::state_firing(const Event& event)
         case TMTC_OPEN_NITROGEN:
         {
             // Open nitrogen
-            getModule<Actuators>()->openNitrogen();
+            uint32_t chamberTime = getModule<Registry>()->getOrSetDefaultUnsafe(
+                CONFIG_ID_CHAMBER_TIME,
+                Config::GroundModeManager::DEFAULT_CHAMBER_VALVE_TIME);
+
+            getModule<Actuators>()->openChamberWithTime(chamberTime);
 
             return transition(&GroundModeManager::state_disarmed);
         }
@@ -315,9 +335,6 @@ State GroundModeManager::state_firing(const Event& event)
         case MOTOR_COOLING_TIMEOUT:  // Normal firing end
         case TMTC_DISARM:            // Abort signal
         {
-            getModule<Actuators>()->openNitrogenWithTime(
-                Config::GroundModeManager::NITROGEN_TIME);
-
             return transition(&GroundModeManager::state_disarmed);
         }
 
@@ -389,6 +406,14 @@ State GroundModeManager::state_oxidizer(const Event& event)
 
             getModule<Actuators>()->openServo(ServosList::MAIN_VALVE);
 
+            uint32_t chamberDelay =
+                getModule<Registry>()->getOrSetDefaultUnsafe(
+                    CONFIG_ID_CHAMBER_DELAY,
+                    Config::GroundModeManager::DEFAULT_CHAMBER_VALVE_DELAY);
+
+            EventBroker::getInstance().postDelayed(MOTOR_OPEN_CHAMBER,
+                                                   TOPIC_MOTOR, chamberDelay);
+
             return HANDLED;
         }
 
@@ -407,8 +432,15 @@ State GroundModeManager::state_oxidizer(const Event& event)
             return HANDLED;
         }
 
-        case MOTOR_CLOSE_FEED_VALVE:
+        case MOTOR_OPEN_CHAMBER:
         {
+            uint32_t chamberTime = getModule<Registry>()->getOrSetDefaultUnsafe(
+                CONFIG_ID_CHAMBER_TIME,
+                Config::GroundModeManager::DEFAULT_CHAMBER_VALVE_TIME);
+
+            // Open the chamber valve
+            getModule<Actuators>()->openChamberWithTime(chamberTime);
+
             return transition(&GroundModeManager::state_cooling);
         }
 
@@ -427,10 +459,6 @@ State GroundModeManager::state_cooling(const Event& event)
         {
             updateAndLogStatus(GroundModeManagerState::COOLING);
 
-            coolingDelayEventId = EventBroker::getInstance().postDelayed(
-                MOTOR_COOLING_TIMEOUT, TOPIC_MOTOR,
-                Config::GroundModeManager::MOTOR_COOLING_TIME);
-
             return HANDLED;
         }
 
diff --git a/src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.h b/src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.h
index a4939c0cb..3abbb141c 100644
--- a/src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.h
+++ b/src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.h
@@ -51,6 +51,10 @@ public:
 
     void setIgnitionTime(uint32_t time);
 
+    void setChamberTime(uint32_t time);
+
+    void setChamberDelay(uint32_t time);
+
 private:
     Boardcore::State state_idle(const Boardcore::Event& event);
     Boardcore::State state_init(const Boardcore::Event& event);
@@ -70,7 +74,6 @@ private:
     std::atomic<GroundModeManagerState> state{GroundModeManagerState::IDLE};
 
     uint16_t openOxidantDelayEventId = -1;
-    uint16_t coolingDelayEventId     = -1;
 };
 
 }  // namespace RIGv2
diff --git a/src/common/Events.h b/src/common/Events.h
index fc524997e..efff19c8d 100644
--- a/src/common/Events.h
+++ b/src/common/Events.h
@@ -158,6 +158,7 @@ enum Events : uint8_t
     MOTOR_OPEN_OXIDANT,
     MOTOR_COOLING_TIMEOUT,
     MOTOR_SHADOW_MODE_TIMEOUT,
+    MOTOR_OPEN_CHAMBER,
     TARS_WASHING_DONE,
     TARS_CHECK_PRESSURE_STABILIZE,
     TARS_PRESSURE_STABILIZED,
@@ -293,6 +294,7 @@ inline std::string getEventString(uint8_t event)
         {MOTOR_OPEN_OXIDANT, "MOTOR_OPEN_OXIDANT"},
         {MOTOR_COOLING_TIMEOUT, "MOTOR_COOLING_TIMEOUT"},
         {MOTOR_SHADOW_MODE_TIMEOUT, "MOTOR_SHADOW_MODE_TIMEOUT"},
+        {MOTOR_OPEN_CHAMBER, "MOTOR_OPEN_CHAMBER"},
         {TARS_WASHING_DONE, "TARS_WASHING_DONE"},
         {TARS_CHECK_PRESSURE_STABILIZE, "TARS_CHECK_PRESSURE_STABILIZE"},
         {TARS_PRESSURE_STABILIZED, "TARS_PRESSURE_STABILIZED"},
-- 
GitLab


From 9c383fe7831e003efb738485268e4b31a5f7b820 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Wed, 27 Nov 2024 14:47:35 +0100
Subject: [PATCH 05/14] [RIGv2] Update registry for new valves

---
 src/RIGv2/Actuators/Actuators.cpp | 28 ++++++-------
 src/RIGv2/Radio/Radio.cpp         | 17 ++++++--
 src/RIGv2/Registry/Registry.cpp   | 67 +++++++++++++++++++++----------
 src/RIGv2/Registry/Registry.h     | 59 ++++++++++++++++++++-------
 4 files changed, 118 insertions(+), 53 deletions(-)

diff --git a/src/RIGv2/Actuators/Actuators.cpp b/src/RIGv2/Actuators/Actuators.cpp
index d2a92c244..f22a2aabb 100644
--- a/src/RIGv2/Actuators/Actuators.cpp
+++ b/src/RIGv2/Actuators/Actuators.cpp
@@ -168,8 +168,8 @@ Actuators::Actuators()
     info->flipped            = Config::Servos::FILLING_FLIPPED;
     info->openingEvent       = Common::Events::MOTOR_OPEN_FILLING_VALVE;
     info->closingEvent       = Common::Events::MOTOR_CLOSE_FILLING_VALVE;
-    info->openingTimeKey     = CONFIG_ID_FILLING_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_FILLING_MAX_APERTURE;
+    info->openingTimeKey     = CONFIG_ID_N2O_FILLING_OPENING_TIME;
+    info->maxApertureKey     = CONFIG_ID_N2O_FILLING_MAX_APERTURE;
     info->unsafeSetServoPosition(0.0f);
 
     info                     = getServo(ServosList::N2O_RELEASE_VALVE);
@@ -179,8 +179,8 @@ Actuators::Actuators()
     info->flipped            = Config::Servos::RELEASE_FLIPPED;
     info->openingEvent       = Common::Events::MOTOR_OPEN_RELEASE_VALVE;
     info->closingEvent       = Common::Events::MOTOR_CLOSE_RELEASE_VALVE;
-    info->openingTimeKey     = CONFIG_ID_RELEASE_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_RELEASE_MAX_APERTURE;
+    info->openingTimeKey     = CONFIG_ID_N2O_RELEASE_OPENING_TIME;
+    info->maxApertureKey     = CONFIG_ID_N2O_RELEASE_MAX_APERTURE;
     info->unsafeSetServoPosition(0.0f);
 
     info                     = getServo(ServosList::N2O_VENTING_VALVE);
@@ -190,8 +190,8 @@ Actuators::Actuators()
     info->flipped            = Config::Servos::VENTING_FLIPPED;
     info->openingEvent       = Common::Events::MOTOR_OPEN_VENTING_VALVE;
     info->closingEvent       = Common::Events::MOTOR_CLOSE_VENTING_VALVE;
-    info->openingTimeKey     = CONFIG_ID_VENTING_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_VENTING_MAX_APERTURE;
+    info->openingTimeKey     = CONFIG_ID_N2O_VENTING_OPENING_TIME;
+    info->maxApertureKey     = CONFIG_ID_N2O_VENTING_MAX_APERTURE;
     info->unsafeSetServoPosition(0.0f);
 
     info                     = getServo(ServosList::N2_FILLING_VALVE);
@@ -201,8 +201,8 @@ Actuators::Actuators()
     info->flipped            = Config::Servos::FILLING_FLIPPED;
     info->openingEvent       = Common::Events::MOTOR_OPEN_FILLING_VALVE;
     info->closingEvent       = Common::Events::MOTOR_CLOSE_FILLING_VALVE;
-    info->openingTimeKey     = CONFIG_ID_FILLING_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_FILLING_MAX_APERTURE;
+    info->openingTimeKey     = CONFIG_ID_N2_FILLING_OPENING_TIME;
+    info->maxApertureKey     = CONFIG_ID_N2_FILLING_MAX_APERTURE;
     info->unsafeSetServoPosition(0.0f);
 
     info                     = getServo(ServosList::N2_RELEASE_VALVE);
@@ -212,8 +212,8 @@ Actuators::Actuators()
     info->flipped            = Config::Servos::RELEASE_FLIPPED;
     info->openingEvent       = Common::Events::MOTOR_OPEN_RELEASE_VALVE;
     info->closingEvent       = Common::Events::MOTOR_CLOSE_RELEASE_VALVE;
-    info->openingTimeKey     = CONFIG_ID_RELEASE_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_RELEASE_MAX_APERTURE;
+    info->openingTimeKey     = CONFIG_ID_N2_RELEASE_OPENING_TIME;
+    info->maxApertureKey     = CONFIG_ID_N2_RELEASE_MAX_APERTURE;
     info->unsafeSetServoPosition(0.0f);
 
     info                     = getServo(ServosList::N2_DETACH_SERVO);
@@ -222,8 +222,8 @@ Actuators::Actuators()
     info->limit              = Config::Servos::DISCONNECT_LIMIT;
     info->flipped            = Config::Servos::DISCONNECT_FLIPPED;
     info->openingEvent       = Common::Events::MOTOR_DISCONNECT;
-    info->openingTimeKey     = CONFIG_ID_DISCONNECT_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_DISCONNECT_MAX_APERTURE;
+    info->openingTimeKey     = CONFIG_ID_N2_DETACH_OPENING_TIME;
+    info->maxApertureKey     = CONFIG_ID_N2_DETACH_MAX_APERTURE;
     info->unsafeSetServoPosition(0.0f);
 
     info                     = getServo(ServosList::MAIN_VALVE);
@@ -244,8 +244,8 @@ Actuators::Actuators()
     info->flipped            = Config::Servos::MAIN_FLIPPED;
     info->openingEvent       = 0;
     info->closingEvent       = 0;
-    info->openingTimeKey     = CONFIG_ID_MAIN_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_MAIN_MAX_APERTURE;
+    info->openingTimeKey     = CONFIG_ID_NITROGEN_OPENING_TIME;
+    info->maxApertureKey     = CONFIG_ID_NITROGEN_MAX_APERTURE;
     info->unsafeSetServoPosition(0.0f);
 }
 
diff --git a/src/RIGv2/Radio/Radio.cpp b/src/RIGv2/Radio/Radio.cpp
index fe44a57c2..09c2aba51 100644
--- a/src/RIGv2/Radio/Radio.cpp
+++ b/src/RIGv2/Radio/Radio.cpp
@@ -364,6 +364,17 @@ void Radio::enqueueRegistry()
             mavlink_message_t msg;
             const char* name = configurationIdToName(id);
 
+            // A safe copy function for key names
+            auto copyKeyName = [](auto& dest, const char* src)
+            {
+                // Ensure dest is not a pointer
+                static_assert(sizeof(dest) != sizeof(char*));
+
+                constexpr size_t maxKeyLen = sizeof(dest) / sizeof(dest[0]) - 1;
+                std::strncpy(dest, src, maxKeyLen);
+                dest[maxKeyLen] = '\0';  // Ensure null-termination
+            };
+
             switch (value.getType())
             {
                 case TypesEnum::UINT32:
@@ -372,7 +383,7 @@ void Radio::enqueueRegistry()
 
                     tm.timestamp = TimestampTimer::getTimestamp();
                     tm.key_id    = id;
-                    strcpy(tm.key_name, name);
+                    copyKeyName(tm.key_name, name);
                     value.get(tm.value);
 
                     mavlink_msg_registry_int_tm_encode(
@@ -386,7 +397,7 @@ void Radio::enqueueRegistry()
 
                     tm.timestamp = TimestampTimer::getTimestamp();
                     tm.key_id    = id;
-                    strcpy(tm.key_name, name);
+                    copyKeyName(tm.key_name, name);
                     value.get(tm.value);
 
                     mavlink_msg_registry_float_tm_encode(
@@ -400,7 +411,7 @@ void Radio::enqueueRegistry()
 
                     tm.timestamp = TimestampTimer::getTimestamp();
                     tm.key_id    = id;
-                    strcpy(tm.key_name, name);
+                    copyKeyName(tm.key_name, name);
                     Coordinates coord;
                     value.get(coord);
                     tm.latitude  = coord.latitude;
diff --git a/src/RIGv2/Registry/Registry.cpp b/src/RIGv2/Registry/Registry.cpp
index 847764c60..2fa748947 100644
--- a/src/RIGv2/Registry/Registry.cpp
+++ b/src/RIGv2/Registry/Registry.cpp
@@ -33,32 +33,57 @@ const char* RIGv2::configurationIdToName(ConfigurationId id)
 {
     switch (id)
     {
-        case CONFIG_ID_FILLING_OPENING_TIME:
-            return "FillingOpeningTime";
-        case CONFIG_ID_VENTING_OPENING_TIME:
-            return "VentingOpeningTime";
+        case CONFIG_ID_N2O_FILLING_OPENING_TIME:
+            return "N2O_FILLING_OPENING_TIME";
+        case CONFIG_ID_N2O_FILLING_MAX_APERTURE:
+            return "N2O_FILLING_MAX_APERTURE";
+        case CONFIG_ID_N2O_RELEASE_OPENING_TIME:
+            return "N2O_RELEASE_OPENING_TIME";
+        case CONFIG_ID_N2O_RELEASE_MAX_APERTURE:
+            return "N2O_RELEASE_MAX_APERTURE";
+        case CONFIG_ID_N2O_DETACH_OPENING_TIME:
+            return "N2O_DETACH_OPENING_TIME";
+        case CONFIG_ID_N2O_DETACH_MAX_APERTURE:
+            return "N2O_DETACH_MAX_APERTURE";
+        case CONFIG_ID_N2O_VENTING_OPENING_TIME:
+            return "N2O_VENTING_OPENING_TIME";
+        case CONFIG_ID_N2O_VENTING_MAX_APERTURE:
+            return "N2O_VENTING_MAX_APERTURE";
+        case CONFIG_ID_N2_FILLING_OPENING_TIME:
+            return "N2_FILLING_OPENING_TIME";
+        case CONFIG_ID_N2_FILLING_MAX_APERTURE:
+            return "N2_FILLING_MAX_APERTURE";
+        case CONFIG_ID_N2_RELEASE_OPENING_TIME:
+            return "N2_RELEASE_OPENING_TIME";
+        case CONFIG_ID_N2_RELEASE_MAX_APERTURE:
+            return "N2_RELEASE_MAX_APERTURE";
+        case CONFIG_ID_N2_DETACH_OPENING_TIME:
+            return "N2_DETACH_OPENING_TIME";
+        case CONFIG_ID_N2_DETACH_MAX_APERTURE:
+            return "N2_DETACH_MAX_APERTURE";
+        case CONFIG_ID_N2_QUENCHING_OPENING_TIME:
+            return "N2_QUENCHING_OPENING_TIME";
+        case CONFIG_ID_N2_QUENCHING_MAX_APERTURE:
+            return "N2_QUENCHING_MAX_APERTURE";
         case CONFIG_ID_MAIN_OPENING_TIME:
-            return "MainOpeningTime";
-        case CONFIG_ID_RELEASE_OPENING_TIME:
-            return "ReleaseOpeningTime";
-        case CONFIG_ID_DISCONNECT_OPENING_TIME:
-            return "DisconOpeningTime";
-        case CONFIG_ID_FILLING_MAX_APERTURE:
-            return "FillingMaxAperture";
-        case CONFIG_ID_VENTING_MAX_APERTURE:
-            return "VentingMaxAperture";
+            return "MAIN_OPENING_TIME";
         case CONFIG_ID_MAIN_MAX_APERTURE:
-            return "MainMaxAperture";
-        case CONFIG_ID_RELEASE_MAX_APERTURE:
-            return "ReleaseMaxAperture";
-        case CONFIG_ID_DISCONNECT_MAX_APERTURE:
-            return "DisconMaxAperture";
+            return "MAIN_MAX_APERTURE";
+        case CONFIG_ID_NITROGEN_OPENING_TIME:
+            return "NITROGEN_OPENING_TIME";
+        case CONFIG_ID_NITROGEN_MAX_APERTURE:
+            return "NITROGEN_MAX_APERTURE";
         case CONFIG_ID_IGNITION_TIME:
-            return "IgnitionTime";
+            return "IGNITION_TIME";
         case CONFIG_ID_DEFAULT_OPENING_TIME:
-            return "DefOpeningTime";
+            return "DEFAULT_OPENING_TIME";
         case CONFIG_ID_DEFAULT_MAX_APERTURE:
-            return "DefMaxAperture";
+            return "DEFAULT_MAX_APERTURE";
+        case CONFIG_ID_CHAMBER_TIME:
+            return "CHAMBER_TIME";
+        case CONFIG_ID_CHAMBER_DELAY:
+            return "CHAMBER_DELAY";
+
         default:
             return "<invalid>";
     }
diff --git a/src/RIGv2/Registry/Registry.h b/src/RIGv2/Registry/Registry.h
index 1f9b99b61..b1f8e4cd2 100644
--- a/src/RIGv2/Registry/Registry.h
+++ b/src/RIGv2/Registry/Registry.h
@@ -30,21 +30,50 @@ namespace RIGv2
 
 enum ConfigurationKeys
 {
-    CONFIG_ID_FILLING_OPENING_TIME    = 1,
-    CONFIG_ID_VENTING_OPENING_TIME    = 2,
-    CONFIG_ID_MAIN_OPENING_TIME       = 3,
-    CONFIG_ID_RELEASE_OPENING_TIME    = 4,
-    CONFIG_ID_DISCONNECT_OPENING_TIME = 5,
-    CONFIG_ID_FILLING_MAX_APERTURE    = 6,
-    CONFIG_ID_VENTING_MAX_APERTURE    = 7,
-    CONFIG_ID_MAIN_MAX_APERTURE       = 8,
-    CONFIG_ID_RELEASE_MAX_APERTURE    = 9,
-    CONFIG_ID_DISCONNECT_MAX_APERTURE = 10,
-    CONFIG_ID_IGNITION_TIME           = 11,
-    CONFIG_ID_DEFAULT_OPENING_TIME    = 12,
-    CONFIG_ID_DEFAULT_MAX_APERTURE    = 13,
-    CONFIG_ID_CHAMBER_TIME            = 14,
-    CONFIG_ID_CHAMBER_DELAY           = 15,
+    // N2O
+    CONFIG_ID_N2O_FILLING_OPENING_TIME,
+    CONFIG_ID_N2O_FILLING_MAX_APERTURE,
+
+    CONFIG_ID_N2O_RELEASE_OPENING_TIME,
+    CONFIG_ID_N2O_RELEASE_MAX_APERTURE,
+
+    CONFIG_ID_N2O_DETACH_OPENING_TIME,
+    CONFIG_ID_N2O_DETACH_MAX_APERTURE,
+
+    CONFIG_ID_N2O_VENTING_OPENING_TIME,
+    CONFIG_ID_N2O_VENTING_MAX_APERTURE,
+
+    // N2
+    CONFIG_ID_N2_FILLING_OPENING_TIME,
+    CONFIG_ID_N2_FILLING_MAX_APERTURE,
+
+    CONFIG_ID_N2_RELEASE_OPENING_TIME,
+    CONFIG_ID_N2_RELEASE_MAX_APERTURE,
+
+    CONFIG_ID_N2_DETACH_OPENING_TIME,
+    CONFIG_ID_N2_DETACH_MAX_APERTURE,
+
+    CONFIG_ID_N2_QUENCHING_OPENING_TIME,
+    CONFIG_ID_N2_QUENCHING_MAX_APERTURE,
+
+    // Main & Nitrogen
+    CONFIG_ID_MAIN_OPENING_TIME,
+    CONFIG_ID_MAIN_MAX_APERTURE,
+
+    CONFIG_ID_NITROGEN_OPENING_TIME,
+    CONFIG_ID_NITROGEN_MAX_APERTURE,
+
+    // Ignition parameters
+    CONFIG_ID_IGNITION_TIME,
+
+    // Default valve parameters
+    CONFIG_ID_DEFAULT_OPENING_TIME,
+    CONFIG_ID_DEFAULT_MAX_APERTURE,
+
+    // Chamber valve parameters
+    CONFIG_ID_CHAMBER_TIME,   // Time the chamber valve stays open
+    CONFIG_ID_CHAMBER_DELAY,  // Delay of opening the chamber valve after
+                              // opening the main valve
 };
 
 const char* configurationIdToName(Boardcore::ConfigurationId id);
-- 
GitLab


From 8e35e73c967b123020d899b44eb3008f5eaaa234 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Wed, 27 Nov 2024 18:19:43 +0100
Subject: [PATCH 06/14] [RIGv2] Close chamber valve when exiting from firing
 state

---
 src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.cpp b/src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.cpp
index cfff1aaa0..31bdd3790 100644
--- a/src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.cpp
+++ b/src/RIGv2/StateMachines/GroundModeManager/GroundModeManager.cpp
@@ -303,6 +303,7 @@ State GroundModeManager::state_firing(const Event& event)
             // Stop ignition and close all servos
             getModule<Actuators>()->igniterOff();
             getModule<Actuators>()->closeAllServos();
+            getModule<Actuators>()->closeChamber();
 
             // Disable all events
             EventBroker::getInstance().removeDelayed(openOxidantDelayEventId);
-- 
GitLab


From 089066942ee1a2967c1ca41d01d31d527ed9256a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Wed, 27 Nov 2024 18:21:43 +0100
Subject: [PATCH 07/14] [RIGv2] Fix servo port mapping

SER_1: N2O_FILLING_VALVE
SER_2: N2O_RELEASE_VALVE
SER_3: N2O_VENTING_VALVE
SER_4: N2_FILLING_VALVE
SER_5: N2_RELEASE_VALVE
SER_6: N2_DETACH_SERVO
SER_7: MAIN_VALVE
SER_8: NITROGEN_VALVE
---
 src/RIGv2/Actuators/Actuators.cpp | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/RIGv2/Actuators/Actuators.cpp b/src/RIGv2/Actuators/Actuators.cpp
index f22a2aabb..c05c94d56 100644
--- a/src/RIGv2/Actuators/Actuators.cpp
+++ b/src/RIGv2/Actuators/Actuators.cpp
@@ -138,11 +138,11 @@ Actuators::Actuators()
     //     Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
     //     Config::Servos::FREQUENCY);
     infos[5].servo = std::make_unique<Servo>(
-        MIOSIX_SERVOS_6_TIM, TimerUtils::Channel::MIOSIX_SERVOS_6_CHANNEL,
+        MIOSIX_SERVOS_7_TIM, TimerUtils::Channel::MIOSIX_SERVOS_7_CHANNEL,
         Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
         Config::Servos::FREQUENCY);
     infos[6].servo = std::make_unique<Servo>(
-        MIOSIX_SERVOS_7_TIM, TimerUtils::Channel::MIOSIX_SERVOS_7_CHANNEL,
+        MIOSIX_SERVOS_9_TIM, TimerUtils::Channel::MIOSIX_SERVOS_9_CHANNEL,
         Config::Servos::SERVO2_MIN_PULSE, Config::Servos::SERVO2_MAX_PULSE,
         Config::Servos::FREQUENCY);
     // This servo is currently unusable, due to it sharing the same timer as
@@ -152,11 +152,11 @@ Actuators::Actuators()
     //     Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
     //     Config::Servos::FREQUENCY);
     infos[8].servo = std::make_unique<Servo>(
-        MIOSIX_SERVOS_9_TIM, TimerUtils::Channel::MIOSIX_SERVOS_9_CHANNEL,
+        MIOSIX_SERVOS_6_TIM, TimerUtils::Channel::MIOSIX_SERVOS_6_CHANNEL,
         Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
         Config::Servos::FREQUENCY);
     infos[9].servo = std::make_unique<Servo>(
-        MIOSIX_SERVOS_10_TIM, TimerUtils::Channel::MIOSIX_SERVOS_10_CHANNEL,
+        MIOSIX_SERVOS_8_TIM, TimerUtils::Channel::MIOSIX_SERVOS_8_CHANNEL,
         Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
         Config::Servos::FREQUENCY);
 
-- 
GitLab


From 9d887dd347dce1688a3fce46834f1b6e7c02b12b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Wed, 27 Nov 2024 18:57:03 +0100
Subject: [PATCH 08/14] [RIGv2] Map pressure transducers to the new Mavlink
 message fields

Methods in the Sensors class have NOT been updated yet, which means their name is mismatching with the pressure they sample, but they sample correct data.
The mavlink message contains the correct name of the pressure value. This will be fixed in the future.
---
 src/RIGv2/Radio/Radio.cpp | 9 ++++++---
 1 file changed, 6 insertions(+), 3 deletions(-)

diff --git a/src/RIGv2/Radio/Radio.cpp b/src/RIGv2/Radio/Radio.cpp
index 09c2aba51..3b5d301f1 100644
--- a/src/RIGv2/Radio/Radio.cpp
+++ b/src/RIGv2/Radio/Radio.cpp
@@ -549,13 +549,16 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             tm.rocket_mass     = sensors->getTankWeightLastSample().load;
             tm.n2o_vessel_mass = sensors->getVesselWeightLastSample().load;
 
+            // TODO: methods below have mismatching names
             tm.n2o_filling_pressure =
+                sensors->getVesselPressLastSample().pressure;
+            tm.n2_filling_pressure =
                 sensors->getFillingPressLastSample().pressure;
             tm.n2o_vessel_pressure =
-                sensors->getVesselPressLastSample().pressure;
+                sensors->getBottomTankPressLastSample().pressure;
+            tm.n2_vessel_1_pressure =
+                sensors->getTopTankPressLastSample().pressure;
 
-            tm.n2_filling_pressure  = -1.f;  // TODO
-            tm.n2_vessel_1_pressure = -1.f;  // TODO
             tm.n2_vessel_2_pressure = -1.f;  // TODO
 
             tm.battery_voltage = sensors->getBatteryVoltageLastSample().voltage;
-- 
GitLab


From 75b310a505ee451f7210e799db9e52ed33103785 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Wed, 27 Nov 2024 19:35:32 +0100
Subject: [PATCH 09/14] [RIGv2] Use loadcell calibration for the new flipping
 system

---
 src/RIGv2/Configs/SensorsConfig.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/RIGv2/Configs/SensorsConfig.h b/src/RIGv2/Configs/SensorsConfig.h
index 44b873702..b0a8ce893 100644
--- a/src/RIGv2/Configs/SensorsConfig.h
+++ b/src/RIGv2/Configs/SensorsConfig.h
@@ -130,7 +130,6 @@ constexpr float VESSEL_P1_VOLTAGE = 0.0010;
 constexpr float VESSEL_P1_MASS    = 6.916;
 */
 
-/*
 // LC Vessel sensor calibration data (post 07/09/2024)
 // - 0kg      V: 0.000630177
 // - 4.985kg  V: 0.000470017 (−31125.124875125 kg/v)
@@ -139,8 +138,8 @@ constexpr float VESSEL_P0_VOLTAGE = 0.000470017;
 constexpr float VESSEL_P0_MASS    = 4.985;
 constexpr float VESSEL_P1_VOLTAGE = 0.00030895;
 constexpr float VESSEL_P1_MASS    = 10.177;
-*/
 
+/*
 // LC Vessel sensor calibration data (post 08/11/2024, old flipping)
 // - 0kg      V: -0.009553
 // - 8.720kg  V: -0.010958 (−31125.124875125 kg/v)
@@ -148,6 +147,7 @@ constexpr float VESSEL_P0_VOLTAGE = -0.009553;
 constexpr float VESSEL_P0_MASS    = 0.0;
 constexpr float VESSEL_P1_VOLTAGE = -0.010958;
 constexpr float VESSEL_P1_MASS    = 8.720;
+*/
 }  // namespace LoadCell
 
 namespace InternalADC
-- 
GitLab


From 5937a7dfd8ff1f026e9de29b2c3f9121aede084d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Sat, 14 Dec 2024 11:55:26 +0100
Subject: [PATCH 10/14] [RIGv2] Update pressure transducer scale config

PT_1: 100 bar
PT_2: 250 bar
PT_3: 100 bar
PT_4: 250 bar
---
 src/RIGv2/Configs/SensorsConfig.h | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/RIGv2/Configs/SensorsConfig.h b/src/RIGv2/Configs/SensorsConfig.h
index b0a8ce893..21dfeeb7d 100644
--- a/src/RIGv2/Configs/SensorsConfig.h
+++ b/src/RIGv2/Configs/SensorsConfig.h
@@ -99,10 +99,10 @@ constexpr float VESSEL_SHUNT_RESISTANCE      = ADS131M08::CH1_SHUNT_RESISTANCE;
 constexpr float MIN_CURRENT = 4;
 constexpr float MAX_CURRENT = 20;
 
-constexpr float FILLING_MAX_PRESSURE     = 100;  // bar
-constexpr float TANK_TOP_MAX_PRESSURE    = 100;  // bar
+constexpr float FILLING_MAX_PRESSURE     = 250;  // bar
+constexpr float TANK_TOP_MAX_PRESSURE    = 250;  // bar
 constexpr float TANK_BOTTOM_MAX_PRESSURE = 100;  // bar
-constexpr float VESSEL_MAX_PRESSURE      = 400;  // bar
+constexpr float VESSEL_MAX_PRESSURE      = 100;  // bar
 }  // namespace Trafag
 
 namespace LoadCell
-- 
GitLab


From efb92445a4ef30f66a167f113266fd5576f9ccd1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Tue, 11 Feb 2025 00:47:55 +0100
Subject: [PATCH 11/14] [RIGv2] Update Actuators to the 11 Orion servo valves

Boardcore has also been updated to include the updated BSP enabling up to 12 servos.
---
 skyward-boardcore                   |   2 +-
 src/RIGv2/Actuators/Actuators.cpp   | 304 ++++++++++++----------------
 src/RIGv2/Actuators/Actuators.h     |  73 ++++---
 src/RIGv2/Configs/ActuatorsConfig.h |  82 +++++---
 src/RIGv2/Registry/Registry.cpp     |  72 +++----
 src/RIGv2/Registry/Registry.h       |  36 ++--
 src/common/Events.h                 |  51 +++--
 7 files changed, 309 insertions(+), 311 deletions(-)

diff --git a/skyward-boardcore b/skyward-boardcore
index ef4e55b65..ead06db6a 160000
--- a/skyward-boardcore
+++ b/skyward-boardcore
@@ -1 +1 @@
-Subproject commit ef4e55b6575914cc021c4eb36173db9339d3a7c8
+Subproject commit ead06db6a21548d24e3004a0027ae19a501bbaf1
diff --git a/src/RIGv2/Actuators/Actuators.cpp b/src/RIGv2/Actuators/Actuators.cpp
index c05c94d56..0b6de233d 100644
--- a/src/RIGv2/Actuators/Actuators.cpp
+++ b/src/RIGv2/Actuators/Actuators.cpp
@@ -1,5 +1,5 @@
-/* Copyright (c) 2024 Skyward Experimental Rocketry
- * Authors: Davide Mor
+/* Copyright (c) 2025 Skyward Experimental Rocketry
+ * Authors: Davide Mor, Niccolò Betto
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -27,6 +27,7 @@
 #include <common/Events.h>
 #include <drivers/timer/TimestampTimer.h>
 #include <events/EventBroker.h>
+#include <interfaces-impl/hwmapping.h>
 
 using namespace Boardcore;
 using namespace miosix;
@@ -40,8 +41,8 @@ void Actuators::ServoInfo::openServoWithTime(uint32_t time)
     closeTs      = currentTime + (time * Constants::NS_IN_MS);
     lastActionTs = currentTime;
 
-    if (openingEvent != 0)
-        EventBroker::getInstance().post(openingEvent, TOPIC_MOTOR);
+    if (config.openingEvent != 0)
+        EventBroker::getInstance().post(config.openingEvent, TOPIC_MOTOR);
 }
 
 void Actuators::ServoInfo::closeServo()
@@ -49,8 +50,8 @@ void Actuators::ServoInfo::closeServo()
     closeTs      = 0;
     lastActionTs = getTime();
 
-    if (closingEvent != 0)
-        EventBroker::getInstance().post(closingEvent, TOPIC_MOTOR);
+    if (config.closingEvent != 0)
+        EventBroker::getInstance().post(config.closingEvent, TOPIC_MOTOR);
 }
 
 void Actuators::ServoInfo::unsafeSetServoPosition(float position)
@@ -59,8 +60,8 @@ void Actuators::ServoInfo::unsafeSetServoPosition(float position)
     if (!servo)
         return;
 
-    position *= limit;
-    if (flipped)
+    position *= config.limit;
+    if (config.flipped)
         position = 1.0f - position;
 
     servo->setPosition(position);
@@ -73,30 +74,30 @@ float Actuators::ServoInfo::getServoPosition()
         return 0.0f;
 
     float position = servo->getPosition();
-    if (flipped)
+    if (config.flipped)
         position = 1.0f - position;
 
-    position /= limit;
+    position /= config.limit;
     return position;
 }
 
 float Actuators::ServoInfo::getMaxAperture()
 {
-    return getModule<Registry>()->getOrSetDefaultUnsafe(maxApertureKey,
-                                                        defaultMaxAperture);
+    return getModule<Registry>()->getOrSetDefaultUnsafe(
+        config.maxApertureRegKey, config.defaultMaxAperture);
 }
 
 uint32_t Actuators::ServoInfo::getOpeningTime()
 {
-    return getModule<Registry>()->getOrSetDefaultUnsafe(openingTimeKey,
-                                                        defaultOpeningTime);
+    return getModule<Registry>()->getOrSetDefaultUnsafe(
+        config.openingTimeRegKey, config.defaultOpeningTime);
 }
 
 bool Actuators::ServoInfo::setMaxAperture(float aperture)
 {
     if (aperture >= 0.0 && aperture <= 1.0)
     {
-        getModule<Registry>()->setUnsafe(maxApertureKey, aperture);
+        getModule<Registry>()->setUnsafe(config.maxApertureRegKey, aperture);
         return true;
     }
     else
@@ -108,145 +109,96 @@ bool Actuators::ServoInfo::setMaxAperture(float aperture)
 
 bool Actuators::ServoInfo::setOpeningTime(uint32_t time)
 {
-    getModule<Registry>()->setUnsafe(openingTimeKey, time);
+    getModule<Registry>()->setUnsafe(config.openingTimeRegKey, time);
     return true;
 }
 
+/**
+ * @brief Shorthand to create a ServoInfo struct from the servo name
+ */
+#define MAKE_SERVO(name)                                          \
+    ServoInfo                                                     \
+    {                                                             \
+        std::make_unique<Servo>(                                  \
+            MIOSIX_SERVOS_##name##_TIM,                           \
+            TimerUtils::Channel::MIOSIX_SERVOS_##name##_CHANNEL,  \
+            Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE, \
+            Config::Servos::FREQUENCY),                           \
+            ServoInfo::ServoConfig                                \
+        {                                                         \
+            .limit   = Config::Servos::name##_LIMIT,              \
+            .flipped = Config::Servos::name##_FLIPPED,            \
+            .defaultOpeningTime =                                 \
+                Config::Servos::DEFAULT_##name##_OPENING_TIME,    \
+            .defaultMaxAperture =                                 \
+                Config::Servos::DEFAULT_##name##_MAX_APERTURE,    \
+            .openingEvent      = MOTOR_##name##_OPEN,             \
+            .closingEvent      = MOTOR_##name##_CLOSE,            \
+            .openingTimeRegKey = CONFIG_ID_##name##_OPENING_TIME, \
+            .maxApertureRegKey = CONFIG_ID_##name##_MAX_APERTURE  \
+        }                                                         \
+    }
+
+/**
+ * @brief Shorthand to create a detach ServoInfo struct from the servo name
+ */
+#define MAKE_DETACH_SERVO(name)                                           \
+    ServoInfo                                                             \
+    {                                                                     \
+        std::make_unique<Servo>(                                          \
+            MIOSIX_SERVOS_##name##_TIM,                                   \
+            TimerUtils::Channel::MIOSIX_SERVOS_##name##_CHANNEL,          \
+            Config::Servos::DETACH_MIN_PULSE,                             \
+            Config::Servos::DETACH_MAX_PULSE, Config::Servos::FREQUENCY), \
+            ServoInfo::ServoConfig                                        \
+        {                                                                 \
+            .limit   = Config::Servos::name##_LIMIT,                      \
+            .flipped = Config::Servos::name##_FLIPPED,                    \
+            .defaultOpeningTime =                                         \
+                Config::Servos::DEFAULT_##name##_OPENING_TIME,            \
+            .defaultMaxAperture =                                         \
+                Config::Servos::DEFAULT_##name##_MAX_APERTURE,            \
+            .openingEvent      = MOTOR_##name##_OPEN,                     \
+            .closingEvent      = MOTOR_##name##_CLOSE,                    \
+            .openingTimeRegKey = CONFIG_ID_##name##_OPENING_TIME,         \
+            .maxApertureRegKey = CONFIG_ID_##name##_MAX_APERTURE          \
+        }                                                                 \
+    }
+
+/**
+ * @brief Shorthand to create a non-atomic ServoInfo struct from the servo name
+ */
+#define MAKE_SIMPLE_SERVO(name)                                   \
+    ServoInfo                                                     \
+    {                                                             \
+        std::make_unique<Servo>(                                  \
+            MIOSIX_SERVOS_##name##_TIM,                           \
+            TimerUtils::Channel::MIOSIX_SERVOS_##name##_CHANNEL,  \
+            Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE, \
+            Config::Servos::FREQUENCY),                           \
+            ServoInfo::ServoConfig                                \
+        {                                                         \
+            .limit        = Config::Servos::name##_LIMIT,         \
+            .flipped      = Config::Servos::name##_FLIPPED,       \
+            .openingEvent = MOTOR_##name##_OPEN,                  \
+            .closingEvent = MOTOR_##name##_CLOSE,                 \
+        }                                                         \
+    }
+
 Actuators::Actuators()
+    : infos{
+          MAKE_SERVO(OX_FIL),        MAKE_SERVO(OX_REL),
+          MAKE_DETACH_SERVO(OX_DET),
+          MAKE_SERVO(N2_FIL),        MAKE_SERVO(N2_REL),
+          MAKE_DETACH_SERVO(N2_DET), MAKE_SERVO(NITR),
+          MAKE_SERVO(OX_VEN),        MAKE_SERVO(N2_QUE),
+          MAKE_SERVO(MAIN),
+      }, n2_3wayValveInfo(MAKE_SIMPLE_SERVO(N2_3W))
 {
-    // Initialize servos
-    infos[0].servo = std::make_unique<Servo>(
-        MIOSIX_SERVOS_1_TIM, TimerUtils::Channel::MIOSIX_SERVOS_1_CHANNEL,
-        Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
-        Config::Servos::FREQUENCY);
-    infos[1].servo = std::make_unique<Servo>(
-        MIOSIX_SERVOS_2_TIM, TimerUtils::Channel::MIOSIX_SERVOS_2_CHANNEL,
-        Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
-        Config::Servos::FREQUENCY);
-    infos[2].servo = std::make_unique<Servo>(
-        MIOSIX_SERVOS_3_TIM, TimerUtils::Channel::MIOSIX_SERVOS_3_CHANNEL,
-        Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
-        Config::Servos::FREQUENCY);
-    infos[3].servo = std::make_unique<Servo>(
-        MIOSIX_SERVOS_4_TIM, TimerUtils::Channel::MIOSIX_SERVOS_4_CHANNEL,
-        Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
-        Config::Servos::FREQUENCY);
-    // This servo is currently unusable, due to it sharing the same timer as
-    // miosix, TIM5
-    // infos[4].servo = std::make_unique<Servo>(
-    //     MIOSIX_SERVOS_5_TIM, TimerUtils::Channel::MIOSIX_SERVOS_5_CHANNEL,
-    //     Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
-    //     Config::Servos::FREQUENCY);
-    infos[5].servo = std::make_unique<Servo>(
-        MIOSIX_SERVOS_7_TIM, TimerUtils::Channel::MIOSIX_SERVOS_7_CHANNEL,
-        Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
-        Config::Servos::FREQUENCY);
-    infos[6].servo = std::make_unique<Servo>(
-        MIOSIX_SERVOS_9_TIM, TimerUtils::Channel::MIOSIX_SERVOS_9_CHANNEL,
-        Config::Servos::SERVO2_MIN_PULSE, Config::Servos::SERVO2_MAX_PULSE,
-        Config::Servos::FREQUENCY);
-    // This servo is currently unusable, due to it sharing the same timer as
-    // servo 1
-    // infos[7].servo = std::make_unique<Servo>(
-    //     MIOSIX_SERVOS_8_TIM, TimerUtils::Channel::MIOSIX_SERVOS_8_CHANNEL,
-    //     Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
-    //     Config::Servos::FREQUENCY);
-    infos[8].servo = std::make_unique<Servo>(
-        MIOSIX_SERVOS_6_TIM, TimerUtils::Channel::MIOSIX_SERVOS_6_CHANNEL,
-        Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
-        Config::Servos::FREQUENCY);
-    infos[9].servo = std::make_unique<Servo>(
-        MIOSIX_SERVOS_8_TIM, TimerUtils::Channel::MIOSIX_SERVOS_8_CHANNEL,
-        Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE,
-        Config::Servos::FREQUENCY);
-
-    ServoInfo* info;
-    info                     = getServo(ServosList::N2O_FILLING_VALVE);
-    info->defaultMaxAperture = Config::Servos::DEFAULT_FILLING_MAX_APERTURE;
-    info->defaultOpeningTime = Config::Servos::DEFAULT_FILLING_OPENING_TIME;
-    info->limit              = Config::Servos::FILLING_LIMIT;
-    info->flipped            = Config::Servos::FILLING_FLIPPED;
-    info->openingEvent       = Common::Events::MOTOR_OPEN_FILLING_VALVE;
-    info->closingEvent       = Common::Events::MOTOR_CLOSE_FILLING_VALVE;
-    info->openingTimeKey     = CONFIG_ID_N2O_FILLING_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_N2O_FILLING_MAX_APERTURE;
-    info->unsafeSetServoPosition(0.0f);
-
-    info                     = getServo(ServosList::N2O_RELEASE_VALVE);
-    info->defaultMaxAperture = Config::Servos::DEFAULT_RELEASE_MAX_APERTURE;
-    info->defaultOpeningTime = Config::Servos::DEFAULT_RELEASE_OPENING_TIME;
-    info->limit              = Config::Servos::RELEASE_LIMIT;
-    info->flipped            = Config::Servos::RELEASE_FLIPPED;
-    info->openingEvent       = Common::Events::MOTOR_OPEN_RELEASE_VALVE;
-    info->closingEvent       = Common::Events::MOTOR_CLOSE_RELEASE_VALVE;
-    info->openingTimeKey     = CONFIG_ID_N2O_RELEASE_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_N2O_RELEASE_MAX_APERTURE;
-    info->unsafeSetServoPosition(0.0f);
-
-    info                     = getServo(ServosList::N2O_VENTING_VALVE);
-    info->defaultMaxAperture = Config::Servos::DEFAULT_VENTING_MAX_APERTURE;
-    info->defaultOpeningTime = Config::Servos::DEFAULT_VENTING_OPENING_TIME;
-    info->limit              = Config::Servos::VENTING_LIMIT;
-    info->flipped            = Config::Servos::VENTING_FLIPPED;
-    info->openingEvent       = Common::Events::MOTOR_OPEN_VENTING_VALVE;
-    info->closingEvent       = Common::Events::MOTOR_CLOSE_VENTING_VALVE;
-    info->openingTimeKey     = CONFIG_ID_N2O_VENTING_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_N2O_VENTING_MAX_APERTURE;
-    info->unsafeSetServoPosition(0.0f);
-
-    info                     = getServo(ServosList::N2_FILLING_VALVE);
-    info->defaultMaxAperture = Config::Servos::DEFAULT_FILLING_MAX_APERTURE;
-    info->defaultOpeningTime = Config::Servos::DEFAULT_FILLING_OPENING_TIME;
-    info->limit              = Config::Servos::FILLING_LIMIT;
-    info->flipped            = Config::Servos::FILLING_FLIPPED;
-    info->openingEvent       = Common::Events::MOTOR_OPEN_FILLING_VALVE;
-    info->closingEvent       = Common::Events::MOTOR_CLOSE_FILLING_VALVE;
-    info->openingTimeKey     = CONFIG_ID_N2_FILLING_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_N2_FILLING_MAX_APERTURE;
-    info->unsafeSetServoPosition(0.0f);
-
-    info                     = getServo(ServosList::N2_RELEASE_VALVE);
-    info->defaultMaxAperture = Config::Servos::DEFAULT_RELEASE_MAX_APERTURE;
-    info->defaultOpeningTime = Config::Servos::DEFAULT_RELEASE_OPENING_TIME;
-    info->limit              = Config::Servos::RELEASE_LIMIT;
-    info->flipped            = Config::Servos::RELEASE_FLIPPED;
-    info->openingEvent       = Common::Events::MOTOR_OPEN_RELEASE_VALVE;
-    info->closingEvent       = Common::Events::MOTOR_CLOSE_RELEASE_VALVE;
-    info->openingTimeKey     = CONFIG_ID_N2_RELEASE_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_N2_RELEASE_MAX_APERTURE;
-    info->unsafeSetServoPosition(0.0f);
-
-    info                     = getServo(ServosList::N2_DETACH_SERVO);
-    info->defaultMaxAperture = Config::Servos::DEFAULT_DISCONNECT_MAX_APERTURE;
-    info->defaultOpeningTime = Config::Servos::DEFAULT_DISCONNECT_OPENING_TIME;
-    info->limit              = Config::Servos::DISCONNECT_LIMIT;
-    info->flipped            = Config::Servos::DISCONNECT_FLIPPED;
-    info->openingEvent       = Common::Events::MOTOR_DISCONNECT;
-    info->openingTimeKey     = CONFIG_ID_N2_DETACH_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_N2_DETACH_MAX_APERTURE;
-    info->unsafeSetServoPosition(0.0f);
-
-    info                     = getServo(ServosList::MAIN_VALVE);
-    info->defaultMaxAperture = Config::Servos::DEFAULT_MAIN_MAX_APERTURE;
-    info->defaultOpeningTime = Config::Servos::DEFAULT_MAIN_OPENING_TIME;
-    info->limit              = Config::Servos::MAIN_LIMIT;
-    info->flipped            = Config::Servos::MAIN_FLIPPED;
-    info->openingEvent       = Common::Events::MOTOR_OPEN_FEED_VALVE;
-    info->closingEvent       = Common::Events::MOTOR_CLOSE_FEED_VALVE;
-    info->openingTimeKey     = CONFIG_ID_MAIN_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_MAIN_MAX_APERTURE;
-    info->unsafeSetServoPosition(0.0f);
-
-    info                     = getServo(ServosList::NITROGEN_VALVE);
-    info->defaultMaxAperture = Config::Servos::DEFAULT_MAIN_MAX_APERTURE;
-    info->defaultOpeningTime = Config::Servos::DEFAULT_MAIN_OPENING_TIME;
-    info->limit              = Config::Servos::MAIN_LIMIT;
-    info->flipped            = Config::Servos::MAIN_FLIPPED;
-    info->openingEvent       = 0;
-    info->closingEvent       = 0;
-    info->openingTimeKey     = CONFIG_ID_NITROGEN_OPENING_TIME;
-    info->maxApertureKey     = CONFIG_ID_NITROGEN_MAX_APERTURE;
-    info->unsafeSetServoPosition(0.0f);
+    for (auto& servo : infos)
+        servo.unsafeSetServoPosition(0.0f);
+
+    n2_3wayValveInfo.unsafeSetServoPosition(0.0f);
 }
 
 bool Actuators::isStarted() { return started; }
@@ -256,16 +208,9 @@ bool Actuators::start()
     TaskScheduler& scheduler =
         getModule<BoardScheduler>()->getActuatorsScheduler();
 
-    infos[0].servo->enable();
-    infos[1].servo->enable();
-    infos[2].servo->enable();
-    infos[3].servo->enable();
-    // infos[4].servo->enable();
-    infos[5].servo->enable();
-    infos[6].servo->enable();
-    // infos[7].servo->enable();
-    infos[8].servo->enable();
-    infos[9].servo->enable();
+    // Enable all servos
+    for (ServoInfo& info : infos)
+        info.servo->enable();
 
     uint8_t result =
         scheduler.addTask([this]() { updatePositionsTask(); },
@@ -408,25 +353,31 @@ bool Actuators::isCanServoOpen(ServosList servo)
         return false;
 }
 
+void Actuators::set3wayValveState(bool state)
+{
+    auto position = state ? 1.0f : 0.0f;
+    n2_3wayValveInfo.unsafeSetServoPosition(position);
+}
+
 void Actuators::openChamberWithTime(uint32_t time)
 {
     Lock<FastMutex> lock(infosMutex);
     long long currentTime = getTime();
 
-    nitrogenCloseTs      = currentTime + (time * Constants::NS_IN_MS);
-    nitrogenLastActionTs = currentTime;
+    chamberCloseTs      = currentTime + (time * Constants::NS_IN_MS);
+    chamberLastActionTs = currentTime;
 }
 
 void Actuators::closeChamber()
 {
     Lock<FastMutex> lock(infosMutex);
-    nitrogenCloseTs = 0;
+    chamberCloseTs = 0;
 }
 
 bool Actuators::isChamberOpen()
 {
     Lock<FastMutex> lock(infosMutex);
-    return nitrogenCloseTs != 0;
+    return chamberCloseTs != 0;
 }
 
 uint32_t Actuators::getServoOpeningTime(ServosList servo)
@@ -467,25 +418,28 @@ void Actuators::inject(DependencyInjector& injector)
 
 Actuators::ServoInfo* Actuators::getServo(ServosList servo)
 {
-    // info[4] and info[7] are currently unavailable
     switch (servo)
     {
-        case N2O_FILLING_VALVE:
+        case N2O_FILLING_VALVE:  // OX_FIL
             return &infos[0];
-        case N2O_RELEASE_VALVE:
+        case N2O_RELEASE_VALVE:  // OX_REL
             return &infos[1];
-        case N2O_VENTING_VALVE:
+        case N2O_DETACH_SERVO:  // OX_DET
             return &infos[2];
-        case N2_FILLING_VALVE:
-            return &infos[3];
-        case N2_RELEASE_VALVE:
+        case N2_FILLING_VALVE:  // N2_FIL
+            return &infos[4];
+        case N2_RELEASE_VALVE:  // N2_REL
             return &infos[5];
-        case N2_DETACH_SERVO:
+        case N2_DETACH_SERVO:  // N2_DET
             return &infos[6];
-        case MAIN_VALVE:
+        case NITROGEN_VALVE:  // NITR
+            return &infos[7];
+        case N2O_VENTING_VALVE:  // OX_VEN
             return &infos[8];
-        case NITROGEN_VALVE:
+        case N2_QUENCHING_VALVE:  // N2_QUE
             return &infos[9];
+        case MAIN_VALVE:  // MAIN
+            return &infos[10];
 
         default:
             // Oh FUCK
@@ -564,13 +518,13 @@ void Actuators::updatePositionsTask()
     }
 
     // Handle nitrogen logic
-    if (currentTime < nitrogenCloseTs)
+    if (currentTime < chamberCloseTs)
     {
         unsafeOpenChamber();
     }
     else
     {
-        nitrogenCloseTs = 0;
+        chamberCloseTs = 0;
 
         unsafeCloseChamber();
     }
diff --git a/src/RIGv2/Actuators/Actuators.h b/src/RIGv2/Actuators/Actuators.h
index 08b66c634..75c413fcc 100644
--- a/src/RIGv2/Actuators/Actuators.h
+++ b/src/RIGv2/Actuators/Actuators.h
@@ -1,5 +1,5 @@
-/* Copyright (c) 2024 Skyward Experimental Rocketry
- * Authors: Davide Mor
+/* Copyright (c) 2025 Skyward Experimental Rocketry
+ * Authors: Davide Mor, Niccolò Betto
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -41,29 +41,34 @@ class Actuators
 private:
     struct ServoInfo : public Boardcore::InjectableWithDeps<Registry>
     {
+        struct ServoConfig
+        {
+            float limit  = 1.0;    ///< Movement range limit
+            bool flipped = false;  ///< Whether the servo is flipped
+            uint32_t defaultOpeningTime = 1000;  // Default opening time [ms]
+            float defaultMaxAperture    = 1.0;   // Max aperture
+
+            uint8_t openingEvent = 0;  ///< Event to fire after opening
+            uint8_t closingEvent = 0;  ///< Event to fire after closing
+            uint32_t openingTimeRegKey =
+                CONFIG_ID_DEFAULT_OPENING_TIME;  ///< Registry key for opening
+                                                 ///< time
+            uint32_t maxApertureRegKey =
+                CONFIG_ID_DEFAULT_MAX_APERTURE;  ///< Registry key for max
+                                                 ///< aperture
+        };
+
+        ServoInfo(std::unique_ptr<Boardcore::Servo> servo,
+                  const ServoConfig& config)
+            : servo(std::move(servo)), config(config)
+        {
+        }
+
         std::unique_ptr<Boardcore::Servo> servo;
-        // Hard limit of the aperture
-        float limit = 1.0;
-        // Should this servo be reversed?
-        bool flipped = false;
-        // How much time to stay open
-        uint32_t defaultOpeningTime = 100000;  // Default 100s [ms]
-        // What angle is the maximum
-        float defaultMaxAperture = 1.0;
-
-        // What event to fire while opening?
-        uint8_t openingEvent = 0;
-        // What event to fire while closing?
-        uint8_t closingEvent = 0;
-        // How much time to stay open
-        uint32_t openingTimeKey = CONFIG_ID_DEFAULT_OPENING_TIME;
-        // What angle is the maximum
-        uint32_t maxApertureKey = CONFIG_ID_DEFAULT_MAX_APERTURE;
-
-        // Timestamp of when the servo should close, 0 if closed
-        long long closeTs = 0;
-        // Timestamp of last servo action (open/close)
-        long long lastActionTs = 0;
+        ServoConfig config;
+
+        long long closeTs = 0;  ///< Timestamp to close the servo (0 if closed)
+        long long lastActionTs = 0;  ///< Timestamp of last servo action
 
         void openServoWithTime(uint32_t time);
         void closeServo();
@@ -93,6 +98,9 @@ public:
     bool isServoOpen(ServosList servo);
     bool isCanServoOpen(ServosList servo);
 
+    // N2 3-way valve control
+    void set3wayValveState(bool state);
+
     // Chamber valve control
     void openChamberWithTime(uint32_t time);
     void closeChamber();
@@ -120,20 +128,21 @@ private:
 
     void updatePositionsTask();
 
-    Boardcore::Logger& sdLogger   = Boardcore::Logger::getInstance();
-    Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("actuators");
-
     std::atomic<bool> started{false};
 
     miosix::FastMutex infosMutex;
-    ServoInfo infos[10] = {};
-    // Timestamp of when the servo should close, 0 if closed
-    long long nitrogenCloseTs = 0;
-    // Timestamp of last servo action (open/close)
-    long long nitrogenLastActionTs = 0;
+    ServoInfo infos[10];
+    ServoInfo n2_3wayValveInfo;
+
+    long long chamberCloseTs =
+        0;  ///< Timestamp to close the chamber (0 if closed)
+    long long chamberLastActionTs = 0;  ///< Timestamp of last chamber action
 
     bool canMainOpen    = false;
     bool canVentingOpen = false;
+
+    Boardcore::Logger& sdLogger   = Boardcore::Logger::getInstance();
+    Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("actuators");
 };
 
 }  // namespace RIGv2
diff --git a/src/RIGv2/Configs/ActuatorsConfig.h b/src/RIGv2/Configs/ActuatorsConfig.h
index 74b5a06ac..6a8f819fd 100644
--- a/src/RIGv2/Configs/ActuatorsConfig.h
+++ b/src/RIGv2/Configs/ActuatorsConfig.h
@@ -1,5 +1,5 @@
-/* Copyright (c) 2024 Skyward Experimental Rocketry
- * Authors: Davide Mor
+/* Copyright (c) 2025 Skyward Experimental Rocketry
+ * Authors: Davide Mor, Niccolò Betto
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -22,27 +22,26 @@
 
 #pragma once
 
-#include <interfaces-impl/hwmapping.h>
 #include <units/Frequency.h>
 
+#include <chrono>
+
 namespace RIGv2
 {
 namespace Config
 {
-
 namespace Servos
 {
-
 /* linter off */ using namespace Boardcore::Units::Frequency;
+/* linter off */ using namespace std::chrono;
 
-// Generic pulse width for all servos
+// Pulse width for all servos
 constexpr unsigned int MIN_PULSE = 500;
 constexpr unsigned int MAX_PULSE = 2440;
 
-// Pulse width specific to SERVO 2 (disconnect servo)
-// TODO(davide.mor): This actually needs tweaking
-constexpr unsigned int SERVO2_MIN_PULSE = 900;
-constexpr unsigned int SERVO2_MAX_PULSE = 2100;
+// Pulse width for detach servos
+constexpr unsigned int DETACH_MIN_PULSE = 900;
+constexpr unsigned int DETACH_MAX_PULSE = 2100;
 
 constexpr unsigned int FREQUENCY = 333;
 
@@ -50,31 +49,52 @@ constexpr Hertz SERVO_TIMINGS_CHECK_PERIOD = 10_hz;
 constexpr long long SERVO_CONFIDENCE_TIME  = 500;   // 0.5s
 constexpr float SERVO_CONFIDENCE           = 0.02;  // 2%
 
-constexpr uint32_t DEFAULT_FILLING_OPENING_TIME    = 15000;  // 15s
-constexpr uint32_t DEFAULT_VENTING_OPENING_TIME    = 15000;  // 15s
-constexpr uint32_t DEFAULT_MAIN_OPENING_TIME       = 6000;   // 6s
-constexpr uint32_t DEFAULT_RELEASE_OPENING_TIME    = 10000;  // 10s
-constexpr uint32_t DEFAULT_DISCONNECT_OPENING_TIME = 2000;   // 2s
+constexpr uint32_t DEFAULT_OX_FIL_OPENING_TIME = 15000;
+constexpr uint32_t DEFAULT_OX_REL_OPENING_TIME = 10000;
+constexpr uint32_t DEFAULT_OX_DET_OPENING_TIME = 2000;
+constexpr uint32_t DEFAULT_N2_FIL_OPENING_TIME = 15000;
+constexpr uint32_t DEFAULT_N2_REL_OPENING_TIME = 10000;
+constexpr uint32_t DEFAULT_N2_DET_OPENING_TIME = 2000;
+constexpr uint32_t DEFAULT_NITR_OPENING_TIME   = 600000;
+constexpr uint32_t DEFAULT_OX_VEN_OPENING_TIME = 15000;
+constexpr uint32_t DEFAULT_N2_QUE_OPENING_TIME = 15000;
+constexpr uint32_t DEFAULT_MAIN_OPENING_TIME   = 6000;
 
-constexpr float DEFAULT_FILLING_MAX_APERTURE    = 1.00f;
-constexpr float DEFAULT_VENTING_MAX_APERTURE    = 1.00f;
-constexpr float DEFAULT_MAIN_MAX_APERTURE       = 1.00f;
-constexpr float DEFAULT_RELEASE_MAX_APERTURE    = 1.00f;
-constexpr float DEFAULT_DISCONNECT_MAX_APERTURE = 1.00f;
+constexpr float DEFAULT_OX_FIL_MAX_APERTURE = 1.0;
+constexpr float DEFAULT_OX_REL_MAX_APERTURE = 1.0;
+constexpr float DEFAULT_OX_DET_MAX_APERTURE = 1.0;
+constexpr float DEFAULT_N2_FIL_MAX_APERTURE = 1.0;
+constexpr float DEFAULT_N2_REL_MAX_APERTURE = 1.0;
+constexpr float DEFAULT_N2_DET_MAX_APERTURE = 1.0;
+constexpr float DEFAULT_NITR_MAX_APERTURE   = 1.0;
+constexpr float DEFAULT_OX_VEN_MAX_APERTURE = 1.0;
+constexpr float DEFAULT_N2_QUE_MAX_APERTURE = 1.0;
+constexpr float DEFAULT_MAIN_MAX_APERTURE   = 1.0;
 
-constexpr float FILLING_LIMIT    = 0.90f;
-constexpr float VENTING_LIMIT    = 0.90f;
-constexpr float MAIN_LIMIT       = 0.90f;
-constexpr float RELEASE_LIMIT    = 0.50f;
-constexpr float DISCONNECT_LIMIT = 1.00f;
+constexpr float OX_FIL_LIMIT = 0.9;
+constexpr float OX_REL_LIMIT = 0.5;
+constexpr float OX_DET_LIMIT = 1.0;
+constexpr float N2_3W_LIMIT  = 1.0;
+constexpr float N2_FIL_LIMIT = 0.9;
+constexpr float N2_REL_LIMIT = 0.5;
+constexpr float N2_DET_LIMIT = 1.0;
+constexpr float NITR_LIMIT   = 0.9;
+constexpr float OX_VEN_LIMIT = 0.9;
+constexpr float N2_QUE_LIMIT = 0.9;
+constexpr float MAIN_LIMIT   = 0.9;
 
-constexpr bool FILLING_FLIPPED    = true;
-constexpr bool VENTING_FLIPPED    = true;
-constexpr bool MAIN_FLIPPED       = true;
-constexpr bool RELEASE_FLIPPED    = true;
-constexpr bool DISCONNECT_FLIPPED = false;
+constexpr bool OX_FIL_FLIPPED = true;
+constexpr bool OX_REL_FLIPPED = true;
+constexpr bool OX_DET_FLIPPED = false;
+constexpr bool N2_3W_FLIPPED  = true;
+constexpr bool N2_FIL_FLIPPED = true;
+constexpr bool N2_REL_FLIPPED = true;
+constexpr bool N2_DET_FLIPPED = false;
+constexpr bool NITR_FLIPPED   = true;
+constexpr bool OX_VEN_FLIPPED = true;
+constexpr bool N2_QUE_FLIPPED = true;
+constexpr bool MAIN_FLIPPED   = true;
 
 }  // namespace Servos
-
 }  // namespace Config
 }  // namespace RIGv2
diff --git a/src/RIGv2/Registry/Registry.cpp b/src/RIGv2/Registry/Registry.cpp
index 2fa748947..bd02273bd 100644
--- a/src/RIGv2/Registry/Registry.cpp
+++ b/src/RIGv2/Registry/Registry.cpp
@@ -33,46 +33,46 @@ const char* RIGv2::configurationIdToName(ConfigurationId id)
 {
     switch (id)
     {
-        case CONFIG_ID_N2O_FILLING_OPENING_TIME:
-            return "N2O_FILLING_OPENING_TIME";
-        case CONFIG_ID_N2O_FILLING_MAX_APERTURE:
-            return "N2O_FILLING_MAX_APERTURE";
-        case CONFIG_ID_N2O_RELEASE_OPENING_TIME:
-            return "N2O_RELEASE_OPENING_TIME";
-        case CONFIG_ID_N2O_RELEASE_MAX_APERTURE:
-            return "N2O_RELEASE_MAX_APERTURE";
-        case CONFIG_ID_N2O_DETACH_OPENING_TIME:
-            return "N2O_DETACH_OPENING_TIME";
-        case CONFIG_ID_N2O_DETACH_MAX_APERTURE:
-            return "N2O_DETACH_MAX_APERTURE";
-        case CONFIG_ID_N2O_VENTING_OPENING_TIME:
-            return "N2O_VENTING_OPENING_TIME";
-        case CONFIG_ID_N2O_VENTING_MAX_APERTURE:
-            return "N2O_VENTING_MAX_APERTURE";
-        case CONFIG_ID_N2_FILLING_OPENING_TIME:
-            return "N2_FILLING_OPENING_TIME";
-        case CONFIG_ID_N2_FILLING_MAX_APERTURE:
-            return "N2_FILLING_MAX_APERTURE";
-        case CONFIG_ID_N2_RELEASE_OPENING_TIME:
-            return "N2_RELEASE_OPENING_TIME";
-        case CONFIG_ID_N2_RELEASE_MAX_APERTURE:
-            return "N2_RELEASE_MAX_APERTURE";
-        case CONFIG_ID_N2_DETACH_OPENING_TIME:
-            return "N2_DETACH_OPENING_TIME";
-        case CONFIG_ID_N2_DETACH_MAX_APERTURE:
-            return "N2_DETACH_MAX_APERTURE";
-        case CONFIG_ID_N2_QUENCHING_OPENING_TIME:
-            return "N2_QUENCHING_OPENING_TIME";
-        case CONFIG_ID_N2_QUENCHING_MAX_APERTURE:
-            return "N2_QUENCHING_MAX_APERTURE";
+        case CONFIG_ID_OX_FIL_OPENING_TIME:
+            return "OX_FIL_OPENING_TIME";
+        case CONFIG_ID_OX_FIL_MAX_APERTURE:
+            return "OX_FIL_MAX_APERTURE";
+        case CONFIG_ID_OX_REL_OPENING_TIME:
+            return "OX_REL_OPENING_TIME";
+        case CONFIG_ID_OX_REL_MAX_APERTURE:
+            return "OX_REL_MAX_APERTURE";
+        case CONFIG_ID_OX_DET_OPENING_TIME:
+            return "OX_DET_OPENING_TIME";
+        case CONFIG_ID_OX_DET_MAX_APERTURE:
+            return "OX_DET_MAX_APERTURE";
+        case CONFIG_ID_OX_VEN_OPENING_TIME:
+            return "OX_VEN_OPENING_TIME";
+        case CONFIG_ID_OX_VEN_MAX_APERTURE:
+            return "OX_VEN_MAX_APERTURE";
+        case CONFIG_ID_N2_FIL_OPENING_TIME:
+            return "N2_FIL_OPENING_TIME";
+        case CONFIG_ID_N2_FIL_MAX_APERTURE:
+            return "N2_FIL_MAX_APERTURE";
+        case CONFIG_ID_N2_REL_OPENING_TIME:
+            return "N2_REL_OPENING_TIME";
+        case CONFIG_ID_N2_REL_MAX_APERTURE:
+            return "N2_REL_MAX_APERTURE";
+        case CONFIG_ID_N2_DET_OPENING_TIME:
+            return "N2_DET_OPENING_TIME";
+        case CONFIG_ID_N2_DET_MAX_APERTURE:
+            return "N2_DET_MAX_APERTURE";
+        case CONFIG_ID_N2_QUE_OPENING_TIME:
+            return "N2_QUE_OPENING_TIME";
+        case CONFIG_ID_N2_QUE_MAX_APERTURE:
+            return "N2_QUE_MAX_APERTURE";
         case CONFIG_ID_MAIN_OPENING_TIME:
             return "MAIN_OPENING_TIME";
         case CONFIG_ID_MAIN_MAX_APERTURE:
             return "MAIN_MAX_APERTURE";
-        case CONFIG_ID_NITROGEN_OPENING_TIME:
-            return "NITROGEN_OPENING_TIME";
-        case CONFIG_ID_NITROGEN_MAX_APERTURE:
-            return "NITROGEN_MAX_APERTURE";
+        case CONFIG_ID_NITR_OPENING_TIME:
+            return "NITR_OPENING_TIME";
+        case CONFIG_ID_NITR_MAX_APERTURE:
+            return "NITR_MAX_APERTURE";
         case CONFIG_ID_IGNITION_TIME:
             return "IGNITION_TIME";
         case CONFIG_ID_DEFAULT_OPENING_TIME:
diff --git a/src/RIGv2/Registry/Registry.h b/src/RIGv2/Registry/Registry.h
index b1f8e4cd2..6f26a3934 100644
--- a/src/RIGv2/Registry/Registry.h
+++ b/src/RIGv2/Registry/Registry.h
@@ -31,37 +31,37 @@ namespace RIGv2
 enum ConfigurationKeys
 {
     // N2O
-    CONFIG_ID_N2O_FILLING_OPENING_TIME,
-    CONFIG_ID_N2O_FILLING_MAX_APERTURE,
+    CONFIG_ID_OX_FIL_OPENING_TIME,
+    CONFIG_ID_OX_FIL_MAX_APERTURE,
 
-    CONFIG_ID_N2O_RELEASE_OPENING_TIME,
-    CONFIG_ID_N2O_RELEASE_MAX_APERTURE,
+    CONFIG_ID_OX_REL_OPENING_TIME,
+    CONFIG_ID_OX_REL_MAX_APERTURE,
 
-    CONFIG_ID_N2O_DETACH_OPENING_TIME,
-    CONFIG_ID_N2O_DETACH_MAX_APERTURE,
+    CONFIG_ID_OX_DET_OPENING_TIME,
+    CONFIG_ID_OX_DET_MAX_APERTURE,
 
-    CONFIG_ID_N2O_VENTING_OPENING_TIME,
-    CONFIG_ID_N2O_VENTING_MAX_APERTURE,
+    CONFIG_ID_OX_VEN_OPENING_TIME,
+    CONFIG_ID_OX_VEN_MAX_APERTURE,
 
     // N2
-    CONFIG_ID_N2_FILLING_OPENING_TIME,
-    CONFIG_ID_N2_FILLING_MAX_APERTURE,
+    CONFIG_ID_N2_FIL_OPENING_TIME,
+    CONFIG_ID_N2_FIL_MAX_APERTURE,
 
-    CONFIG_ID_N2_RELEASE_OPENING_TIME,
-    CONFIG_ID_N2_RELEASE_MAX_APERTURE,
+    CONFIG_ID_N2_REL_OPENING_TIME,
+    CONFIG_ID_N2_REL_MAX_APERTURE,
 
-    CONFIG_ID_N2_DETACH_OPENING_TIME,
-    CONFIG_ID_N2_DETACH_MAX_APERTURE,
+    CONFIG_ID_N2_DET_OPENING_TIME,
+    CONFIG_ID_N2_DET_MAX_APERTURE,
 
-    CONFIG_ID_N2_QUENCHING_OPENING_TIME,
-    CONFIG_ID_N2_QUENCHING_MAX_APERTURE,
+    CONFIG_ID_N2_QUE_OPENING_TIME,
+    CONFIG_ID_N2_QUE_MAX_APERTURE,
 
     // Main & Nitrogen
     CONFIG_ID_MAIN_OPENING_TIME,
     CONFIG_ID_MAIN_MAX_APERTURE,
 
-    CONFIG_ID_NITROGEN_OPENING_TIME,
-    CONFIG_ID_NITROGEN_MAX_APERTURE,
+    CONFIG_ID_NITR_OPENING_TIME,
+    CONFIG_ID_NITR_MAX_APERTURE,
 
     // Ignition parameters
     CONFIG_ID_IGNITION_TIME,
diff --git a/src/common/Events.h b/src/common/Events.h
index efff19c8d..6a93c35fd 100644
--- a/src/common/Events.h
+++ b/src/common/Events.h
@@ -144,16 +144,29 @@ enum Events : uint8_t
     TMTC_ARP_EXIT_TEST_MODE,
     MOTOR_START_TARS,
     MOTOR_STOP_TARS,
-    MOTOR_OPEN_VENTING_VALVE,
-    MOTOR_CLOSE_VENTING_VALVE,
-    MOTOR_OPEN_FILLING_VALVE,
-    MOTOR_CLOSE_FILLING_VALVE,
-    MOTOR_OPEN_RELEASE_VALVE,
-    MOTOR_CLOSE_RELEASE_VALVE,
-    MOTOR_DISCONNECT,
+    MOTOR_OX_FIL_OPEN,
+    MOTOR_OX_FIL_CLOSE,
+    MOTOR_OX_REL_OPEN,
+    MOTOR_OX_REL_CLOSE,
+    MOTOR_OX_DET_OPEN,
+    MOTOR_OX_DET_CLOSE,
+    MOTOR_N2_3W_OPEN,
+    MOTOR_N2_3W_CLOSE,
+    MOTOR_N2_FIL_OPEN,
+    MOTOR_N2_FIL_CLOSE,
+    MOTOR_N2_REL_OPEN,
+    MOTOR_N2_REL_CLOSE,
+    MOTOR_N2_DET_OPEN,
+    MOTOR_N2_DET_CLOSE,
+    MOTOR_NITR_OPEN,
+    MOTOR_NITR_CLOSE,
+    MOTOR_OX_VEN_OPEN,
+    MOTOR_OX_VEN_CLOSE,
+    MOTOR_N2_QUE_OPEN,
+    MOTOR_N2_QUE_CLOSE,
+    MOTOR_MAIN_OPEN,
+    MOTOR_MAIN_CLOSE,
     MOTOR_IGNITION,
-    MOTOR_OPEN_FEED_VALVE,
-    MOTOR_CLOSE_FEED_VALVE,
     MOTOR_MANUAL_ACTION,
     MOTOR_OPEN_OXIDANT,
     MOTOR_COOLING_TIMEOUT,
@@ -280,16 +293,18 @@ inline std::string getEventString(uint8_t event)
         {TMTC_ARP_EXIT_TEST_MODE, "TMTC_ARP_EXIT_TEST_MODE"},
         {MOTOR_START_TARS, "MOTOR_START_TARS"},
         {MOTOR_STOP_TARS, "MOTOR_STOP_TARS"},
-        {MOTOR_OPEN_VENTING_VALVE, "MOTOR_OPEN_VENTING_VALVE"},
-        {MOTOR_CLOSE_VENTING_VALVE, "MOTOR_CLOSE_VENTING_VALVE"},
-        {MOTOR_OPEN_FILLING_VALVE, "MOTOR_OPEN_FILLING_VALVE"},
-        {MOTOR_CLOSE_FILLING_VALVE, "MOTOR_CLOSE_FILLING_VALVE"},
-        {MOTOR_OPEN_RELEASE_VALVE, "MOTOR_OPEN_RELEASE_VALVE"},
-        {MOTOR_CLOSE_RELEASE_VALVE, "MOTOR_CLOSE_RELEASE_VALVE"},
-        {MOTOR_DISCONNECT, "MOTOR_DISCONNECT"},
+        {MOTOR_OX_FIL_OPEN, "MOTOR_OX_FIL_OPEN"},
+        {MOTOR_OX_REL_OPEN, "MOTOR_OX_REL_OPEN"},
+        {MOTOR_OX_DET_OPEN, "MOTOR_OX_DET_OPEN"},
+        {MOTOR_N2_3W_OPEN, "MOTOR_N2_3W_OPEN"},
+        {MOTOR_N2_FIL_OPEN, "MOTOR_N2_FIL_OPEN"},
+        {MOTOR_N2_REL_OPEN, "MOTOR_N2_REL_OPEN"},
+        {MOTOR_N2_DET_OPEN, "MOTOR_N2_DET_OPEN"},
+        {MOTOR_NITR_OPEN, "MOTOR_NITR_OPEN"},
+        {MOTOR_OX_VEN_OPEN, "MOTOR_OX_VEN_OPEN"},
+        {MOTOR_N2_QUE_OPEN, "MOTOR_N2_QUE_OPEN"},
+        {MOTOR_MAIN_OPEN, "MOTOR_MAIN_OPEN"},
         {MOTOR_IGNITION, "MOTOR_IGNITION"},
-        {MOTOR_OPEN_FEED_VALVE, "MOTOR_OPEN_FEED_VALVE"},
-        {MOTOR_CLOSE_FEED_VALVE, "MOTOR_CLOSE_FEED_VALVE"},
         {MOTOR_MANUAL_ACTION, "MOTOR_MANUAL_ACTION"},
         {MOTOR_OPEN_OXIDANT, "MOTOR_OPEN_OXIDANT"},
         {MOTOR_COOLING_TIMEOUT, "MOTOR_COOLING_TIMEOUT"},
-- 
GitLab


From 328b60b264783851ad42c6082c1809e41603e70e Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Tue, 11 Feb 2025 13:11:24 +0100
Subject: [PATCH 12/14] [RIGv2][Radio] Update ConRIG state handler to Orion
 valves

---
 src/RIGv2/Radio/Radio.cpp | 69 ++++++++++++++++++++++++---------------
 src/RIGv2/Radio/Radio.h   |  3 +-
 2 files changed, 44 insertions(+), 28 deletions(-)

diff --git a/src/RIGv2/Radio/Radio.cpp b/src/RIGv2/Radio/Radio.cpp
index 3b5d301f1..4e6b17fbf 100644
--- a/src/RIGv2/Radio/Radio.cpp
+++ b/src/RIGv2/Radio/Radio.cpp
@@ -889,109 +889,124 @@ void Radio::handleConrigState(const mavlink_message_t& msg)
     mavlink_conrig_state_tc_t state;
     mavlink_msg_conrig_state_tc_decode(&msg, &state);
 
+#define BUTTON_PRESSED(btn) (lastConrigState.btn == 0 && state.btn == 1)
+#define BUTTON_CHANGED(btn) (lastConrigState.btn != state.btn)
+
+    // Use a debounce time to prevent updates too close to each other
+    // that may be caused by interference on the buttons
+    auto debounceTime     = msToNs(Config::Radio::LAST_COMMAND_THRESHOLD);
     long long currentTime = getTime();
-    if (currentTime >
-        lastManualActuation +
-            (Config::Radio::LAST_COMMAND_THRESHOLD * Constants::NS_IN_MS))
+
+    if (currentTime > lastManualActuation + debounceTime)
     {
         // Ok we can accept new commands
-        if (oldConrigState.arm_switch == 0 && state.arm_switch == 1)
+        if (BUTTON_PRESSED(arm_switch))
         {
             // The ARM switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
             EventBroker::getInstance().post(TMTC_ARM, TOPIC_MOTOR);
-
             lastManualActuation = currentTime;
         }
 
-        if (oldConrigState.ignition_btn == 0 && state.ignition_btn == 1)
+        if (BUTTON_PRESSED(ignition_btn))
         {
             // The ignition switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
             EventBroker::getInstance().post(MOTOR_IGNITION, TOPIC_MOTOR);
-
             lastManualActuation = currentTime;
         }
 
-        if (oldConrigState.n2o_filling_btn == 0 && state.n2o_filling_btn == 1)
+        if (BUTTON_PRESSED(n2o_filling_btn))
         {
             // The N2O filling switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
             getModule<Actuators>()->toggleServo(ServosList::N2O_FILLING_VALVE);
-
             lastManualActuation = currentTime;
         }
 
-        if (oldConrigState.n2o_release_btn == 0 && state.n2o_release_btn == 1)
+        if (BUTTON_PRESSED(n2o_release_btn))
         {
             // The N2O release switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
             getModule<Actuators>()->toggleServo(ServosList::N2O_RELEASE_VALVE);
-
             lastManualActuation = currentTime;
         }
 
-        // TODO: n2o_detach_btn
+        if (BUTTON_PRESSED(n2o_detach_btn))
+        {
+            // The N2O detach switch was pressed
+            EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
+            getModule<Actuators>()->toggleServo(ServosList::N2O_DETACH_SERVO);
+            lastManualActuation = currentTime;
+        }
 
-        if (oldConrigState.n2o_venting_btn == 0 && state.n2o_venting_btn == 1)
+        if (BUTTON_PRESSED(n2o_venting_btn))
         {
             // The N2O venting switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
             getModule<Actuators>()->toggleServo(ServosList::N2O_VENTING_VALVE);
-
             lastManualActuation = currentTime;
         }
 
-        if (oldConrigState.n2_filling_btn == 0 && state.n2_filling_btn == 1)
+        if (BUTTON_PRESSED(n2_filling_btn))
         {
             // The N2 filling switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
             getModule<Actuators>()->toggleServo(ServosList::N2_FILLING_VALVE);
-
             lastManualActuation = currentTime;
         }
 
-        if (oldConrigState.n2_release_btn == 0 && state.n2_release_btn == 1)
+        if (BUTTON_PRESSED(n2_release_btn))
         {
             // The N2 release switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
             getModule<Actuators>()->toggleServo(ServosList::N2_RELEASE_VALVE);
-
             lastManualActuation = currentTime;
         }
 
-        if (oldConrigState.n2_detach_btn == 0 && state.n2_detach_btn == 1)
+        if (BUTTON_PRESSED(n2_detach_btn))
         {
             // The N2 detach switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
             getModule<Actuators>()->toggleServo(ServosList::N2_DETACH_SERVO);
-
             lastManualActuation = currentTime;
         }
 
-        // TODO: n2_quenching_btn
-        // TODO: n2_3way_btn
+        if (BUTTON_PRESSED(n2_quenching_btn))
+        {
+            // The N2 quenching switch was pressed
+            EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
+            getModule<Actuators>()->toggleServo(ServosList::N2_QUENCHING_VALVE);
+            lastManualActuation = currentTime;
+        }
 
-        if (oldConrigState.tars_btn == 0 && state.tars_btn == 1)
+        // TODO: tars3
+        if (BUTTON_PRESSED(tars_btn))
         {
             // The TARS switch was pressed
             EventBroker::getInstance().post(MOTOR_START_TARS, TOPIC_TARS);
-
             lastManualActuation = currentTime;
         }
 
-        if (oldConrigState.nitrogen_btn == 0 && state.nitrogen_btn == 1)
+        if (BUTTON_PRESSED(nitrogen_btn))
         {
             // The nitrogen switch was pressed
             EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
             getModule<Actuators>()->toggleServo(ServosList::NITROGEN_VALVE);
+            lastManualActuation = currentTime;
+        }
 
+        if (BUTTON_CHANGED(n2_3way_btn))
+        {
+            // The 3-way valve switch was pressed
+            EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
+            getModule<Actuators>()->set3wayValveState(state.n2_3way_btn);
             lastManualActuation = currentTime;
         }
     }
 
     // Special case for disarming, that can be done bypassing the timeout
-    if (oldConrigState.arm_switch == 1 && state.arm_switch == 0)
+    if (lastConrigState.arm_switch == 1 && state.arm_switch == 0)
     {
         EventBroker::getInstance().post(MOTOR_MANUAL_ACTION, TOPIC_TARS);
         EventBroker::getInstance().post(TMTC_DISARM, TOPIC_MOTOR);
@@ -999,5 +1014,5 @@ void Radio::handleConrigState(const mavlink_message_t& msg)
         lastManualActuation = currentTime;
     }
 
-    oldConrigState = state;
+    lastConrigState = state;
 }
diff --git a/src/RIGv2/Radio/Radio.h b/src/RIGv2/Radio/Radio.h
index 582ee6d97..37b61efd8 100644
--- a/src/RIGv2/Radio/Radio.h
+++ b/src/RIGv2/Radio/Radio.h
@@ -88,7 +88,8 @@ private:
 
     // Last time a ConRIG state triggered an actuation [ns]
     long long lastManualActuation = 0;
-    mavlink_conrig_state_tc_t oldConrigState;
+    // Last ConRIG state received and processed
+    mavlink_conrig_state_tc_t lastConrigState;
 };
 
 }  // namespace RIGv2
-- 
GitLab


From cfbc228bc1300d457b3adbe2b04508d6d271ffd1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Thu, 6 Mar 2025 00:25:42 +0100
Subject: [PATCH 13/14] [RIGv2] Update to Orion sensors

Updated pressure transducers list for the Orion system:
* OX Vessel
* OX Filling
* N2 Vessel 1
* N2 Vessel 2
* N2 Filling
* OX Tank Top
* OX Tank Bottom
---
 scripts/logdecoder/General/logdecoder.cpp |  16 +-
 scripts/logdecoder/RIGv2/logdecoder.cpp   |  16 +-
 src/RIGv2/CanHandler/CanHandler.cpp       |   8 +-
 src/RIGv2/Configs/SensorsConfig.h         |  88 ++--
 src/RIGv2/Radio/Radio.cpp                 |  92 ++--
 src/RIGv2/Sensors/Sensors.cpp             | 486 ++++++++++++++--------
 src/RIGv2/Sensors/Sensors.h               | 114 +++--
 src/RIGv2/Sensors/SensorsData.h           |  78 +++-
 src/RIGv2/StateMachines/TARS1/TARS1.cpp   |   4 +-
 src/RIGv2/rig-v2-entry.cpp                |   6 +-
 10 files changed, 576 insertions(+), 332 deletions(-)

diff --git a/scripts/logdecoder/General/logdecoder.cpp b/scripts/logdecoder/General/logdecoder.cpp
index 73451409c..c2639f17f 100644
--- a/scripts/logdecoder/General/logdecoder.cpp
+++ b/scripts/logdecoder/General/logdecoder.cpp
@@ -106,13 +106,17 @@ void registerTypes(Deserializer& ds)
 
     // RIGv2
     ds.registerType<RIGv2::ADC1Data>();
+    ds.registerType<RIGv2::ADC2Data>();
     ds.registerType<RIGv2::TC1Data>();
-    ds.registerType<RIGv2::VesselWeightData>();
-    ds.registerType<RIGv2::TankWeightData>();
-    ds.registerType<RIGv2::VesselPressureData>();
-    ds.registerType<RIGv2::FillingPressureData>();
-    ds.registerType<RIGv2::TopTankPressureData>();
-    ds.registerType<RIGv2::BottomTankPressureData>();
+    ds.registerType<RIGv2::OxVesselWeightData>();
+    ds.registerType<RIGv2::OxTankWeightData>();
+    ds.registerType<RIGv2::OxVesselPressureData>();
+    ds.registerType<RIGv2::OxFillingPressureData>();
+    ds.registerType<RIGv2::N2Vessel1PressureData>();
+    ds.registerType<RIGv2::N2Vessel2PressureData>();
+    ds.registerType<RIGv2::N2FillingPressureData>();
+    ds.registerType<RIGv2::OxTankTopPressureData>();
+    ds.registerType<RIGv2::OxTankBottomPressureData>();
     ds.registerType<RIGv2::ActuatorsData>();
     ds.registerType<RIGv2::GroundModeManagerData>();
     ds.registerType<RIGv2::TarsActionData>();
diff --git a/scripts/logdecoder/RIGv2/logdecoder.cpp b/scripts/logdecoder/RIGv2/logdecoder.cpp
index 6709b7eca..666ae2f71 100644
--- a/scripts/logdecoder/RIGv2/logdecoder.cpp
+++ b/scripts/logdecoder/RIGv2/logdecoder.cpp
@@ -54,13 +54,17 @@ void registerTypes(Deserializer& ds)
 
     // Custom types
     ds.registerType<ADC1Data>();
+    ds.registerType<ADC2Data>();
     ds.registerType<TC1Data>();
-    ds.registerType<VesselWeightData>();
-    ds.registerType<TankWeightData>();
-    ds.registerType<VesselPressureData>();
-    ds.registerType<FillingPressureData>();
-    ds.registerType<TopTankPressureData>();
-    ds.registerType<BottomTankPressureData>();
+    ds.registerType<OxVesselWeightData>();
+    ds.registerType<OxTankWeightData>();
+    ds.registerType<OxVesselPressureData>();
+    ds.registerType<OxFillingPressureData>();
+    ds.registerType<N2Vessel1PressureData>();
+    ds.registerType<N2Vessel2PressureData>();
+    ds.registerType<N2FillingPressureData>();
+    ds.registerType<OxTankTopPressureData>();
+    ds.registerType<OxTankBottomPressureData>();
     ds.registerType<ActuatorsData>();
     ds.registerType<GroundModeManagerData>();
     ds.registerType<TarsActionData>();
diff --git a/src/RIGv2/CanHandler/CanHandler.cpp b/src/RIGv2/CanHandler/CanHandler.cpp
index 055ae6e57..42494b83b 100644
--- a/src/RIGv2/CanHandler/CanHandler.cpp
+++ b/src/RIGv2/CanHandler/CanHandler.cpp
@@ -205,7 +205,7 @@ void CanHandler::handleSensor(const Canbus::CanMessage& msg)
         {
             CanPressureData data = pressureDataFromCanMessage(msg);
             sdLogger.log(data);
-            sensors->setCanCCPress(data);
+            sensors->setCanCombustionChamberPressure(data);
             break;
         }
 
@@ -213,7 +213,7 @@ void CanHandler::handleSensor(const Canbus::CanMessage& msg)
         {
             CanPressureData data = pressureDataFromCanMessage(msg);
             sdLogger.log(data);
-            sensors->setCanTopTankPress(data);
+            sensors->setCanOxTankTopPressure(data);
             break;
         }
 
@@ -221,7 +221,7 @@ void CanHandler::handleSensor(const Canbus::CanMessage& msg)
         {
             CanPressureData data = pressureDataFromCanMessage(msg);
             sdLogger.log(data);
-            sensors->setCanBottomTankPress(data);
+            sensors->setCanOxTankBottomPressure(data);
             break;
         }
 
@@ -229,7 +229,7 @@ void CanHandler::handleSensor(const Canbus::CanMessage& msg)
         {
             CanTemperatureData data = temperatureDataFromCanMessage(msg);
             sdLogger.log(data);
-            sensors->setCanTankTemp(data);
+            sensors->setCanOxTankTemperature(data);
             break;
         }
 
diff --git a/src/RIGv2/Configs/SensorsConfig.h b/src/RIGv2/Configs/SensorsConfig.h
index 21dfeeb7d..397a5bd8a 100644
--- a/src/RIGv2/Configs/SensorsConfig.h
+++ b/src/RIGv2/Configs/SensorsConfig.h
@@ -1,5 +1,5 @@
 /* Copyright (c) 2024 Skyward Experimental Rocketry
- * Authors: Davide Mor
+ * Authors: Davide Mor, Niccolò Betto
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -42,31 +42,11 @@ namespace Sensors
 
 namespace ADS131M08
 {
-
-constexpr Boardcore::ADS131M08Defs::OversamplingRatio OSR =
-    Boardcore::ADS131M08Defs::OversamplingRatio::OSR_8192;
+constexpr auto OSR = Boardcore::ADS131M08Defs::OversamplingRatio::OSR_8192;
 constexpr bool GLOBAL_CHOP_MODE_EN = true;
 
-constexpr float CH1_SHUNT_RESISTANCE = 29.4048;
-constexpr float CH2_SHUNT_RESISTANCE = 29.5830;
-constexpr float CH3_SHUNT_RESISTANCE = 29.4973;
-constexpr float CH4_SHUNT_RESISTANCE = 29.8849;
-
-// ADC channels definitions for various sensors
-constexpr Boardcore::ADS131M08Defs::Channel VESSEL_PT_CHANNEL =
-    Boardcore::ADS131M08Defs::Channel::CHANNEL_0;
-constexpr Boardcore::ADS131M08Defs::Channel FILLING_PT_CHANNEL =
-    Boardcore::ADS131M08Defs::Channel::CHANNEL_1;
-constexpr Boardcore::ADS131M08Defs::Channel BOTTOM_PT_CHANNEL =
-    Boardcore::ADS131M08Defs::Channel::CHANNEL_2;
-constexpr Boardcore::ADS131M08Defs::Channel TOP_PT_CHANNEL =
-    Boardcore::ADS131M08Defs::Channel::CHANNEL_3;
-constexpr Boardcore::ADS131M08Defs::Channel SERVO_CURRENT_CHANNEL =
-    Boardcore::ADS131M08Defs::Channel::CHANNEL_4;
-constexpr Boardcore::ADS131M08Defs::Channel VESSEL_LC_CHANNEL =
-    Boardcore::ADS131M08Defs::Channel::CHANNEL_5;
-constexpr Boardcore::ADS131M08Defs::Channel TANK_LC_CHANNEL =
-    Boardcore::ADS131M08Defs::Channel::CHANNEL_6;
+constexpr Hertz PERIOD = 100_hz;
+constexpr bool ENABLED = true;
 
 // Servo current sensor calibration data
 // - A: 0.0 V: 2.520
@@ -78,11 +58,39 @@ constexpr Boardcore::ADS131M08Defs::Channel TANK_LC_CHANNEL =
 // - A: 5.2 V: 2.441
 constexpr float SERVO_CURRENT_SCALE = 4.5466;
 constexpr float SERVO_CURRENT_ZERO  = 2.520 / SERVO_CURRENT_SCALE;
-
-constexpr Hertz PERIOD = 100_hz;
-constexpr bool ENABLED = true;
 }  // namespace ADS131M08
 
+namespace ADC_1
+{
+using Channel = Boardcore::ADS131M08Defs::Channel;
+
+constexpr auto OX_VESSEL_PT_CHANNEL   = Channel::CHANNEL_0;
+constexpr auto OX_FILLING_PT_CHANNEL  = Channel::CHANNEL_1;
+constexpr auto N2_VESSEL_1_PT_CHANNEL = Channel::CHANNEL_2;
+constexpr auto N2_VESSEL_2_PT_CHANNEL = Channel::CHANNEL_3;
+constexpr auto SERVO_CURRENT_CHANNEL  = Channel::CHANNEL_4;
+constexpr auto OX_VESSEL_LC_CHANNEL   = Channel::CHANNEL_5;
+constexpr auto OX_TANK_LC_CHANNEL     = Channel::CHANNEL_6;
+constexpr auto N2_FILLING_PT_CHANNEL  = Channel::CHANNEL_7;
+
+constexpr float CH0_SHUNT_RESISTANCE = 29.4048;  // TODO: check
+constexpr float CH1_SHUNT_RESISTANCE = 29.5830;  // TODO: check
+constexpr float CH2_SHUNT_RESISTANCE = 29.4973;  // TODO: check
+constexpr float CH3_SHUNT_RESISTANCE = 29.8849;  // TODO: check
+constexpr float CH7_SHUNT_RESISTANCE = 29.0;     // TODO: measure
+}  // namespace ADC_1
+
+namespace ADC_2
+{
+using Channel = Boardcore::ADS131M08Defs::Channel;
+
+constexpr auto OX_TANK_TOP_PT_CHANNEL    = Channel::CHANNEL_0;
+constexpr auto OX_TANK_BOTTOM_PT_CHANNEL = Channel::CHANNEL_1;
+
+constexpr float CH0_SHUNT_RESISTANCE = 29.0;  // TODO: measure
+constexpr float CH1_SHUNT_RESISTANCE = 29.0;  // TODO: measure
+}  // namespace ADC_2
+
 namespace MAX31856
 {
 constexpr Hertz PERIOD = 10_hz;
@@ -91,18 +99,25 @@ constexpr bool ENABLED = true;
 
 namespace Trafag
 {
-constexpr float FILLING_SHUNT_RESISTANCE     = ADS131M08::CH2_SHUNT_RESISTANCE;
-constexpr float TANK_TOP_SHUNT_RESISTANCE    = ADS131M08::CH4_SHUNT_RESISTANCE;
-constexpr float TANK_BOTTOM_SHUNT_RESISTANCE = ADS131M08::CH3_SHUNT_RESISTANCE;
-constexpr float VESSEL_SHUNT_RESISTANCE      = ADS131M08::CH1_SHUNT_RESISTANCE;
+constexpr float OX_VESSEL_SHUNT_RESISTANCE      = ADC_1::CH0_SHUNT_RESISTANCE;
+constexpr float OX_FILLING_SHUNT_RESISTANCE     = ADC_1::CH1_SHUNT_RESISTANCE;
+constexpr float N2_VESSEL1_SHUNT_RESISTANCE     = ADC_1::CH2_SHUNT_RESISTANCE;
+constexpr float N2_VESSEL2_SHUNT_RESISTANCE     = ADC_1::CH3_SHUNT_RESISTANCE;
+constexpr float N2_FILLING_SHUNT_RESISTANCE     = ADC_1::CH7_SHUNT_RESISTANCE;
+constexpr float OX_TANK_TOP_SHUNT_RESISTANCE    = ADC_2::CH0_SHUNT_RESISTANCE;
+constexpr float OX_TANK_BOTTOM_SHUNT_RESISTANCE = ADC_2::CH1_SHUNT_RESISTANCE;
 
 constexpr float MIN_CURRENT = 4;
 constexpr float MAX_CURRENT = 20;
 
-constexpr float FILLING_MAX_PRESSURE     = 250;  // bar
-constexpr float TANK_TOP_MAX_PRESSURE    = 250;  // bar
-constexpr float TANK_BOTTOM_MAX_PRESSURE = 100;  // bar
-constexpr float VESSEL_MAX_PRESSURE      = 100;  // bar
+// TODO: check depending on which trafags are used
+constexpr float OX_VESSEL_MAX_PRESSURE      = 100;  // bar
+constexpr float OX_FILLING_MAX_PRESSURE     = 250;  // bar
+constexpr float N2_VESSEL1_MAX_PRESSURE     = 400;  // bar
+constexpr float N2_VESSEL2_MAX_PRESSURE     = 400;  // bar
+constexpr float N2_FILLING_MAX_PRESSURE     = 400;  // bar
+constexpr float OX_TANK_TOP_MAX_PRESSURE    = 250;  // bar
+constexpr float OX_TANK_BOTTOM_MAX_PRESSURE = 100;  // bar
 }  // namespace Trafag
 
 namespace LoadCell
@@ -152,8 +167,7 @@ constexpr float VESSEL_P1_MASS    = 8.720;
 
 namespace InternalADC
 {
-constexpr Boardcore::InternalADC::Channel BATTERY_VOLTAGE_CHANNEL =
-    Boardcore::InternalADC::CH14;
+constexpr auto BATTERY_VOLTAGE_CHANNEL = Boardcore::InternalADC::CH14;
 
 constexpr float BATTERY_VOLTAGE_SCALE = 4.7917;
 constexpr Hertz PERIOD                = 10_hz;
diff --git a/src/RIGv2/Radio/Radio.cpp b/src/RIGv2/Radio/Radio.cpp
index 4e6b17fbf..d35a38d32 100644
--- a/src/RIGv2/Radio/Radio.cpp
+++ b/src/RIGv2/Radio/Radio.cpp
@@ -546,26 +546,19 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             tm.timestamp = TimestampTimer::getTimestamp();
 
             // Sensors
-            tm.rocket_mass     = sensors->getTankWeightLastSample().load;
-            tm.n2o_vessel_mass = sensors->getVesselWeightLastSample().load;
-
-            // TODO: methods below have mismatching names
-            tm.n2o_filling_pressure =
-                sensors->getVesselPressLastSample().pressure;
-            tm.n2_filling_pressure =
-                sensors->getFillingPressLastSample().pressure;
-            tm.n2o_vessel_pressure =
-                sensors->getBottomTankPressLastSample().pressure;
-            tm.n2_vessel_1_pressure =
-                sensors->getTopTankPressLastSample().pressure;
-
-            tm.n2_vessel_2_pressure = -1.f;  // TODO
-
-            tm.battery_voltage = sensors->getBatteryVoltageLastSample().voltage;
-            tm.current_consumption =
-                sensors->getServoCurrentLastSample().current;
+            tm.rocket_mass     = sensors->getOxTankWeight().load;
+            tm.n2o_vessel_mass = sensors->getOxVesselWeight().load;
+
+            tm.n2o_vessel_pressure  = sensors->getOxVesselPressure().pressure;
+            tm.n2o_filling_pressure = sensors->getOxFillingPressure().pressure;
+            tm.n2_filling_pressure  = sensors->getN2FillingPressure().pressure;
+            tm.n2_vessel_1_pressure = sensors->getN2Vessel1Pressure().pressure;
+            tm.n2_vessel_2_pressure = sensors->getN2Vessel2Pressure().pressure;
+
+            tm.battery_voltage     = sensors->getBatteryVoltage().voltage;
+            tm.current_consumption = sensors->getServoCurrent().current;
             tm.umbilical_current_consumption =
-                sensors->getUmbilicalCurrentLastSample().current;
+                sensors->getUmbilicalCurrent().current;
 
             // Log data
             LoggerStats stats = sdLogger.getStats();
@@ -641,15 +634,13 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             tm.timestamp = TimestampTimer::getTimestamp();
 
             // Sensors (either CAN or local)
-            tm.top_tank_pressure =
-                sensors->getTopTankPressLastSample().pressure;
+            tm.top_tank_pressure = sensors->getOxTankTopPressure().pressure;
             tm.bottom_tank_pressure =
-                sensors->getBottomTankPressLastSample().pressure;
+                sensors->getOxTankBottomPressure().pressure;
             tm.combustion_chamber_pressure =
-                sensors->getCCPressLastSample().pressure;
-            tm.tank_temperature = sensors->getTankTempLastSample().temperature;
-            tm.battery_voltage =
-                sensors->getMotorBatteryVoltageLastSample().voltage;
+                sensors->getCombustionChamberPressure().pressure;
+            tm.tank_temperature = sensors->getOxTankTemperature().temperature;
+            tm.battery_voltage  = sensors->getMotorBatteryVoltage().voltage;
 
             // Valve states
             tm.main_valve_state =
@@ -708,12 +699,39 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             tm.channel_7 =
                 data.getVoltage(ADS131M08Defs::Channel::CHANNEL_7).voltage;
             tm.timestamp = data.timestamp;
-            strcpy(tm.sensor_name, "ADS131M08");
+            strcpy(tm.sensor_name, "ADS131M08_1");
 
             mavlink_msg_adc_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                       Config::Radio::MAV_COMPONENT_ID, &msg,
                                       &tm);
             enqueuePacket(msg);
+
+            data = getModule<Sensors>()->getADC2LastSample();
+
+            tm.channel_0 =
+                data.getVoltage(ADS131M08Defs::Channel::CHANNEL_0).voltage;
+            tm.channel_1 =
+                data.getVoltage(ADS131M08Defs::Channel::CHANNEL_1).voltage;
+            tm.channel_2 =
+                data.getVoltage(ADS131M08Defs::Channel::CHANNEL_2).voltage;
+            tm.channel_3 =
+                data.getVoltage(ADS131M08Defs::Channel::CHANNEL_3).voltage;
+            tm.channel_4 =
+                data.getVoltage(ADS131M08Defs::Channel::CHANNEL_4).voltage;
+            tm.channel_5 =
+                data.getVoltage(ADS131M08Defs::Channel::CHANNEL_5).voltage;
+            tm.channel_6 =
+                data.getVoltage(ADS131M08Defs::Channel::CHANNEL_6).voltage;
+            tm.channel_7 =
+                data.getVoltage(ADS131M08Defs::Channel::CHANNEL_7).voltage;
+            tm.timestamp = data.timestamp;
+            strcpy(tm.sensor_name, "ADS131M08_2");
+
+            mavlink_msg_adc_tm_encode(Config::Radio::MAV_SYSTEM_ID,
+                                      Config::Radio::MAV_COMPONENT_ID, &msg,
+                                      &tm);
+            enqueuePacket(msg);
+
             return true;
         }
 
@@ -722,8 +740,7 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             mavlink_message_t msg;
             mavlink_pressure_tm_t tm;
 
-            PressureData data =
-                getModule<Sensors>()->getVesselPressLastSample();
+            PressureData data = getModule<Sensors>()->getOxVesselPressure();
 
             tm.timestamp = data.pressureTimestamp;
             tm.pressure  = data.pressure;
@@ -741,8 +758,7 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             mavlink_message_t msg;
             mavlink_pressure_tm_t tm;
 
-            PressureData data =
-                getModule<Sensors>()->getFillingPressLastSample();
+            PressureData data = getModule<Sensors>()->getOxFillingPressure();
 
             tm.timestamp = data.pressureTimestamp;
             tm.pressure  = data.pressure;
@@ -760,8 +776,7 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             mavlink_message_t msg;
             mavlink_pressure_tm_t tm;
 
-            PressureData data =
-                getModule<Sensors>()->getBottomTankPressLastSample();
+            PressureData data = getModule<Sensors>()->getOxTankBottomPressure();
 
             tm.timestamp = data.pressureTimestamp;
             tm.pressure  = data.pressure;
@@ -779,8 +794,7 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             mavlink_message_t msg;
             mavlink_pressure_tm_t tm;
 
-            PressureData data =
-                getModule<Sensors>()->getTopTankPressLastSample();
+            PressureData data = getModule<Sensors>()->getOxTankTopPressure();
 
             tm.timestamp = data.pressureTimestamp;
             tm.pressure  = data.pressure;
@@ -816,8 +830,7 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             mavlink_message_t msg;
             mavlink_load_tm_t tm;
 
-            LoadCellData data =
-                getModule<Sensors>()->getVesselWeightLastSample();
+            LoadCellData data = getModule<Sensors>()->getOxVesselWeight();
 
             tm.timestamp = data.loadTimestamp;
             tm.load      = data.load;
@@ -835,7 +848,7 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             mavlink_message_t msg;
             mavlink_load_tm_t tm;
 
-            LoadCellData data = getModule<Sensors>()->getTankWeightLastSample();
+            LoadCellData data = getModule<Sensors>()->getOxTankWeight();
 
             tm.timestamp = data.loadTimestamp;
             tm.load      = data.load;
@@ -853,8 +866,7 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             mavlink_message_t msg;
             mavlink_voltage_tm_t tm;
 
-            VoltageData data =
-                getModule<Sensors>()->getBatteryVoltageLastSample();
+            VoltageData data = getModule<Sensors>()->getBatteryVoltage();
 
             tm.timestamp = data.voltageTimestamp;
             tm.voltage   = data.voltage;
diff --git a/src/RIGv2/Sensors/Sensors.cpp b/src/RIGv2/Sensors/Sensors.cpp
index cf83ecd54..a6f3aed84 100644
--- a/src/RIGv2/Sensors/Sensors.cpp
+++ b/src/RIGv2/Sensors/Sensors.cpp
@@ -1,5 +1,5 @@
 /* Copyright (c) 2024 Skyward Experimental Rocketry
- * Authors: Davide Mor
+ * Authors: Davide Mor, Niccolò Betto
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -40,12 +40,13 @@ bool Sensors::start()
     if (Config::Sensors::ADS131M08::ENABLED)
     {
         adc1Init();
-        vesselPressureInit();
-        fillingPressureInit();
-        topTankPressureInit();
-        bottomTankPressureInit();
-        vesselWeightInit();
-        tankWeightInit();
+        adc2Init();
+        oxVesselPressureInit();
+        oxFillingPressureInit();
+        oxTankTopPressureInit();
+        oxTankBottomPressureInit();
+        oxVesselWeightInit();
+        oxTankWeightInit();
     }
 
     if (Config::Sensors::MAX31856::ENABLED)
@@ -71,99 +72,123 @@ ADS131M08Data Sensors::getADC1LastSample()
     return adc1 ? adc1->getLastSample() : ADS131M08Data{};
 }
 
+ADS131M08Data Sensors::getADC2LastSample()
+{
+    return adc2 ? adc2->getLastSample() : ADS131M08Data{};
+}
+
 MAX31856Data Sensors::getTc1LastSample()
 {
     return tc1 ? tc1->getLastSample() : MAX31856Data{};
 }
 
-PressureData Sensors::getVesselPressLastSample()
+PressureData Sensors::getOxVesselPressure()
+{
+    return oxVesselPressure ? oxVesselPressure->getLastSample()
+                            : PressureData{};
+}
+
+PressureData Sensors::getOxFillingPressure()
 {
-    return vesselPressure ? vesselPressure->getLastSample() : PressureData{};
+    return oxFillingPressure ? oxFillingPressure->getLastSample()
+                             : PressureData{};
 }
 
-PressureData Sensors::getFillingPressLastSample()
+PressureData Sensors::getN2Vessel1Pressure()
 {
-    return fillingPressure ? fillingPressure->getLastSample() : PressureData{};
+    return n2Vessel1Pressure ? n2Vessel1Pressure->getLastSample()
+                             : PressureData{};
 }
 
-PressureData Sensors::getTopTankPressLastSample()
+PressureData Sensors::getN2Vessel2Pressure()
+{
+    return n2Vessel2Pressure ? n2Vessel2Pressure->getLastSample()
+                             : PressureData{};
+}
+
+PressureData Sensors::getN2FillingPressure()
+{
+    return n2FillingPressure ? n2FillingPressure->getLastSample()
+                             : PressureData{};
+}
+
+PressureData Sensors::getOxTankTopPressure()
 {
     if (useCanData)
     {
-        return getCanTopTankPressLastSample();
+        return getCanOxTankTopPressure();
     }
     else
     {
-        return topTankPressure ? topTankPressure->getLastSample()
-                               : PressureData{};
+        return oxTankTopPressure ? oxTankTopPressure->getLastSample()
+                                 : PressureData{};
     }
 }
 
-PressureData Sensors::getBottomTankPressLastSample()
+PressureData Sensors::getOxTankBottomPressure()
 {
     if (useCanData)
     {
-        return getCanBottomTankPressLastSample();
+        return getCanOxTankBottomPressure();
     }
     else
     {
-        return bottomTankPressure ? bottomTankPressure->getLastSample()
-                                  : PressureData{};
+        return oxTankBottomPressure ? oxTankBottomPressure->getLastSample()
+                                    : PressureData{};
     }
 }
 
-PressureData Sensors::getCCPressLastSample()
+PressureData Sensors::getCombustionChamberPressure()
 {
     if (useCanData)
-        return getCanCCPressLastSample();
+        return getCanCombustionChamberPressure();
     else
         return PressureData{};
 }
 
-TemperatureData Sensors::getTankTempLastSample()
+TemperatureData Sensors::getOxTankTemperature()
 {
     if (useCanData)
-        return getCanTankTempLastSample();
+        return getCanTankTemperature();
     else
         return getTc1LastSample();
 }
 
-LoadCellData Sensors::getVesselWeightLastSample()
+LoadCellData Sensors::getOxVesselWeight()
 {
-    if (vesselWeight)
-        return vesselWeight->getLastSample();
+    if (oxVesselWeight)
+        return oxVesselWeight->getLastSample();
     else
         return {};
 }
 
-LoadCellData Sensors::getTankWeightLastSample()
+LoadCellData Sensors::getOxTankWeight()
 {
-    if (tankWeight)
-        return tankWeight->getLastSample();
+    if (oxTankWeight)
+        return oxTankWeight->getLastSample();
     else
         return {};
 }
 
-CurrentData Sensors::getUmbilicalCurrentLastSample()
+CurrentData Sensors::getUmbilicalCurrent()
 {
-    // TODO: Implement this
+    // TODO: Implement umbilical current
     return {};
 }
 
-CurrentData Sensors::getServoCurrentLastSample()
+CurrentData Sensors::getServoCurrent()
 {
     auto sample = getADC1LastSample();
 
     float current =
-        (sample
-             .voltage[(int)Config::Sensors::ADS131M08::SERVO_CURRENT_CHANNEL] -
+        (sample.voltage[(int)Config::Sensors::ADC_1::SERVO_CURRENT_CHANNEL] -
          Config::Sensors::ADS131M08::SERVO_CURRENT_ZERO) *
         Config::Sensors::ADS131M08::SERVO_CURRENT_SCALE;
     // Current reading are flipped
     return {sample.timestamp, -current / 5.0f * 50.0f};
 }
 
-VoltageData Sensors::getBatteryVoltageLastSample()
+VoltageData Sensors::getBatteryVoltage()
 {
     auto sample = getInternalADCLastSample();
 
@@ -174,66 +199,66 @@ VoltageData Sensors::getBatteryVoltageLastSample()
     return {sample.timestamp, voltage};
 }
 
-VoltageData Sensors::getMotorBatteryVoltageLastSample()
+VoltageData Sensors::getMotorBatteryVoltage()
 {
     if (useCanData)
-        return getCanMotorBatteryVoltageLastSample();
+        return getCanMotorBatteryVoltage();
     else
         return VoltageData{};
 }
 
-PressureData Sensors::getCanTopTankPressLastSample()
+PressureData Sensors::getCanOxTankTopPressure()
 {
     Lock<FastMutex> lock{canMutex};
-    return canTopTankPressure;
+    return canOxTankBottomPressure;
 }
 
-PressureData Sensors::getCanBottomTankPressLastSample()
+PressureData Sensors::getCanOxTankBottomPressure()
 {
     Lock<FastMutex> lock{canMutex};
-    return canBottomTankPressure;
+    return canOxTankTopPressure;
 }
 
-PressureData Sensors::getCanCCPressLastSample()
+PressureData Sensors::getCanCombustionChamberPressure()
 {
     Lock<FastMutex> lock{canMutex};
-    return canCCPressure;
+    return canCombustionChamberPressure;
 }
 
-TemperatureData Sensors::getCanTankTempLastSample()
+TemperatureData Sensors::getCanTankTemperature()
 {
     Lock<FastMutex> lock{canMutex};
-    return canTankTemperature;
+    return canOxTankTemperature;
 }
 
-VoltageData Sensors::getCanMotorBatteryVoltageLastSample()
+VoltageData Sensors::getCanMotorBatteryVoltage()
 {
     Lock<FastMutex> lock{canMutex};
     return canMotorBatteryVoltage;
 }
 
-void Sensors::setCanTopTankPress(PressureData data)
+void Sensors::setCanOxTankTopPressure(PressureData data)
 {
     Lock<FastMutex> lock{canMutex};
-    canTopTankPressure = data;
+    canOxTankBottomPressure = data;
 }
 
-void Sensors::setCanBottomTankPress(PressureData data)
+void Sensors::setCanOxTankBottomPressure(PressureData data)
 {
     Lock<FastMutex> lock{canMutex};
-    canBottomTankPressure = data;
+    canOxTankTopPressure = data;
 }
 
-void Sensors::setCanCCPress(PressureData data)
+void Sensors::setCanCombustionChamberPressure(PressureData data)
 {
     Lock<FastMutex> lock{canMutex};
-    canCCPressure = data;
+    canCombustionChamberPressure = data;
 }
 
-void Sensors::setCanTankTemp(TemperatureData data)
+void Sensors::setCanOxTankTemperature(TemperatureData data)
 {
     Lock<FastMutex> lock{canMutex};
-    canTankTemperature = data;
+    canOxTankTemperature = data;
 }
 
 void Sensors::setCanMotorBatteryVoltage(VoltageData data)
@@ -246,20 +271,20 @@ void Sensors::switchToCanSensors() { useCanData = true; }
 
 void Sensors::calibrate()
 {
-    Stats vesselStats, tankStats;
+    Stats oxVesselStats, oxTankStats;
 
     for (unsigned int i = 0;
          i < Config::Sensors::LoadCell::CALIBRATE_SAMPLE_COUNT; i++)
     {
         // Tank readings WITHOUT offsets
-        vesselStats.add(vesselWeight->getLastSample().load);
-        tankStats.add(tankWeight->getLastSample().load);
+        oxVesselStats.add(oxVesselWeight->getLastSample().load);
+        oxTankStats.add(oxTankWeight->getLastSample().load);
 
         Thread::sleep(Config::Sensors::LoadCell::CALIBRATE_SAMPLE_PERIOD);
     }
 
-    vesselWeight->updateOffset(vesselStats.getStats().mean);
-    tankWeight->updateOffset(tankStats.getStats().mean);
+    oxVesselWeight->updateOffset(oxVesselStats.getStats().mean);
+    oxTankWeight->updateOffset(oxTankStats.getStats().mean);
 }
 
 std::vector<SensorInfo> Sensors::getSensorInfos()
@@ -268,32 +293,25 @@ std::vector<SensorInfo> Sensors::getSensorInfos()
     {
         std::vector<SensorInfo> infos{};
 
-        if (vesselWeight)
-            infos.push_back(manager->getSensorInfo(vesselWeight.get()));
-
-        if (tankWeight)
-            infos.push_back(manager->getSensorInfo(tankWeight.get()));
-
-        if (vesselPressure)
-            infos.push_back(manager->getSensorInfo(vesselPressure.get()));
-
-        if (fillingPressure)
-            infos.push_back(manager->getSensorInfo(fillingPressure.get()));
-
-        if (topTankPressure)
-            infos.push_back(manager->getSensorInfo(topTankPressure.get()));
-
-        if (bottomTankPressure)
-            infos.push_back(manager->getSensorInfo(bottomTankPressure.get()));
-
-        if (internalAdc)
-            infos.push_back(manager->getSensorInfo(internalAdc.get()));
-
-        if (adc1)
-            infos.push_back(manager->getSensorInfo(adc1.get()));
-
-        if (tc1)
-            infos.push_back(manager->getSensorInfo(tc1.get()));
+#define PUSH_SENSOR_INFO(instance, name)                         \
+    if (instance)                                                \
+        infos.push_back(manager->getSensorInfo(instance.get())); \
+    else                                                         \
+        infos.push_back(SensorInfo { #name, 0, nullptr, false })
+
+        PUSH_SENSOR_INFO(adc1, "ADC1");
+        PUSH_SENSOR_INFO(adc2, "ADC2");
+        PUSH_SENSOR_INFO(tc1, "TC1");
+        PUSH_SENSOR_INFO(internalAdc, "InternalADC");
+        PUSH_SENSOR_INFO(oxVesselPressure, "OxVesselPressure");
+        PUSH_SENSOR_INFO(oxFillingPressure, "OxFillingPressure");
+        PUSH_SENSOR_INFO(n2Vessel1Pressure, "N2Vessel1Pressure");
+        PUSH_SENSOR_INFO(n2Vessel2Pressure, "N2Vessel2Pressure");
+        PUSH_SENSOR_INFO(n2FillingPressure, "N2FillingPressure");
+        PUSH_SENSOR_INFO(oxTankTopPressure, "OxTankTopPressure");
+        PUSH_SENSOR_INFO(oxTankBottomPressure, "OxTankBotPressure");
+        PUSH_SENSOR_INFO(oxVesselWeight, "OxVesselWeight");
+        PUSH_SENSOR_INFO(oxTankWeight, "OxTankWeight");
 
         return infos;
     }
@@ -333,65 +351,101 @@ void Sensors::adc1Init()
         Config::Sensors::ADS131M08::GLOBAL_CHOP_MODE_EN;
 
     // Disable all channels
-    config.channelsConfig[0].enabled = false;
-    config.channelsConfig[1].enabled = false;
-    config.channelsConfig[2].enabled = false;
-    config.channelsConfig[3].enabled = false;
-    config.channelsConfig[4].enabled = false;
-    config.channelsConfig[5].enabled = false;
-    config.channelsConfig[6].enabled = false;
-    config.channelsConfig[7].enabled = false;
+    for (auto& channel : config.channelsConfig)
+        channel.enabled = false;
 
     // Configure all required channels
-    config.channelsConfig[(int)Config::Sensors::ADS131M08::VESSEL_PT_CHANNEL] =
+    config.channelsConfig[(int)Config::Sensors::ADC_1::OX_VESSEL_PT_CHANNEL] = {
+        .enabled = true,
+        .pga     = ADS131M08Defs::PGA::PGA_1,
+        .offset  = 0,
+        .gain    = 1.0};
+
+    config.channelsConfig[(int)Config::Sensors::ADC_1::OX_FILLING_PT_CHANNEL] =
+        {.enabled = true,
+         .pga     = ADS131M08Defs::PGA::PGA_1,
+         .offset  = 0,
+         .gain    = 1.0};
+
+    config.channelsConfig[(int)Config::Sensors::ADC_1::N2_VESSEL_1_PT_CHANNEL] =
         {.enabled = true,
          .pga     = ADS131M08Defs::PGA::PGA_1,
          .offset  = 0,
          .gain    = 1.0};
 
-    config.channelsConfig[(int)Config::Sensors::ADS131M08::FILLING_PT_CHANNEL] =
+    config.channelsConfig[(int)Config::Sensors::ADC_1::N2_VESSEL_2_PT_CHANNEL] =
         {.enabled = true,
          .pga     = ADS131M08Defs::PGA::PGA_1,
          .offset  = 0,
          .gain    = 1.0};
 
-    config.channelsConfig[(int)Config::Sensors::ADS131M08::BOTTOM_PT_CHANNEL] =
+    config.channelsConfig[(int)Config::Sensors::ADC_1::SERVO_CURRENT_CHANNEL] =
         {.enabled = true,
          .pga     = ADS131M08Defs::PGA::PGA_1,
          .offset  = 0,
          .gain    = 1.0};
 
-    config.channelsConfig[(int)Config::Sensors::ADS131M08::TOP_PT_CHANNEL] = {
+    config.channelsConfig[(int)Config::Sensors::ADC_1::OX_VESSEL_LC_CHANNEL] = {
         .enabled = true,
-        .pga     = ADS131M08Defs::PGA::PGA_1,
+        .pga     = ADS131M08Defs::PGA::PGA_32,
         .offset  = 0,
         .gain    = 1.0};
 
-    config.channelsConfig[(
-        int)Config::Sensors::ADS131M08::SERVO_CURRENT_CHANNEL] = {
+    config.channelsConfig[(int)Config::Sensors::ADC_1::OX_TANK_LC_CHANNEL] = {
         .enabled = true,
-        .pga     = ADS131M08Defs::PGA::PGA_1,
+        .pga     = ADS131M08Defs::PGA::PGA_32,
         .offset  = 0,
         .gain    = 1.0};
 
-    config.channelsConfig[(int)Config::Sensors::ADS131M08::VESSEL_LC_CHANNEL] =
+    config.channelsConfig[(int)Config::Sensors::ADC_1::N2_FILLING_PT_CHANNEL] =
         {.enabled = true,
-         .pga     = ADS131M08Defs::PGA::PGA_32,
+         .pga     = ADS131M08Defs::PGA::PGA_1,
          .offset  = 0,
          .gain    = 1.0};
 
-    config.channelsConfig[(int)Config::Sensors::ADS131M08::TANK_LC_CHANNEL] = {
+    adc1 = std::make_unique<ADS131M08>(getModule<Buses>()->getADS131M08_1(),
+                                       sensors::ADS131_1::cs::getPin(),
+                                       spiConfig, config);
+}
+
+void Sensors::adc1Callback() { sdLogger.log(ADC1Data{getADC1LastSample()}); }
+
+void Sensors::adc2Init()
+{
+    SPIBusConfig spiConfig = {};
+    spiConfig.mode         = SPI::Mode::MODE_0;
+    spiConfig.clockDivider = SPI::ClockDivider::DIV_32;
+
+    ADS131M08::Config config = {};
+    // Setup global configurations
+    config.oversamplingRatio = Config::Sensors::ADS131M08::OSR;
+    config.globalChopModeEnabled =
+        Config::Sensors::ADS131M08::GLOBAL_CHOP_MODE_EN;
+
+    // Disable all channels
+    for (auto& channel : config.channelsConfig)
+        channel.enabled = false;
+
+    // Configure all required channels
+    config.channelsConfig[(int)Config::Sensors::ADC_2::OX_TANK_TOP_PT_CHANNEL] =
+        {.enabled = true,
+         .pga     = ADS131M08Defs::PGA::PGA_1,
+         .offset  = 0,
+         .gain    = 1.0};
+
+    config.channelsConfig[(
+        int)Config::Sensors::ADC_2::OX_TANK_BOTTOM_PT_CHANNEL] = {
         .enabled = true,
-        .pga     = ADS131M08Defs::PGA::PGA_32,
+        .pga     = ADS131M08Defs::PGA::PGA_1,
         .offset  = 0,
         .gain    = 1.0};
 
-    adc1 = std::make_unique<ADS131M08>(getModule<Buses>()->getADS131M08_1(),
-                                       sensors::ADS131_1::cs::getPin(),
+    adc2 = std::make_unique<ADS131M08>(getModule<Buses>()->getADS131M08_2(),
+                                       sensors::ADS131_2::cs::getPin(),
                                        spiConfig, config);
 }
 
-void Sensors::adc1Callback() { sdLogger.log(ADC1Data{getADC1LastSample()}); }
+void Sensors::adc2Callback() { sdLogger.log(ADC2Data{getADC2LastSample()}); }
 
 void Sensors::tc1Init()
 {
@@ -405,94 +459,155 @@ void Sensors::tc1Init()
 
 void Sensors::tc1Callback() { sdLogger.log(TC1Data{getTc1LastSample()}); }
 
-void Sensors::vesselPressureInit()
+void Sensors::oxVesselPressureInit()
 {
-    vesselPressure = std::make_unique<TrafagPressureSensor>(
+    oxVesselPressure = std::make_unique<TrafagPressureSensor>(
         [this]()
         {
             auto sample = getADC1LastSample();
             return sample.getVoltage(
-                Config::Sensors::ADS131M08::VESSEL_PT_CHANNEL);
+                Config::Sensors::ADC_1::OX_VESSEL_PT_CHANNEL);
         },
-        Config::Sensors::Trafag::VESSEL_SHUNT_RESISTANCE,
-        Config::Sensors::Trafag::VESSEL_MAX_PRESSURE,
+        Config::Sensors::Trafag::OX_VESSEL_SHUNT_RESISTANCE,
+        Config::Sensors::Trafag::OX_VESSEL_MAX_PRESSURE,
         Config::Sensors::Trafag::MIN_CURRENT,
         Config::Sensors::Trafag::MAX_CURRENT);
 }
 
-void Sensors::vesselPressureCallback()
+void Sensors::oxVesselPressureCallback()
 {
-    sdLogger.log(VesselPressureData{getVesselPressLastSample()});
+    sdLogger.log(OxVesselPressureData{getOxVesselPressure()});
 }
 
-void Sensors::fillingPressureInit()
+void Sensors::oxFillingPressureInit()
 {
-    fillingPressure = std::make_unique<TrafagPressureSensor>(
+    oxFillingPressure = std::make_unique<TrafagPressureSensor>(
         [this]()
         {
             auto sample = getADC1LastSample();
             return sample.getVoltage(
-                Config::Sensors::ADS131M08::FILLING_PT_CHANNEL);
+                Config::Sensors::ADC_1::OX_FILLING_PT_CHANNEL);
         },
-        Config::Sensors::Trafag::FILLING_SHUNT_RESISTANCE,
-        Config::Sensors::Trafag::FILLING_MAX_PRESSURE,
+        Config::Sensors::Trafag::OX_FILLING_SHUNT_RESISTANCE,
+        Config::Sensors::Trafag::OX_FILLING_MAX_PRESSURE,
         Config::Sensors::Trafag::MIN_CURRENT,
         Config::Sensors::Trafag::MAX_CURRENT);
 }
 
-void Sensors::fillingPressureCallback()
+void Sensors::oxFillingPressureCallback()
 {
-    sdLogger.log(FillingPressureData{getFillingPressLastSample()});
+    sdLogger.log(OxFillingPressureData{getOxFillingPressure()});
 }
 
-void Sensors::topTankPressureInit()
+void Sensors::n2Vessel1PressureInit()
 {
-    topTankPressure = std::make_unique<TrafagPressureSensor>(
+    n2Vessel1Pressure = std::make_unique<TrafagPressureSensor>(
         [this]()
         {
             auto sample = getADC1LastSample();
             return sample.getVoltage(
-                Config::Sensors::ADS131M08::TOP_PT_CHANNEL);
+                Config::Sensors::ADC_1::N2_VESSEL_1_PT_CHANNEL);
         },
-        Config::Sensors::Trafag::TANK_TOP_SHUNT_RESISTANCE,
-        Config::Sensors::Trafag::TANK_TOP_MAX_PRESSURE,
+        Config::Sensors::Trafag::N2_VESSEL1_SHUNT_RESISTANCE,
+        Config::Sensors::Trafag::N2_VESSEL1_MAX_PRESSURE,
         Config::Sensors::Trafag::MIN_CURRENT,
         Config::Sensors::Trafag::MAX_CURRENT);
 }
 
-void Sensors::topTankPressureCallback()
+void Sensors::n2Vessel1PressureCallback()
 {
-    sdLogger.log(TopTankPressureData{topTankPressure->getLastSample()});
+    sdLogger.log(N2Vessel1PressureData{getN2Vessel1Pressure()});
 }
 
-void Sensors::bottomTankPressureInit()
+void Sensors::n2Vessel2PressureInit()
 {
-    bottomTankPressure = std::make_unique<TrafagPressureSensor>(
+    n2Vessel2Pressure = std::make_unique<TrafagPressureSensor>(
         [this]()
         {
             auto sample = getADC1LastSample();
             return sample.getVoltage(
-                Config::Sensors::ADS131M08::BOTTOM_PT_CHANNEL);
+                Config::Sensors::ADC_1::N2_VESSEL_2_PT_CHANNEL);
+        },
+        Config::Sensors::Trafag::N2_VESSEL2_SHUNT_RESISTANCE,
+        Config::Sensors::Trafag::N2_VESSEL2_MAX_PRESSURE,
+        Config::Sensors::Trafag::MIN_CURRENT,
+        Config::Sensors::Trafag::MAX_CURRENT);
+}
+
+void Sensors::n2Vessel2PressureCallback()
+{
+    sdLogger.log(N2Vessel2PressureData{getN2Vessel2Pressure()});
+}
+
+void Sensors::n2FillingPressureInit()
+{
+    n2FillingPressure = std::make_unique<TrafagPressureSensor>(
+        [this]()
+        {
+            auto sample = getADC1LastSample();
+            return sample.getVoltage(
+                Config::Sensors::ADC_1::N2_FILLING_PT_CHANNEL);
+        },
+        Config::Sensors::Trafag::N2_FILLING_SHUNT_RESISTANCE,
+        Config::Sensors::Trafag::N2_FILLING_MAX_PRESSURE,
+        Config::Sensors::Trafag::MIN_CURRENT,
+        Config::Sensors::Trafag::MAX_CURRENT);
+}
+
+void Sensors::n2FillingPressureCallback()
+{
+    sdLogger.log(N2FillingPressureData{getN2FillingPressure()});
+}
+
+void Sensors::oxTankTopPressureInit()
+{
+    oxTankTopPressure = std::make_unique<TrafagPressureSensor>(
+        [this]()
+        {
+            auto sample = getADC2LastSample();
+            return sample.getVoltage(
+                Config::Sensors::ADC_2::OX_TANK_TOP_PT_CHANNEL);
         },
-        Config::Sensors::Trafag::TANK_BOTTOM_SHUNT_RESISTANCE,
-        Config::Sensors::Trafag::TANK_BOTTOM_MAX_PRESSURE,
+        Config::Sensors::Trafag::OX_TANK_TOP_SHUNT_RESISTANCE,
+        Config::Sensors::Trafag::OX_TANK_TOP_MAX_PRESSURE,
         Config::Sensors::Trafag::MIN_CURRENT,
         Config::Sensors::Trafag::MAX_CURRENT);
 }
 
-void Sensors::bottomTankPressureCallback()
+void Sensors::oxTankTopPressureCallback()
 {
-    sdLogger.log(BottomTankPressureData{bottomTankPressure->getLastSample()});
+    sdLogger.log(OxTankTopPressureData{oxTankTopPressure->getLastSample()});
 }
 
-void Sensors::vesselWeightInit()
+void Sensors::oxTankBottomPressureInit()
 {
-    vesselWeight = std::make_unique<TwoPointAnalogLoadCell>(
+    oxTankBottomPressure = std::make_unique<TrafagPressureSensor>(
+        [this]()
+        {
+            auto sample = getADC2LastSample();
+            return sample.getVoltage(
+                Config::Sensors::ADC_2::OX_TANK_BOTTOM_PT_CHANNEL);
+        },
+        Config::Sensors::Trafag::OX_TANK_BOTTOM_SHUNT_RESISTANCE,
+        Config::Sensors::Trafag::OX_TANK_BOTTOM_MAX_PRESSURE,
+        Config::Sensors::Trafag::MIN_CURRENT,
+        Config::Sensors::Trafag::MAX_CURRENT);
+}
+
+void Sensors::oxTankBottomPressureCallback()
+{
+    sdLogger.log(
+        OxTankBottomPressureData{oxTankBottomPressure->getLastSample()});
+}
+
+void Sensors::oxVesselWeightInit()
+{
+    oxVesselWeight = std::make_unique<TwoPointAnalogLoadCell>(
         [this]()
         {
             auto sample = getADC1LastSample();
             return sample.getVoltage(
-                Config::Sensors::ADS131M08::VESSEL_LC_CHANNEL);
+                Config::Sensors::ADC_1::OX_VESSEL_LC_CHANNEL);
         },
         Config::Sensors::LoadCell::VESSEL_P0_VOLTAGE,
         Config::Sensors::LoadCell::VESSEL_P0_MASS,
@@ -500,19 +615,19 @@ void Sensors::vesselWeightInit()
         Config::Sensors::LoadCell::VESSEL_P1_MASS);
 }
 
-void Sensors::vesselWeightCallback()
+void Sensors::oxVesselWeightCallback()
 {
-    sdLogger.log(VesselWeightData{getVesselWeightLastSample()});
+    sdLogger.log(OxVesselWeightData{getOxVesselWeight()});
 }
 
-void Sensors::tankWeightInit()
+void Sensors::oxTankWeightInit()
 {
-    tankWeight = std::make_unique<TwoPointAnalogLoadCell>(
+    oxTankWeight = std::make_unique<TwoPointAnalogLoadCell>(
         [this]()
         {
             auto sample = getADC1LastSample();
             return sample.getVoltage(
-                Config::Sensors::ADS131M08::TANK_LC_CHANNEL);
+                Config::Sensors::ADC_1::OX_TANK_LC_CHANNEL);
         },
         Config::Sensors::LoadCell::TANK_P0_VOLTAGE,
         Config::Sensors::LoadCell::TANK_P0_MASS,
@@ -520,9 +635,9 @@ void Sensors::tankWeightInit()
         Config::Sensors::LoadCell::TANK_P1_MASS);
 }
 
-void Sensors::tankWeightCallback()
+void Sensors::oxTankWeightCallback()
 {
-    sdLogger.log(TankWeightData{getTankWeightLastSample()});
+    sdLogger.log(OxTankWeightData{getOxTankWeight()});
 }
 
 bool Sensors::sensorManagerInit()
@@ -534,7 +649,7 @@ bool Sensors::sensorManagerInit()
 
     if (internalAdc)
     {
-        SensorInfo info("InternalAdc", Config::Sensors::InternalADC::PERIOD,
+        SensorInfo info("InternalADC", Config::Sensors::InternalADC::PERIOD,
                         [this]() { internalAdcCallback(); });
         map.emplace(internalAdc.get(), info);
     }
@@ -546,6 +661,13 @@ bool Sensors::sensorManagerInit()
         map.emplace(std::make_pair(adc1.get(), info));
     }
 
+    if (adc2)
+    {
+        SensorInfo info("ADS131M08_2", Config::Sensors::ADS131M08::PERIOD,
+                        [this]() { adc2Callback(); });
+        map.emplace(std::make_pair(adc2.get(), info));
+    }
+
     if (tc1)
     {
         SensorInfo info("MAX31856_1", Config::Sensors::MAX31856::PERIOD,
@@ -553,47 +675,67 @@ bool Sensors::sensorManagerInit()
         map.emplace(std::make_pair(tc1.get(), info));
     }
 
-    if (vesselPressure)
+    if (oxVesselPressure)
+    {
+        SensorInfo info("OxVesselPressure", Config::Sensors::ADS131M08::PERIOD,
+                        [this]() { oxVesselPressureCallback(); });
+        map.emplace(std::make_pair(oxVesselPressure.get(), info));
+    }
+
+    if (oxFillingPressure)
+    {
+        SensorInfo info("OxFillingPressure", Config::Sensors::ADS131M08::PERIOD,
+                        [this]() { oxFillingPressureCallback(); });
+        map.emplace(std::make_pair(oxFillingPressure.get(), info));
+    }
+
+    if (n2Vessel1Pressure)
+    {
+        SensorInfo info("N2Vessel1Pressure", Config::Sensors::ADS131M08::PERIOD,
+                        [this]() { n2Vessel1PressureCallback(); });
+        map.emplace(std::make_pair(n2Vessel1Pressure.get(), info));
+    }
+
+    if (n2Vessel2Pressure)
     {
-        SensorInfo info("VesselPressure", Config::Sensors::ADS131M08::PERIOD,
-                        [this]() { vesselPressureCallback(); });
-        map.emplace(std::make_pair(vesselPressure.get(), info));
+        SensorInfo info("N2Vessel2Pressure", Config::Sensors::ADS131M08::PERIOD,
+                        [this]() { n2Vessel2PressureCallback(); });
+        map.emplace(std::make_pair(n2Vessel2Pressure.get(), info));
     }
 
-    if (fillingPressure)
+    if (n2FillingPressure)
     {
-        SensorInfo info("FillingPressure", Config::Sensors::ADS131M08::PERIOD,
-                        [this]() { fillingPressureCallback(); });
-        map.emplace(std::make_pair(fillingPressure.get(), info));
+        SensorInfo info("N2FillingPressure", Config::Sensors::ADS131M08::PERIOD,
+                        [this]() { n2FillingPressureCallback(); });
+        map.emplace(std::make_pair(n2FillingPressure.get(), info));
     }
 
-    if (topTankPressure)
+    if (oxTankTopPressure)
     {
-        SensorInfo info("TopTankPressure", Config::Sensors::ADS131M08::PERIOD,
-                        [this]() { topTankPressureCallback(); });
-        map.emplace(std::make_pair(topTankPressure.get(), info));
+        SensorInfo info("OxTankTopPressure", Config::Sensors::ADS131M08::PERIOD,
+                        [this]() { oxTankTopPressureCallback(); });
+        map.emplace(std::make_pair(oxTankTopPressure.get(), info));
     }
 
-    if (bottomTankPressure)
+    if (oxTankBottomPressure)
     {
-        SensorInfo info("BottomTankPressure",
-                        Config::Sensors::ADS131M08::PERIOD,
-                        [this]() { bottomTankPressureCallback(); });
-        map.emplace(std::make_pair(bottomTankPressure.get(), info));
+        SensorInfo info("OxTankBotPressure", Config::Sensors::ADS131M08::PERIOD,
+                        [this]() { oxTankBottomPressureCallback(); });
+        map.emplace(std::make_pair(oxTankBottomPressure.get(), info));
     }
 
-    if (vesselWeight)
+    if (oxVesselWeight)
     {
-        SensorInfo info("VesselWeight", Config::Sensors::ADS131M08::PERIOD,
-                        [this]() { vesselWeightCallback(); });
-        map.emplace(std::make_pair(vesselWeight.get(), info));
+        SensorInfo info("OxVesselWeight", Config::Sensors::ADS131M08::PERIOD,
+                        [this]() { oxVesselWeightCallback(); });
+        map.emplace(std::make_pair(oxVesselWeight.get(), info));
     }
 
-    if (tankWeight)
+    if (oxTankWeight)
     {
-        SensorInfo info("TankWeight", Config::Sensors::ADS131M08::PERIOD,
-                        [this]() { tankWeightCallback(); });
-        map.emplace(std::make_pair(tankWeight.get(), info));
+        SensorInfo info("OxTankWeight", Config::Sensors::ADS131M08::PERIOD,
+                        [this]() { oxTankWeightCallback(); });
+        map.emplace(std::make_pair(oxTankWeight.get(), info));
     }
 
     manager = std::make_unique<SensorManager>(map, &scheduler);
diff --git a/src/RIGv2/Sensors/Sensors.h b/src/RIGv2/Sensors/Sensors.h
index c349b48b9..06a5ceb1f 100644
--- a/src/RIGv2/Sensors/Sensors.h
+++ b/src/RIGv2/Sensors/Sensors.h
@@ -1,5 +1,5 @@
 /* Copyright (c) 2024 Skyward Experimental Rocketry
- * Authors: Davide Mor
+ * Authors: Davide Mor, Niccolò Betto
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -55,55 +55,70 @@ public:
     // Getters for raw data coming from sensors
     Boardcore::InternalADCData getInternalADCLastSample();
     Boardcore::ADS131M08Data getADC1LastSample();
+    Boardcore::ADS131M08Data getADC2LastSample();
     Boardcore::MAX31856Data getTc1LastSample();
 
     // Getters for processed data
-    Boardcore::PressureData getVesselPressLastSample();
-    Boardcore::PressureData getFillingPressLastSample();
-    Boardcore::PressureData getTopTankPressLastSample();
-    Boardcore::PressureData getBottomTankPressLastSample();
-    Boardcore::PressureData getCCPressLastSample();
-    Boardcore::TemperatureData getTankTempLastSample();
-    Boardcore::LoadCellData getVesselWeightLastSample();
-    Boardcore::LoadCellData getTankWeightLastSample();
-    Boardcore::CurrentData getUmbilicalCurrentLastSample();
-    Boardcore::CurrentData getServoCurrentLastSample();
-    Boardcore::VoltageData getBatteryVoltageLastSample();
-    Boardcore::VoltageData getMotorBatteryVoltageLastSample();
-
-    Boardcore::PressureData getCanTopTankPressLastSample();
-    Boardcore::PressureData getCanBottomTankPressLastSample();
-    Boardcore::PressureData getCanCCPressLastSample();
-    Boardcore::TemperatureData getCanTankTempLastSample();
-    Boardcore::VoltageData getCanMotorBatteryVoltageLastSample();
+    Boardcore::PressureData getOxVesselPressure();
+    Boardcore::PressureData getOxFillingPressure();
+    Boardcore::PressureData getN2Vessel1Pressure();
+    Boardcore::PressureData getN2Vessel2Pressure();
+    Boardcore::PressureData getN2FillingPressure();
+    Boardcore::PressureData getOxTankTopPressure();
+    Boardcore::PressureData getOxTankBottomPressure();
+    Boardcore::PressureData getCombustionChamberPressure();
+
+    Boardcore::TemperatureData getOxTankTemperature();
+    Boardcore::LoadCellData getOxVesselWeight();
+    Boardcore::LoadCellData getOxTankWeight();
+
+    Boardcore::CurrentData getUmbilicalCurrent();
+    Boardcore::CurrentData getServoCurrent();
+    Boardcore::VoltageData getBatteryVoltage();
+    Boardcore::VoltageData getMotorBatteryVoltage();
+
+    Boardcore::PressureData getCanOxTankTopPressure();
+    Boardcore::PressureData getCanOxTankBottomPressure();
+    Boardcore::PressureData getCanCombustionChamberPressure();
+    Boardcore::TemperatureData getCanTankTemperature();
+    Boardcore::VoltageData getCanMotorBatteryVoltage();
 
     std::vector<Boardcore::SensorInfo> getSensorInfos();
 
-    void setCanTopTankPress(Boardcore::PressureData data);
-    void setCanBottomTankPress(Boardcore::PressureData data);
-    void setCanCCPress(Boardcore::PressureData data);
-    void setCanTankTemp(Boardcore::TemperatureData data);
+    void setCanOxTankTopPressure(Boardcore::PressureData data);
+    void setCanOxTankBottomPressure(Boardcore::PressureData data);
+    void setCanCombustionChamberPressure(Boardcore::PressureData data);
+    void setCanOxTankTemperature(Boardcore::TemperatureData data);
     void setCanMotorBatteryVoltage(Boardcore::VoltageData data);
     void switchToCanSensors();
 
 private:
-    void vesselPressureInit();
-    void vesselPressureCallback();
+    void oxVesselPressureInit();
+    void oxVesselPressureCallback();
 
-    void fillingPressureInit();
-    void fillingPressureCallback();
+    void oxFillingPressureInit();
+    void oxFillingPressureCallback();
 
-    void topTankPressureInit();
-    void topTankPressureCallback();
+    void n2Vessel1PressureInit();
+    void n2Vessel1PressureCallback();
 
-    void bottomTankPressureInit();
-    void bottomTankPressureCallback();
+    void n2Vessel2PressureInit();
+    void n2Vessel2PressureCallback();
 
-    void vesselWeightInit();
-    void vesselWeightCallback();
+    void n2FillingPressureInit();
+    void n2FillingPressureCallback();
 
-    void tankWeightInit();
-    void tankWeightCallback();
+    void oxTankTopPressureInit();
+    void oxTankTopPressureCallback();
+
+    void oxTankBottomPressureInit();
+    void oxTankBottomPressureCallback();
+
+    void oxVesselWeightInit();
+    void oxVesselWeightCallback();
+
+    void oxTankWeightInit();
+    void oxTankWeightCallback();
 
     void internalAdcInit();
     void internalAdcCallback();
@@ -111,6 +126,9 @@ private:
     void adc1Init();
     void adc1Callback();
 
+    void adc2Init();
+    void adc2Callback();
+
     void tc1Init();
     void tc1Callback();
 
@@ -123,22 +141,28 @@ private:
 
     std::atomic<bool> useCanData{false};
     miosix::FastMutex canMutex;
-    Boardcore::PressureData canCCPressure;
-    Boardcore::PressureData canBottomTankPressure;
-    Boardcore::PressureData canTopTankPressure;
-    Boardcore::TemperatureData canTankTemperature;
+
+    Boardcore::PressureData canOxTankTopPressure;
+    Boardcore::PressureData canOxTankBottomPressure;
+    Boardcore::PressureData canCombustionChamberPressure;
+    // TODO: N2 tank pressure from CAN
+    Boardcore::TemperatureData canOxTankTemperature;
     Boardcore::VoltageData canMotorBatteryVoltage;
 
     // Analog sensors
-    std::unique_ptr<Boardcore::TrafagPressureSensor> vesselPressure;
-    std::unique_ptr<Boardcore::TrafagPressureSensor> fillingPressure;
-    std::unique_ptr<Boardcore::TrafagPressureSensor> topTankPressure;
-    std::unique_ptr<Boardcore::TrafagPressureSensor> bottomTankPressure;
-    std::unique_ptr<Boardcore::TwoPointAnalogLoadCell> vesselWeight;
-    std::unique_ptr<Boardcore::TwoPointAnalogLoadCell> tankWeight;
+    std::unique_ptr<Boardcore::TrafagPressureSensor> oxVesselPressure;
+    std::unique_ptr<Boardcore::TrafagPressureSensor> oxFillingPressure;
+    std::unique_ptr<Boardcore::TrafagPressureSensor> n2Vessel1Pressure;
+    std::unique_ptr<Boardcore::TrafagPressureSensor> n2Vessel2Pressure;
+    std::unique_ptr<Boardcore::TrafagPressureSensor> n2FillingPressure;
+    std::unique_ptr<Boardcore::TrafagPressureSensor> oxTankTopPressure;
+    std::unique_ptr<Boardcore::TrafagPressureSensor> oxTankBottomPressure;
+    std::unique_ptr<Boardcore::TwoPointAnalogLoadCell> oxVesselWeight;
+    std::unique_ptr<Boardcore::TwoPointAnalogLoadCell> oxTankWeight;
 
     // Digital sensors
     std::unique_ptr<Boardcore::ADS131M08> adc1;
+    std::unique_ptr<Boardcore::ADS131M08> adc2;
     std::unique_ptr<Boardcore::MAX31856> tc1;
     std::unique_ptr<Boardcore::InternalADC> internalAdc;
     std::unique_ptr<Boardcore::SensorManager> manager;
diff --git a/src/RIGv2/Sensors/SensorsData.h b/src/RIGv2/Sensors/SensorsData.h
index 5f418da1e..c598c0a2a 100644
--- a/src/RIGv2/Sensors/SensorsData.h
+++ b/src/RIGv2/Sensors/SensorsData.h
@@ -1,5 +1,5 @@
 /* Copyright (c) 2024 Skyward Experimental Rocketry
- * Authors: Davide Mor
+ * Authors: Davide Mor, Niccolò Betto
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -39,6 +39,16 @@ struct ADC1Data : Boardcore::ADS131M08Data
     ADC1Data() {}
 };
 
+struct ADC2Data : Boardcore::ADS131M08Data
+{
+    explicit ADC2Data(const Boardcore::ADS131M08Data& data)
+        : Boardcore::ADS131M08Data(data)
+    {
+    }
+
+    ADC2Data() {}
+};
+
 struct TC1Data : Boardcore::MAX31856Data
 {
     explicit TC1Data(const Boardcore::MAX31856Data& data)
@@ -49,64 +59,94 @@ struct TC1Data : Boardcore::MAX31856Data
     TC1Data() {}
 };
 
-struct VesselWeightData : Boardcore::LoadCellData
+struct OxVesselWeightData : Boardcore::LoadCellData
 {
-    explicit VesselWeightData(const Boardcore::LoadCellData& data)
+    explicit OxVesselWeightData(const Boardcore::LoadCellData& data)
         : Boardcore::LoadCellData(data)
     {
     }
 
-    VesselWeightData() {}
+    OxVesselWeightData() {}
 };
 
-struct TankWeightData : Boardcore::LoadCellData
+struct OxTankWeightData : Boardcore::LoadCellData
 {
-    explicit TankWeightData(const Boardcore::LoadCellData& data)
+    explicit OxTankWeightData(const Boardcore::LoadCellData& data)
         : Boardcore::LoadCellData(data)
     {
     }
 
-    TankWeightData() {}
+    OxTankWeightData() {}
+};
+
+struct OxVesselPressureData : Boardcore::PressureData
+{
+    explicit OxVesselPressureData(const Boardcore::PressureData& data)
+        : Boardcore::PressureData(data)
+    {
+    }
+
+    OxVesselPressureData() {}
+};
+
+struct OxFillingPressureData : Boardcore::PressureData
+{
+    explicit OxFillingPressureData(const Boardcore::PressureData& data)
+        : Boardcore::PressureData(data)
+    {
+    }
+
+    OxFillingPressureData() {}
+};
+
+struct N2Vessel1PressureData : Boardcore::PressureData
+{
+    explicit N2Vessel1PressureData(const Boardcore::PressureData& data)
+        : Boardcore::PressureData(data)
+    {
+    }
+
+    N2Vessel1PressureData() {}
 };
 
-struct VesselPressureData : Boardcore::PressureData
+struct N2Vessel2PressureData : Boardcore::PressureData
 {
-    explicit VesselPressureData(const Boardcore::PressureData& data)
+    explicit N2Vessel2PressureData(const Boardcore::PressureData& data)
         : Boardcore::PressureData(data)
     {
     }
 
-    VesselPressureData() {}
+    N2Vessel2PressureData() {}
 };
 
-struct FillingPressureData : Boardcore::PressureData
+struct N2FillingPressureData : Boardcore::PressureData
 {
-    explicit FillingPressureData(const Boardcore::PressureData& data)
+    explicit N2FillingPressureData(const Boardcore::PressureData& data)
         : Boardcore::PressureData(data)
     {
     }
 
-    FillingPressureData() {}
+    N2FillingPressureData() {}
 };
 
-struct TopTankPressureData : Boardcore::PressureData
+struct OxTankTopPressureData : Boardcore::PressureData
 {
-    explicit TopTankPressureData(const Boardcore::PressureData& data)
+    explicit OxTankTopPressureData(const Boardcore::PressureData& data)
         : Boardcore::PressureData(data)
     {
     }
 
-    TopTankPressureData() {}
+    OxTankTopPressureData() {}
 };
 
-struct BottomTankPressureData : Boardcore::PressureData
+struct OxTankBottomPressureData : Boardcore::PressureData
 {
-    explicit BottomTankPressureData(const Boardcore::PressureData& data)
+    explicit OxTankBottomPressureData(const Boardcore::PressureData& data)
         : Boardcore::PressureData(data)
     {
     }
 
-    BottomTankPressureData() {}
+    OxTankBottomPressureData() {}
 };
 
 }  // namespace RIGv2
diff --git a/src/RIGv2/StateMachines/TARS1/TARS1.cpp b/src/RIGv2/StateMachines/TARS1/TARS1.cpp
index 50a1f90d7..b6806abf3 100644
--- a/src/RIGv2/StateMachines/TARS1/TARS1.cpp
+++ b/src/RIGv2/StateMachines/TARS1/TARS1.cpp
@@ -257,8 +257,8 @@ void TARS1::sample()
 {
     Sensors* sensors = getModule<Sensors>();
 
-    pressureFilter.add(sensors->getBottomTankPressLastSample().pressure);
-    massFilter.add(sensors->getTankWeightLastSample().load);
+    pressureFilter.add(sensors->getOxTankBottomPressure().pressure);
+    massFilter.add(sensors->getOxTankWeight().load);
     medianSamples++;
 
     if (medianSamples == Config::TARS1::MEDIAN_SAMPLE_NUMBER)
diff --git a/src/RIGv2/rig-v2-entry.cpp b/src/RIGv2/rig-v2-entry.cpp
index ebc617446..b8ec84e95 100644
--- a/src/RIGv2/rig-v2-entry.cpp
+++ b/src/RIGv2/rig-v2-entry.cpp
@@ -208,8 +208,12 @@ int main()
     std::cout << "Sensor status:" << std::endl;
     for (auto info : sensors->getSensorInfos())
     {
+        auto statusStr = !info.isEnabled      ? "Disabled"
+                         : info.isInitialized ? "Ok"
+                                              : "Error";
+
         std::cout << "\t" << std::setw(16) << std::left << info.id << " "
-                  << (info.isInitialized ? "Ok" : "Error") << std::endl;
+                  << statusStr << std::endl;
     }
 
     // Periodic statistics
-- 
GitLab


From 26530f9dee82c791510f4a6f2313deeccc0bbf9b Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu>
Date: Thu, 6 Mar 2025 13:28:08 +0100
Subject: [PATCH 14/14] [RIGv2] Improve documentation of actuators
 initialization macros

---
 src/RIGv2/Actuators/Actuators.cpp     |  74 +--------------
 src/RIGv2/Actuators/ActuatorsMacros.h | 128 ++++++++++++++++++++++++++
 2 files changed, 130 insertions(+), 72 deletions(-)
 create mode 100644 src/RIGv2/Actuators/ActuatorsMacros.h

diff --git a/src/RIGv2/Actuators/Actuators.cpp b/src/RIGv2/Actuators/Actuators.cpp
index 0b6de233d..412562582 100644
--- a/src/RIGv2/Actuators/Actuators.cpp
+++ b/src/RIGv2/Actuators/Actuators.cpp
@@ -29,6 +29,8 @@
 #include <events/EventBroker.h>
 #include <interfaces-impl/hwmapping.h>
 
+#include "ActuatorsMacros.h"
+
 using namespace Boardcore;
 using namespace miosix;
 using namespace Common;
@@ -113,78 +115,6 @@ bool Actuators::ServoInfo::setOpeningTime(uint32_t time)
     return true;
 }
 
-/**
- * @brief Shorthand to create a ServoInfo struct from the servo name
- */
-#define MAKE_SERVO(name)                                          \
-    ServoInfo                                                     \
-    {                                                             \
-        std::make_unique<Servo>(                                  \
-            MIOSIX_SERVOS_##name##_TIM,                           \
-            TimerUtils::Channel::MIOSIX_SERVOS_##name##_CHANNEL,  \
-            Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE, \
-            Config::Servos::FREQUENCY),                           \
-            ServoInfo::ServoConfig                                \
-        {                                                         \
-            .limit   = Config::Servos::name##_LIMIT,              \
-            .flipped = Config::Servos::name##_FLIPPED,            \
-            .defaultOpeningTime =                                 \
-                Config::Servos::DEFAULT_##name##_OPENING_TIME,    \
-            .defaultMaxAperture =                                 \
-                Config::Servos::DEFAULT_##name##_MAX_APERTURE,    \
-            .openingEvent      = MOTOR_##name##_OPEN,             \
-            .closingEvent      = MOTOR_##name##_CLOSE,            \
-            .openingTimeRegKey = CONFIG_ID_##name##_OPENING_TIME, \
-            .maxApertureRegKey = CONFIG_ID_##name##_MAX_APERTURE  \
-        }                                                         \
-    }
-
-/**
- * @brief Shorthand to create a detach ServoInfo struct from the servo name
- */
-#define MAKE_DETACH_SERVO(name)                                           \
-    ServoInfo                                                             \
-    {                                                                     \
-        std::make_unique<Servo>(                                          \
-            MIOSIX_SERVOS_##name##_TIM,                                   \
-            TimerUtils::Channel::MIOSIX_SERVOS_##name##_CHANNEL,          \
-            Config::Servos::DETACH_MIN_PULSE,                             \
-            Config::Servos::DETACH_MAX_PULSE, Config::Servos::FREQUENCY), \
-            ServoInfo::ServoConfig                                        \
-        {                                                                 \
-            .limit   = Config::Servos::name##_LIMIT,                      \
-            .flipped = Config::Servos::name##_FLIPPED,                    \
-            .defaultOpeningTime =                                         \
-                Config::Servos::DEFAULT_##name##_OPENING_TIME,            \
-            .defaultMaxAperture =                                         \
-                Config::Servos::DEFAULT_##name##_MAX_APERTURE,            \
-            .openingEvent      = MOTOR_##name##_OPEN,                     \
-            .closingEvent      = MOTOR_##name##_CLOSE,                    \
-            .openingTimeRegKey = CONFIG_ID_##name##_OPENING_TIME,         \
-            .maxApertureRegKey = CONFIG_ID_##name##_MAX_APERTURE          \
-        }                                                                 \
-    }
-
-/**
- * @brief Shorthand to create a non-atomic ServoInfo struct from the servo name
- */
-#define MAKE_SIMPLE_SERVO(name)                                   \
-    ServoInfo                                                     \
-    {                                                             \
-        std::make_unique<Servo>(                                  \
-            MIOSIX_SERVOS_##name##_TIM,                           \
-            TimerUtils::Channel::MIOSIX_SERVOS_##name##_CHANNEL,  \
-            Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE, \
-            Config::Servos::FREQUENCY),                           \
-            ServoInfo::ServoConfig                                \
-        {                                                         \
-            .limit        = Config::Servos::name##_LIMIT,         \
-            .flipped      = Config::Servos::name##_FLIPPED,       \
-            .openingEvent = MOTOR_##name##_OPEN,                  \
-            .closingEvent = MOTOR_##name##_CLOSE,                 \
-        }                                                         \
-    }
-
 Actuators::Actuators()
     : infos{
           MAKE_SERVO(OX_FIL),        MAKE_SERVO(OX_REL),
diff --git a/src/RIGv2/Actuators/ActuatorsMacros.h b/src/RIGv2/Actuators/ActuatorsMacros.h
new file mode 100644
index 000000000..3fa941e94
--- /dev/null
+++ b/src/RIGv2/Actuators/ActuatorsMacros.h
@@ -0,0 +1,128 @@
+/* Copyright (c) 2025 Skyward Experimental Rocketry
+ * Author: Niccolò Betto
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+/**
+ * @file ActuatorsMacros.h
+ * @brief Macros for the Actuators module
+ *
+ * This file contains macros to simplify the creation of ServoInfo structs
+ * for the Actuators module.
+ *
+ * The hardware mapping (hwmapping.h), the actuators configuration
+ * (ActuatorsConfig.h) and the registry keys (Registry.h) have been created with
+ * a specific naming convention to allow the use of these macros, to reduce the
+ * amount of code repetition and to make the code more readable during servo
+ * creation.
+ *
+ * The following naming convention is used:
+ * - The servo name is an uppercase string code (e.g. OX_FIL)
+ * - Constants are expected to be in the Config::Servos namespace
+ * - The servo name is used to create the following constants:
+ *      - MIOSIX_SERVOS_{servo}_TIM             (hwmapping)
+ *      - MIOSIX_SERVOS_{servo}_CHANNEL         (hwmapping)
+ *      - {servo}_LIMIT                         (ActuatorsConfig)
+ *      - {servo}_FLIPPED                       (ActuatorsConfig)
+ *      - Common::MOTOR_{servo}_OPEN                    (Events)
+ *      - Common::MOTOR_{servo}_CLOSE                   (Events)
+ *      - DEFAULT_{servo}_OPENING_TIME          (ActuatorsConfig)
+ *      - DEFAULT_{servo}_MAX_APERTURE          (ActuatorsConfig)
+ *      - CONFIG_ID_{servo}_OPENING_TIME        (Registry)
+ *      - CONFIG_ID_{servo}_MAX_APERTURE        (Registry)
+ *  - The following constants are used for all servos:
+ *     - MIN_PULSE
+ *     - MAX_PULSE
+ *     - FREQUENCY
+ */
+
+/**
+ * @brief Shorthand to create a ServoInfo struct from the servo name
+ */
+#define MAKE_SERVO(name)                                          \
+    ServoInfo                                                     \
+    {                                                             \
+        std::make_unique<Servo>(                                  \
+            MIOSIX_SERVOS_##name##_TIM,                           \
+            TimerUtils::Channel::MIOSIX_SERVOS_##name##_CHANNEL,  \
+            Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE, \
+            Config::Servos::FREQUENCY),                           \
+            ServoInfo::ServoConfig                                \
+        {                                                         \
+            .limit   = Config::Servos::name##_LIMIT,              \
+            .flipped = Config::Servos::name##_FLIPPED,            \
+            .defaultOpeningTime =                                 \
+                Config::Servos::DEFAULT_##name##_OPENING_TIME,    \
+            .defaultMaxAperture =                                 \
+                Config::Servos::DEFAULT_##name##_MAX_APERTURE,    \
+            .openingEvent      = Common::MOTOR_##name##_OPEN,     \
+            .closingEvent      = Common::MOTOR_##name##_CLOSE,    \
+            .openingTimeRegKey = CONFIG_ID_##name##_OPENING_TIME, \
+            .maxApertureRegKey = CONFIG_ID_##name##_MAX_APERTURE  \
+        }                                                         \
+    }
+
+/**
+ * @brief Shorthand to create a detach ServoInfo struct from the servo name
+ */
+#define MAKE_DETACH_SERVO(name)                                           \
+    ServoInfo                                                             \
+    {                                                                     \
+        std::make_unique<Servo>(                                          \
+            MIOSIX_SERVOS_##name##_TIM,                                   \
+            TimerUtils::Channel::MIOSIX_SERVOS_##name##_CHANNEL,          \
+            Config::Servos::DETACH_MIN_PULSE,                             \
+            Config::Servos::DETACH_MAX_PULSE, Config::Servos::FREQUENCY), \
+            ServoInfo::ServoConfig                                        \
+        {                                                                 \
+            .limit   = Config::Servos::name##_LIMIT,                      \
+            .flipped = Config::Servos::name##_FLIPPED,                    \
+            .defaultOpeningTime =                                         \
+                Config::Servos::DEFAULT_##name##_OPENING_TIME,            \
+            .defaultMaxAperture =                                         \
+                Config::Servos::DEFAULT_##name##_MAX_APERTURE,            \
+            .openingEvent      = Common::MOTOR_##name##_OPEN,             \
+            .closingEvent      = Common::MOTOR_##name##_CLOSE,            \
+            .openingTimeRegKey = CONFIG_ID_##name##_OPENING_TIME,         \
+            .maxApertureRegKey = CONFIG_ID_##name##_MAX_APERTURE          \
+        }                                                                 \
+    }
+
+/**
+ * @brief Shorthand to create a non-atomic ServoInfo struct from the servo name
+ */
+#define MAKE_SIMPLE_SERVO(name)                                   \
+    ServoInfo                                                     \
+    {                                                             \
+        std::make_unique<Servo>(                                  \
+            MIOSIX_SERVOS_##name##_TIM,                           \
+            TimerUtils::Channel::MIOSIX_SERVOS_##name##_CHANNEL,  \
+            Config::Servos::MIN_PULSE, Config::Servos::MAX_PULSE, \
+            Config::Servos::FREQUENCY),                           \
+            ServoInfo::ServoConfig                                \
+        {                                                         \
+            .limit        = Config::Servos::name##_LIMIT,         \
+            .flipped      = Config::Servos::name##_FLIPPED,       \
+            .openingEvent = Common::MOTOR_##name##_OPEN,          \
+            .closingEvent = Common::MOTOR_##name##_CLOSE,         \
+        }                                                         \
+    }
-- 
GitLab