diff --git a/CMakeLists.txt b/CMakeLists.txt
index d44bbc9def4d34462530edbaf8486b6c115a3ff3..a1510b8c65a58309f0cf4c4f80d968cb325dea86 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -72,6 +72,10 @@ add_executable(rig-v2-entry src/RIGv2/rig-v2-entry.cpp ${RIG_V2_COMPUTER})
 target_include_directories(rig-v2-entry PRIVATE ${OBSW_INCLUDE_DIRS})
 sbs_target(rig-v2-entry stm32f767zi_rig_v2)
 
+add_executable(rig-v2-adc-test src/RIGv2/rig-v2-adc-test.cpp ${RIG_V2_COMPUTER})
+target_include_directories(rig-v2-adc-test PRIVATE ${OBSW_INCLUDE_DIRS})
+sbs_target(rig-v2-adc-test stm32f767zi_rig_v2)
+
 add_executable(con_rig-entry src/ConRIG/con_rig-entry.cpp ${CON_RIG_COMPUTER})
 target_include_directories(con_rig-entry PRIVATE ${OBSW_INCLUDE_DIRS})
 sbs_target(con_rig-entry stm32f429zi_con_rig)
diff --git a/scripts/logdecoder/General/logdecoder.cpp b/scripts/logdecoder/General/logdecoder.cpp
index c2639f17f9dc77a5cce605effb5cb22d7846d97d..d6226ce7dfcf4e7269812bc242826f169749e16f 100644
--- a/scripts/logdecoder/General/logdecoder.cpp
+++ b/scripts/logdecoder/General/logdecoder.cpp
@@ -109,14 +109,15 @@ void registerTypes(Deserializer& ds)
     ds.registerType<RIGv2::ADC2Data>();
     ds.registerType<RIGv2::TC1Data>();
     ds.registerType<RIGv2::OxVesselWeightData>();
+    ds.registerType<RIGv2::RocketWeightData>();
     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::OxTankPressureData>();
+    ds.registerType<RIGv2::N2TankPressureData>();
     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 666ae2f71b2185ac68989df5efbef11f8dccdc98..6062e9ff7a2a7f5c962c439b4cd167fc406ea0e3 100644
--- a/scripts/logdecoder/RIGv2/logdecoder.cpp
+++ b/scripts/logdecoder/RIGv2/logdecoder.cpp
@@ -57,14 +57,15 @@ void registerTypes(Deserializer& ds)
     ds.registerType<ADC2Data>();
     ds.registerType<TC1Data>();
     ds.registerType<OxVesselWeightData>();
+    ds.registerType<RocketWeightData>();
     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<OxTankPressureData>();
+    ds.registerType<N2TankPressureData>();
     ds.registerType<ActuatorsData>();
     ds.registerType<GroundModeManagerData>();
     ds.registerType<TarsActionData>();
diff --git a/src/ConRIG/Buttons/Buttons.cpp b/src/ConRIG/Buttons/Buttons.cpp
index 8390a9494aaeeccff1c67dcba0a204da15672c8c..c4b5a98d179e46698949a65174c12c55c5e4c504 100644
--- a/src/ConRIG/Buttons/Buttons.cpp
+++ b/src/ConRIG/Buttons/Buttons.cpp
@@ -32,11 +32,10 @@ using namespace miosix;
 using namespace Boardcore;
 using namespace ConRIG;
 
-Buttons::Buttons() : state() {}
-
 bool Buttons::start()
 {
-    TaskScheduler& scheduler = getModule<BoardScheduler>()->getRadioScheduler();
+    TaskScheduler& scheduler =
+        getModule<BoardScheduler>()->getButtonsScheduler();
 
     return scheduler.addTask([this]() { periodicStatusCheck(); },
                              Config::Buttons::BUTTON_SAMPLE_PERIOD) != 0;
@@ -44,131 +43,43 @@ bool Buttons::start()
 
 mavlink_conrig_state_tc_t Buttons::getState() { return state; }
 
-void Buttons::resetState()
-{
-    // Preserve the arm switch state
-    auto armSwitch   = state.arm_switch;
-    state            = {};
-    state.arm_switch = armSwitch;
-}
-
 void Buttons::periodicStatusCheck()
 {
+#define CHECK_BUTTON(cond, btn)                           \
+    if (cond)                                             \
+    {                                                     \
+        if (guard.btn > Config::Buttons::GUARD_THRESHOLD) \
+        {                                                 \
+            guard.btn = 0;                                \
+            state.btn = true;                             \
+            LOG_DEBUG(logger, #btn " button pressed");    \
+        }                                                 \
+        else                                              \
+        {                                                 \
+            guard.btn++;                                  \
+        }                                                 \
+    }                                                     \
+    else                                                  \
+    {                                                     \
+        guard.btn = 0;                                    \
+        state.btn = false;                                \
+    }
+
     state.arm_switch = btns::arm::value();
 
-    if (!btns::ignition::value() && state.arm_switch)
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard              = 0;
-            state.ignition_btn = true;
-            LOG_DEBUG(logger, "Ignition button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::n2o_filling::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard                = 0;
-            state.ox_filling_btn = true;
-            LOG_DEBUG(logger, "ox filling button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::n2o_release::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard                = 0;
-            state.ox_release_btn = true;
-            LOG_DEBUG(logger, "ox release button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::n2_release::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard                = 0;
-            state.n2_release_btn = true;
-            LOG_DEBUG(logger, "n2 release button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::n2o_venting::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard                = 0;
-            state.ox_venting_btn = true;
-            LOG_DEBUG(logger, "ox venting button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::n2_detach::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard               = 0;
-            state.n2_detach_btn = true;
-            LOG_DEBUG(logger, "n2 detach button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::n2_filling::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard                = 0;
-            state.n2_filling_btn = true;
-            LOG_DEBUG(logger, "n2 filling button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::nitrogen::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard              = 0;
-            state.nitrogen_btn = true;
-            LOG_DEBUG(logger, "nitrogen button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else
-    {
-        // Reset all the states and guard
-        guard = 0;
-        resetState();
-    }
+    CHECK_BUTTON(!btns::ignition::value() && state.arm_switch, ignition_btn);
+    CHECK_BUTTON(btns::n2o_filling::value(), ox_filling_btn);
+    CHECK_BUTTON(btns::n2o_release::value(), ox_release_btn);
+    CHECK_BUTTON(btns::n2_release::value(), n2_release_btn);
+    CHECK_BUTTON(btns::n2o_venting::value(), ox_venting_btn);
+    CHECK_BUTTON(btns::n2_detach::value(), n2_detach_btn);
+    CHECK_BUTTON(btns::n2_filling::value(), n2_filling_btn);
+    CHECK_BUTTON(btns::nitrogen::value(), nitrogen_btn);
+
+#undef CHECK_BUTTON
 
     // Set the internal button state in Radio module
-    getModule<Radio>()->setButtonsState(state);
+    getModule<Radio>()->updateButtonState(state);
 }
 
 void Buttons::enableIgnition() { ui::armedLed::high(); }
diff --git a/src/ConRIG/Buttons/Buttons.h b/src/ConRIG/Buttons/Buttons.h
index ecd160f2fd7d43d43d0c08e8de4aba4aee57a0bf..2d6fff4ae199923019fe7a44d52ae447647899e2 100644
--- a/src/ConRIG/Buttons/Buttons.h
+++ b/src/ConRIG/Buttons/Buttons.h
@@ -36,8 +36,6 @@ class Radio;
 class Buttons : public Boardcore::InjectableWithDeps<BoardScheduler, Radio>
 {
 public:
-    Buttons();
-
     [[nodiscard]] bool start();
 
     mavlink_conrig_state_tc_t getState();
@@ -46,14 +44,11 @@ public:
     void disableIgnition();
 
 private:
-    void resetState();
-
     void periodicStatusCheck();
 
-    mavlink_conrig_state_tc_t state;
-
+    mavlink_conrig_state_tc_t state{};
     // Counter guard to avoid spurious triggers
-    uint8_t guard = 0;
+    mavlink_conrig_state_tc_t guard{};
 
     Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("buttons");
 };
diff --git a/src/ConRIG/Configs/RadioConfig.h b/src/ConRIG/Configs/RadioConfig.h
index 735ae3f51db71ad76c0ebe6a8ce151bdc35a39b9..af7f66cdea1a9a808c22f1cdf18404ea3e97bd82 100644
--- a/src/ConRIG/Configs/RadioConfig.h
+++ b/src/ConRIG/Configs/RadioConfig.h
@@ -50,6 +50,12 @@ constexpr uint8_t MAV_COMPONENT_ID = 96;
 // Periodic telemetries frequency
 constexpr Hertz PING_GSE_PERIOD = 2_hz;
 
+// Audio feedback message threshold
+constexpr auto AUDIO_FEEDBACK_THRESHOLD = 10;
+// Value to reset the message counter to, to avoid long pauses without audio
+// feedback after startup or disarming
+constexpr auto AUDIO_FEEDBACK_RESET_VALUE = AUDIO_FEEDBACK_THRESHOLD * 4 / 5;
+
 }  // namespace Radio
 }  // namespace Config
 }  // namespace ConRIG
diff --git a/src/ConRIG/Radio/Radio.cpp b/src/ConRIG/Radio/Radio.cpp
index af3e1cf783a54f6658200b941995d4e095973c00..f9e218372658f5aea704a04a780a7963e658f7a7 100644
--- a/src/ConRIG/Radio/Radio.cpp
+++ b/src/ConRIG/Radio/Radio.cpp
@@ -63,10 +63,18 @@ void Radio::handleMessage(const mavlink_message_t& msg)
         case MAVLINK_MSG_ID_GSE_TM:
         {
             int armingState = mavlink_msg_gse_tm_get_arming_state(&msg);
-            messagesReceived += 1;
+            bool wasArmed   = isArmed;
+            bool isNowArmed = armingState == 1;
+            isArmed         = isNowArmed;
+
+            // Reset the message counter to a value higher than zero to avoid
+            // long pauses without audio feedback after disarming
+            if (wasArmed && !isNowArmed)
+                messagesReceived = Config::Radio::AUDIO_FEEDBACK_RESET_VALUE;
+            else
+                messagesReceived += 1;
 
-            isArmed = armingState == 1;
-            if (armingState == 1)
+            if (isNowArmed)
                 getModule<Buttons>()->enableIgnition();
             else
                 getModule<Buttons>()->disableIgnition();
@@ -80,9 +88,8 @@ void Radio::handleMessage(const mavlink_message_t& msg)
             // we assume this ack is about the last sent message
             if (id == MAVLINK_MSG_ID_CONRIG_STATE_TC)
             {
-                Lock<FastMutex> lock{buttonsMutex};
                 // Reset the internal button state
-                buttonState = {};
+                resetButtonState();
             }
 
             break;
@@ -145,7 +152,8 @@ void Radio::loopBuzzer()
         Thread::sleep(100);
         // Doesn't matter the precision, the important thing is
         // the beep, this is because an atomic is used
-        if ((!isArmed && messagesReceived > 2) ||
+        if ((!isArmed &&
+             messagesReceived > Config::Radio::AUDIO_FEEDBACK_THRESHOLD) ||
             (isArmed && messagesReceived > 0))
         {
             messagesReceived = 0;
@@ -156,11 +164,11 @@ void Radio::loopBuzzer()
     }
 }
 
-void Radio::setButtonsState(mavlink_conrig_state_tc_t state)
+void Radio::updateButtonState(const mavlink_conrig_state_tc_t& state)
 {
     Lock<FastMutex> lock{buttonsMutex};
-    // The OR operator is introduced to make sure that the receiver
-    // understood the command
+    // Merge the new state with the old one, an extra-dumb way to ensure
+    // that we don't lose any button pressess
     buttonState.ox_filling_btn |= state.ox_filling_btn;
     buttonState.ox_release_btn |= state.ox_release_btn;
     buttonState.n2_filling_btn |= state.n2_filling_btn;
@@ -170,11 +178,24 @@ void Radio::setButtonsState(mavlink_conrig_state_tc_t state)
     buttonState.nitrogen_btn |= state.nitrogen_btn;
     buttonState.ox_detach_btn |= state.ox_detach_btn;
     buttonState.n2_quenching_btn |= state.n2_quenching_btn;
-    buttonState.n2_3way_btn |= state.n2_3way_btn;
     buttonState.tars3_btn |= state.tars3_btn;
     buttonState.tars3m_btn |= state.tars3m_btn;
     buttonState.ignition_btn |= state.ignition_btn;
-    buttonState.arm_switch |= state.arm_switch;
+
+    // Don't merge lever states
+    buttonState.n2_3way_btn = state.n2_3way_btn;
+    buttonState.arm_switch  = state.arm_switch;
+}
+
+void Radio::resetButtonState()
+{
+    Lock<FastMutex> lock{buttonsMutex};
+    // Save and restore lever states
+    auto n2_3way_btn        = buttonState.n2_3way_btn;
+    auto arm_switch         = buttonState.arm_switch;
+    buttonState             = {};
+    buttonState.n2_3way_btn = n2_3way_btn;
+    buttonState.arm_switch  = arm_switch;
 }
 
 bool Radio::start()
@@ -229,5 +250,3 @@ bool Radio::start()
 }
 
 MavlinkStatus Radio::getMavlinkStatus() { return mavDriver->getStatus(); }
-
-Radio::Radio() : buttonState() {}
diff --git a/src/ConRIG/Radio/Radio.h b/src/ConRIG/Radio/Radio.h
index f9d5edb293ce01516b11dfd26ea984318950b110..29197d28011941501edad0de994f1d06b94e7954 100644
--- a/src/ConRIG/Radio/Radio.h
+++ b/src/ConRIG/Radio/Radio.h
@@ -49,13 +49,11 @@ class Radio : public Boardcore::InjectableWithDeps<Buses, BoardScheduler,
                                                    Buttons, Serial>
 {
 public:
-    Radio();
-
     [[nodiscard]] bool start();
 
     Boardcore::MavlinkStatus getMavlinkStatus();
 
-    void setButtonsState(mavlink_conrig_state_tc_t state);
+    void updateButtonState(const mavlink_conrig_state_tc_t& state);
 
     bool enqueueMessage(const mavlink_message_t& msg);
 
@@ -64,6 +62,8 @@ private:
     void loopBuzzer();
     void handleMessage(const mavlink_message_t& msg);
 
+    void resetButtonState();
+
     std::unique_ptr<Boardcore::SX1278Lora> radio;
     std::unique_ptr<MavDriver> mavDriver;
 
@@ -72,14 +72,15 @@ private:
         messageQueue;
 
     miosix::FastMutex queueMutex;
-    miosix::FastMutex buttonsMutex;
 
     // Button internal state
-    mavlink_conrig_state_tc_t buttonState;
+    miosix::FastMutex buttonsMutex;
+    mavlink_conrig_state_tc_t buttonState{};
 
     std::thread buzzerLooper;
 
-    std::atomic<uint8_t> messagesReceived{0};
+    std::atomic<uint8_t> messagesReceived{
+        Config::Radio::AUDIO_FEEDBACK_RESET_VALUE};
     std::atomic<bool> isArmed{false};
 
     Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("radio");
diff --git a/src/ConRIGv2/Buttons/Buttons.cpp b/src/ConRIGv2/Buttons/Buttons.cpp
index e7056ab79167ecda0e60e0254917e566461ca41e..f30478643745bf43486aa25a24b2980da0fd1913 100644
--- a/src/ConRIGv2/Buttons/Buttons.cpp
+++ b/src/ConRIGv2/Buttons/Buttons.cpp
@@ -1,5 +1,5 @@
 /* Copyright (c) 2025 Skyward Experimental Rocketry
- * Author: Ettore Pane
+ * Authors: Ettore Pane, 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
@@ -32,15 +32,10 @@ using namespace miosix;
 using namespace Boardcore;
 using namespace ConRIGv2;
 
-Buttons::Buttons()
-{
-    resetState();
-    state.arm_switch = false;
-}
-
 bool Buttons::start()
 {
-    TaskScheduler& scheduler = getModule<BoardScheduler>()->getRadioScheduler();
+    TaskScheduler& scheduler =
+        getModule<BoardScheduler>()->getButtonsScheduler();
 
     return scheduler.addTask([this]() { periodicStatusCheck(); },
                              Config::Buttons::BUTTON_SAMPLE_PERIOD) != 0;
@@ -48,196 +43,48 @@ bool Buttons::start()
 
 mavlink_conrig_state_tc_t Buttons::getState() { return state; }
 
-void Buttons::resetState()
-{
-    // Preserve the arm switch state
-    auto armSwitch   = state.arm_switch;
-    state            = {};
-    state.arm_switch = armSwitch;
-}
-
 void Buttons::periodicStatusCheck()
 {
-    state.arm_switch = btns::arm::value();
-
-    if (!btns::ignition::value() && state.arm_switch)
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard              = 0;
-            state.ignition_btn = true;
-            LOG_DEBUG(logger, "Ignition button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::ox_filling::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard                = 0;
-            state.ox_filling_btn = true;
-            LOG_DEBUG(logger, "Ox filling button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::ox_release::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard                = 0;
-            state.ox_release_btn = true;
-            LOG_DEBUG(logger, "Ox release button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::ox_detach::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard               = 0;
-            state.ox_detach_btn = true;
-            LOG_DEBUG(logger, "Ox detach button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::n2_3way::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard               = 0;
-            state.ox_detach_btn = true;
-            LOG_DEBUG(logger, "n2 3way button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::n2_filling::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard                = 0;
-            state.n2_filling_btn = true;
-            LOG_DEBUG(logger, "N2 filling button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::n2_release::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard                = 0;
-            state.n2_release_btn = true;
-            LOG_DEBUG(logger, "N2 release button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::n2_detach::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard               = 0;
-            state.n2_detach_btn = true;
-            LOG_DEBUG(logger, "N2 detach button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::nitrogen::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard              = 0;
-            state.nitrogen_btn = true;
-            LOG_DEBUG(logger, "Nitrogen button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::ox_venting::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard                = 0;
-            state.ox_venting_btn = true;
-            LOG_DEBUG(logger, "Ox venting button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::n2_quenching::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard                  = 0;
-            state.n2_quenching_btn = true;
-            LOG_DEBUG(logger, "N2 quenching button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::tars3::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard           = 0;
-            state.tars3_btn = true;
-            LOG_DEBUG(logger, "Tars3 button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else if (btns::tars3m::value())
-    {
-        if (guard > Config::Buttons::GUARD_THRESHOLD)
-        {
-            guard            = 0;
-            state.tars3m_btn = true;
-            LOG_DEBUG(logger, "Tars3m button pressed");
-        }
-        else
-        {
-            guard++;
-        }
-    }
-    else
-    {
-        // Reset all the states and guard
-        guard = 0;
-        resetState();
+#define CHECK_BUTTON(cond, btn)                           \
+    if (cond)                                             \
+    {                                                     \
+        if (guard.btn > Config::Buttons::GUARD_THRESHOLD) \
+        {                                                 \
+            guard.btn = 0;                                \
+            state.btn = true;                             \
+            LOG_DEBUG(logger, #btn " button pressed");    \
+        }                                                 \
+        else                                              \
+        {                                                 \
+            guard.btn++;                                  \
+        }                                                 \
+    }                                                     \
+    else                                                  \
+    {                                                     \
+        guard.btn = 0;                                    \
+        state.btn = false;                                \
     }
 
+    state.arm_switch  = btns::arm::value();
+    state.n2_3way_btn = btns::n2_3way::value();
+
+    CHECK_BUTTON(!btns::ignition::value() && state.arm_switch, ignition_btn);
+    CHECK_BUTTON(btns::ox_filling::value(), ox_filling_btn);
+    CHECK_BUTTON(btns::ox_release::value(), ox_release_btn);
+    CHECK_BUTTON(btns::ox_detach::value(), ox_detach_btn);
+    CHECK_BUTTON(btns::ox_venting::value(), ox_venting_btn);
+    CHECK_BUTTON(btns::n2_filling::value(), n2_filling_btn);
+    CHECK_BUTTON(btns::n2_release::value(), n2_release_btn);
+    CHECK_BUTTON(btns::n2_detach::value(), n2_detach_btn);
+    CHECK_BUTTON(btns::n2_quenching::value(), n2_quenching_btn);
+    CHECK_BUTTON(btns::nitrogen::value(), nitrogen_btn);
+    CHECK_BUTTON(btns::tars3::value(), tars3_btn);
+    CHECK_BUTTON(btns::tars3m::value(), tars3m_btn);
+
+#undef CHECK_BUTTON
+
     // Set the internal button state in Radio module
-    getModule<Radio>()->setButtonsState(state);
+    getModule<Radio>()->updateButtonState(state);
 }
 
 void Buttons::enableIgnition() { ui::armedLed::high(); }
diff --git a/src/ConRIGv2/Buttons/Buttons.h b/src/ConRIGv2/Buttons/Buttons.h
index 5d2c26d0e205475718628903b21934478dfb8c6e..2c4d5440825d41614c65c8dc960fa64bd26fe4fc 100644
--- a/src/ConRIGv2/Buttons/Buttons.h
+++ b/src/ConRIGv2/Buttons/Buttons.h
@@ -36,8 +36,6 @@ class Radio;
 class Buttons : public Boardcore::InjectableWithDeps<BoardScheduler, Radio>
 {
 public:
-    Buttons();
-
     [[nodiscard]] bool start();
 
     mavlink_conrig_state_tc_t getState();
@@ -46,14 +44,11 @@ public:
     void disableIgnition();
 
 private:
-    void resetState();
-
     void periodicStatusCheck();
 
-    mavlink_conrig_state_tc_t state;
-
+    mavlink_conrig_state_tc_t state{};
     // Counter guard to avoid spurious triggers
-    uint8_t guard = 0;
+    mavlink_conrig_state_tc_t guard{};
 
     Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("buttons");
 };
diff --git a/src/ConRIGv2/Configs/RadioConfig.h b/src/ConRIGv2/Configs/RadioConfig.h
index 8f2695e6784a4d18966dbb0ad481efeb2eebe4bb..b6065aa5e0652ef0d3aeaa43bc9316b47d37160a 100644
--- a/src/ConRIGv2/Configs/RadioConfig.h
+++ b/src/ConRIGv2/Configs/RadioConfig.h
@@ -50,6 +50,12 @@ constexpr uint8_t MAV_COMPONENT_ID = 96;
 // Periodic telemetries frequency
 constexpr Hertz PING_GSE_PERIOD = 2_hz;
 
+// Audio feedback message threshold
+constexpr auto AUDIO_FEEDBACK_THRESHOLD = 10;
+// Value to reset the message counter to, to avoid long pauses without audio
+// feedback after startup or disarming
+constexpr auto AUDIO_FEEDBACK_RESET_VALUE = AUDIO_FEEDBACK_THRESHOLD * 4 / 5;
+
 }  // namespace Radio
 }  // namespace Config
 }  // namespace ConRIGv2
diff --git a/src/ConRIGv2/Radio/Radio.cpp b/src/ConRIGv2/Radio/Radio.cpp
index 8e7ebb8436e7f309b9cc74e4bb1e0665e72c250a..3091b2a7c18990bc20ff87c01ee2c452cc6f6381 100644
--- a/src/ConRIGv2/Radio/Radio.cpp
+++ b/src/ConRIGv2/Radio/Radio.cpp
@@ -1,5 +1,5 @@
 /* Copyright (c) 2025 Skyward Experimental Rocketry
- * Author: Ettore Pane
+ * Authors: Ettore Pane, 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
@@ -63,10 +63,18 @@ void Radio::handleMessage(const mavlink_message_t& msg)
         case MAVLINK_MSG_ID_GSE_TM:
         {
             int armingState = mavlink_msg_gse_tm_get_arming_state(&msg);
-            messagesReceived += 1;
+            bool wasArmed   = isArmed;
+            bool isNowArmed = armingState == 1;
+            isArmed         = isNowArmed;
+
+            // Reset the message counter to a value higher than zero to avoid
+            // long pauses without audio feedback after disarming
+            if (wasArmed && !isNowArmed)
+                messagesReceived = Config::Radio::AUDIO_FEEDBACK_RESET_VALUE;
+            else
+                messagesReceived += 1;
 
-            isArmed = armingState == 1;
-            if (armingState == 1)
+            if (isNowArmed)
                 getModule<Buttons>()->enableIgnition();
             else
                 getModule<Buttons>()->disableIgnition();
@@ -80,9 +88,8 @@ void Radio::handleMessage(const mavlink_message_t& msg)
             // we assume this ack is about the last sent message
             if (id == MAVLINK_MSG_ID_CONRIG_STATE_TC)
             {
-                Lock<FastMutex> lock{buttonsMutex};
                 // Reset the internal button state
-                buttonState = {};
+                resetButtonState();
             }
 
             break;
@@ -150,9 +157,8 @@ void Radio::buzzerOff()
 
 void Radio::buzzerTask()
 {
-    constexpr int beepPeriod = 5;  // seconds
-
-    if ((!isArmed && messagesReceived > beepPeriod * 2) ||
+    if ((!isArmed &&
+         messagesReceived > Config::Radio::AUDIO_FEEDBACK_THRESHOLD) ||
         (isArmed && messagesReceived > 0))
     {
         messagesReceived = 0;
@@ -164,11 +170,11 @@ void Radio::buzzerTask()
     }
 }
 
-void Radio::setButtonsState(const mavlink_conrig_state_tc_t& state)
+void Radio::updateButtonState(const mavlink_conrig_state_tc_t& state)
 {
     Lock<FastMutex> lock{buttonsMutex};
-    // The OR operator is introduced to make sure that the receiver
-    // understood the command
+    // Merge the new state with the old one, an extra-dumb way to ensure
+    // that we don't lose any button pressess
     buttonState.ox_filling_btn |= state.ox_filling_btn;
     buttonState.ox_release_btn |= state.ox_release_btn;
     buttonState.n2_filling_btn |= state.n2_filling_btn;
@@ -178,11 +184,24 @@ void Radio::setButtonsState(const mavlink_conrig_state_tc_t& state)
     buttonState.nitrogen_btn |= state.nitrogen_btn;
     buttonState.ox_detach_btn |= state.ox_detach_btn;
     buttonState.n2_quenching_btn |= state.n2_quenching_btn;
-    buttonState.n2_3way_btn |= state.n2_3way_btn;
     buttonState.tars3_btn |= state.tars3_btn;
     buttonState.tars3m_btn |= state.tars3m_btn;
     buttonState.ignition_btn |= state.ignition_btn;
-    buttonState.arm_switch |= state.arm_switch;
+
+    // Don't merge lever states
+    buttonState.n2_3way_btn = state.n2_3way_btn;
+    buttonState.arm_switch  = state.arm_switch;
+}
+
+void Radio::resetButtonState()
+{
+    Lock<FastMutex> lock{buttonsMutex};
+    // Save and restore lever states
+    auto n2_3way_btn        = buttonState.n2_3way_btn;
+    auto arm_switch         = buttonState.arm_switch;
+    buttonState             = {};
+    buttonState.n2_3way_btn = n2_3way_btn;
+    buttonState.arm_switch  = arm_switch;
 }
 
 bool Radio::start()
@@ -239,7 +258,7 @@ bool Radio::start()
 
 MavlinkStatus Radio::getMavlinkStatus() { return mavDriver->getStatus(); }
 
-Radio::Radio() : buzzer(MIOSIX_BUZZER_TIM, 523), buttonState()
+Radio::Radio() : buzzer(MIOSIX_BUZZER_TIM, 523)
 {
     buzzer.setDutyCycle(TimerUtils::Channel::MIOSIX_BUZZER_CHANNEL, 0.5);
 }
diff --git a/src/ConRIGv2/Radio/Radio.h b/src/ConRIGv2/Radio/Radio.h
index 399eb42fba46ada9bbf87528b16a6d8b04091493..71120d3fbe62145106615d3ea97724a1744d7129 100644
--- a/src/ConRIGv2/Radio/Radio.h
+++ b/src/ConRIGv2/Radio/Radio.h
@@ -56,7 +56,7 @@ public:
 
     Boardcore::MavlinkStatus getMavlinkStatus();
 
-    void setButtonsState(const mavlink_conrig_state_tc_t& state);
+    void updateButtonState(const mavlink_conrig_state_tc_t& state);
 
     bool enqueueMessage(const mavlink_message_t& msg);
 
@@ -65,6 +65,8 @@ private:
     void buzzerTask();
     void handleMessage(const mavlink_message_t& msg);
 
+    void resetButtonState();
+
     std::unique_ptr<Boardcore::SX1278Lora> radio;
     std::unique_ptr<MavDriver> mavDriver;
 
@@ -81,12 +83,13 @@ private:
         messageQueue;
 
     miosix::FastMutex queueMutex;
-    miosix::FastMutex buttonsMutex;
 
     // Button internal state
-    mavlink_conrig_state_tc_t buttonState;
+    miosix::FastMutex buttonsMutex;
+    mavlink_conrig_state_tc_t buttonState{};
 
-    std::atomic<uint8_t> messagesReceived{0};
+    std::atomic<uint8_t> messagesReceived{
+        Config::Radio::AUDIO_FEEDBACK_RESET_VALUE};
     std::atomic<bool> isArmed{false};
 
     Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("radio");
diff --git a/src/RIGv2/Actuators/Actuators.cpp b/src/RIGv2/Actuators/Actuators.cpp
index 6f2f570b529ad4d884e56f5557e12fd87a59caff..6138b6901c1dfade4006863700a83eabee0cc7da 100644
--- a/src/RIGv2/Actuators/Actuators.cpp
+++ b/src/RIGv2/Actuators/Actuators.cpp
@@ -116,14 +116,11 @@ bool Actuators::ServoInfo::setOpeningTime(uint32_t time)
 }
 
 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))
+    : 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))
 {
     for (auto& servo : infos)
         servo.unsafeSetServoPosition(0.0f);
@@ -142,6 +139,8 @@ bool Actuators::start()
     for (ServoInfo& info : infos)
         info.servo->enable();
 
+    n2_3wayValveInfo.servo->enable();
+
     uint8_t result =
         scheduler.addTask([this]() { updatePositionsTask(); },
                           Config::Servos::SERVO_TIMINGS_CHECK_PERIOD);
@@ -164,6 +163,19 @@ void Actuators::igniterOff() { relays::ignition::high(); }
 
 bool Actuators::wiggleServo(ServosList servo)
 {
+    // Special handling for the 3-way valve
+    if (servo == N2_3WAY_VALVE)
+    {
+        // Toggle the valve to the current opposite state
+        auto state = get3wayValveState();
+
+        set3wayValveState(!state);
+        Thread::sleep(1000);
+        set3wayValveState(state);
+
+        return true;
+    }
+
     // Wiggle means open the servo for 1s
     return openServoWithTime(servo, 1000);
 }
@@ -288,16 +300,9 @@ 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::set3wayValveState(bool state) { n2_3wayValveState = state; }
 
-bool Actuators::get3wayValveState()
-{
-    return n2_3wayValveInfo.getServoPosition() == 1.0f;
-}
+bool Actuators::get3wayValveState() { return n2_3wayValveState; }
 
 void Actuators::openChamberWithTime(uint32_t time)
 {
@@ -371,19 +376,19 @@ Actuators::ServoInfo* Actuators::getServo(ServosList servo)
         case OX_DETACH_SERVO:  // OX_DET
             return &infos[2];
         case N2_FILLING_VALVE:  // N2_FIL
-            return &infos[4];
+            return &infos[3];
         case N2_RELEASE_VALVE:  // N2_REL
-            return &infos[5];
+            return &infos[4];
         case N2_DETACH_SERVO:  // N2_DET
-            return &infos[6];
+            return &infos[5];
         case NITROGEN_VALVE:  // NITR
-            return &infos[7];
+            return &infos[6];
         case OX_VENTING_VALVE:  // OX_VEN
-            return &infos[8];
+            return &infos[7];
         case N2_QUENCHING_VALVE:  // N2_QUE
-            return &infos[9];
+            return &infos[8];
         case MAIN_VALVE:  // MAIN
-            return &infos[10];
+            return &infos[9];
 
         default:
             // Oh FUCK
@@ -472,4 +477,8 @@ void Actuators::updatePositionsTask()
 
         unsafeCloseChamber();
     }
+
+    // Handle the 3-way valve
+    auto position = n2_3wayValveState ? 1.0f : 0.0f;
+    n2_3wayValveInfo.unsafeSetServoPosition(position);
 }
diff --git a/src/RIGv2/Actuators/Actuators.h b/src/RIGv2/Actuators/Actuators.h
index 0289b1a7812906c4e7925c55a602085917b7266c..b6cb422d7fd882adbb001e0faf14e596dfd95c62 100644
--- a/src/RIGv2/Actuators/Actuators.h
+++ b/src/RIGv2/Actuators/Actuators.h
@@ -132,8 +132,9 @@ private:
     std::atomic<bool> started{false};
 
     miosix::FastMutex infosMutex;
-    ServoInfo infos[10];
+    std::array<ServoInfo, 10> infos;
     ServoInfo n2_3wayValveInfo;
+    std::atomic<bool> n2_3wayValveState{false};
 
     long long chamberCloseTs =
         0;  ///< Timestamp to close the chamber (0 if closed)
diff --git a/src/RIGv2/Configs/RadioConfig.h b/src/RIGv2/Configs/RadioConfig.h
index af1b8643e9be58a52e7c29b74f2514fd5a38db79..fb8a2a6b8b701206250412c7786e85a4ad94d7eb 100644
--- a/src/RIGv2/Configs/RadioConfig.h
+++ b/src/RIGv2/Configs/RadioConfig.h
@@ -39,8 +39,9 @@ constexpr unsigned int MAV_MAX_LENGTH     = MAVLINK_MAX_DIALECT_PAYLOAD_SIZE;
 constexpr uint16_t MAV_SLEEP_AFTER_SEND = 0;
 constexpr size_t MAV_OUT_BUFFER_MAX_AGE = 10;
 
-constexpr unsigned int CIRCULAR_BUFFER_SIZE  = 30;
-constexpr unsigned int MAX_PACKETS_PER_FLUSH = 4;
+constexpr unsigned int CIRCULAR_BUFFER_SIZE = 30;
+// Measured empirically, used to determine how many packets to send in a flush
+constexpr unsigned int BITRATE = 4000;  // [bits/s]
 
 constexpr uint8_t MAV_SYSTEM_ID    = MAV_SYSID_RIG;
 constexpr uint8_t MAV_COMPONENT_ID = 0;
diff --git a/src/RIGv2/Configs/SensorsConfig.h b/src/RIGv2/Configs/SensorsConfig.h
index 397a5bd8ac3759b9bd86a8d95dfbab42d4be0ea9..ac9e7bea67ff55a6d2ee4a03fbf42bf729cd2237 100644
--- a/src/RIGv2/Configs/SensorsConfig.h
+++ b/src/RIGv2/Configs/SensorsConfig.h
@@ -27,6 +27,7 @@
 #include <sensors/MAX31856/MAX31856.h>
 #include <units/Frequency.h>
 
+#include <chrono>
 #include <cstdint>
 
 namespace RIGv2
@@ -38,6 +39,7 @@ namespace Config
 namespace Sensors
 {
 
+/* linter off */ using namespace std::chrono;
 /* linter off */ using namespace Boardcore::Units::Frequency;
 
 namespace ADS131M08
@@ -46,7 +48,6 @@ constexpr auto OSR = Boardcore::ADS131M08Defs::OversamplingRatio::OSR_8192;
 constexpr bool GLOBAL_CHOP_MODE_EN = true;
 
 constexpr Hertz PERIOD = 100_hz;
-constexpr bool ENABLED = true;
 
 // Servo current sensor calibration data
 // - A: 0.0 V: 2.520
@@ -62,6 +63,8 @@ constexpr float SERVO_CURRENT_ZERO  = 2.520 / SERVO_CURRENT_SCALE;
 
 namespace ADC_1
 {
+constexpr bool ENABLED = true;
+
 using Channel = Boardcore::ADS131M08Defs::Channel;
 
 constexpr auto OX_VESSEL_PT_CHANNEL   = Channel::CHANNEL_0;
@@ -70,25 +73,27 @@ 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 ROCKET_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
+constexpr float CH0_SHUNT_RESISTANCE = 29.283f;
+constexpr float CH1_SHUNT_RESISTANCE = 29.233f;
+constexpr float CH2_SHUNT_RESISTANCE = 29.268f;
+constexpr float CH3_SHUNT_RESISTANCE = 29.645f;
+constexpr float CH7_SHUNT_RESISTANCE = 29.708f;
 }  // namespace ADC_1
 
 namespace ADC_2
 {
+constexpr bool ENABLED = true;
+
 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 auto OX_TANK_PT_CHANNEL = Channel::CHANNEL_0;
+constexpr auto N2_TANK_PT_CHANNEL = Channel::CHANNEL_1;
 
-constexpr float CH0_SHUNT_RESISTANCE = 29.0;  // TODO: measure
-constexpr float CH1_SHUNT_RESISTANCE = 29.0;  // TODO: measure
+constexpr float CH0_SHUNT_RESISTANCE = 29.685f;
+constexpr float CH1_SHUNT_RESISTANCE = 29.625f;
 }  // namespace ADC_2
 
 namespace MAX31856
@@ -99,40 +104,36 @@ constexpr bool ENABLED = true;
 
 namespace Trafag
 {
-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 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_SHUNT_RESISTANCE    = ADC_2::CH0_SHUNT_RESISTANCE;
+constexpr float N2_TANK_SHUNT_RESISTANCE    = ADC_2::CH1_SHUNT_RESISTANCE;
 
 constexpr float MIN_CURRENT = 4;
 constexpr float MAX_CURRENT = 20;
 
-// 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
+constexpr float OX_VESSEL_MAX_PRESSURE  = 100;  // bar
+constexpr float OX_FILLING_MAX_PRESSURE = 100;  // bar
+constexpr float N2_VESSEL1_MAX_PRESSURE = 100;  // bar
+constexpr float N2_VESSEL2_MAX_PRESSURE = 100;  // bar
+constexpr float N2_FILLING_MAX_PRESSURE = 100;  // bar
+constexpr float OX_TANK_MAX_PRESSURE    = 100;  // bar
+constexpr float N2_TANK_MAX_PRESSURE    = 250;  // bar
 }  // namespace Trafag
 
 namespace LoadCell
 {
-constexpr unsigned int CALIBRATE_SAMPLE_COUNT  = 10;
-constexpr unsigned int CALIBRATE_SAMPLE_PERIOD = 40;
-
-// LC Tank sensor calibration data
-// - 1.866kg V: 0.000941
-// - 5.050kg V: 0.002550
-// - 6.916kg V: 0.003559
-constexpr float TANK_P0_VOLTAGE = 0.000941;
-constexpr float TANK_P0_MASS    = 1.866;
-constexpr float TANK_P1_VOLTAGE = 0.003559;
-constexpr float TANK_P1_MASS    = 6.916;
+constexpr auto CALIBRATE_SAMPLE_COUNT  = 10;
+constexpr auto CALIBRATE_SAMPLE_PERIOD = 40ms;
+
+// Rocket ramp loadcell calibration data
+constexpr float ROCKET_P0_VOLTAGE = -0.0004273;
+constexpr float ROCKET_P0_MASS    = 10.005;
+constexpr float ROCKET_P1_VOLTAGE = -0.0018125;
+constexpr float ROCKET_P1_MASS    = 40.290;
 
 /* OLD CALIBRATION DATA (before 07/09/2024, before new flipping)
 // LC Vessel sensor calibration data
diff --git a/src/RIGv2/Radio/Radio.cpp b/src/RIGv2/Radio/Radio.cpp
index 472eb5d10ec967853d538710de7c789db9abd39a..26bce81fea300e75fa65c225faa5ee18abdd254b 100644
--- a/src/RIGv2/Radio/Radio.cpp
+++ b/src/RIGv2/Radio/Radio.cpp
@@ -22,6 +22,7 @@
 
 #include "Radio.h"
 
+#include <ConRIGv2/Configs/RadioConfig.h>
 #include <common/Events.h>
 #include <common/Radio.h>
 #include <diagnostic/CpuMeter/CpuMeter.h>
@@ -98,27 +99,44 @@ bool Radio::start()
     return true;
 }
 
-void Radio::enqueuePacket(const mavlink_message_t& msg)
+void Radio::enqueueMessage(const mavlink_message_t& msg)
 {
-    queuedPackets.put(msg);
+    queuedMessages.put(msg);
 }
 
-void Radio::flushPackets()
+void Radio::flushMessages()
 {
-    // Flush all packets of the queue
-    size_t count =
-        std::min(queuedPackets.count(), Config::Radio::MAX_PACKETS_PER_FLUSH);
-    for (size_t i = 0; i < count; i++)
+    // Flush the maximum number of packets according to the bitrate
+    constexpr auto sendSlotDuration =
+        1.0f / ConRIGv2::Config::Radio::PING_GSE_PERIOD.value();  // [s]
+    constexpr auto maxFlushSize =
+        static_cast<size_t>(Config::Radio::BITRATE / 8 * sendSlotDuration);
+
+    try
     {
-        try
-        {
-            mavDriver->enqueueMsg(queuedPackets.pop());
-        }
-        catch (...)
+        size_t bytesSent = 0;
+
+        while (!queuedMessages.isEmpty())
         {
-            // This shouldn't happen, but still try to prevent it
+            auto& message      = queuedMessages.get();
+            auto messageLength = mavlink_msg_get_send_buffer_length(&message);
+            if (bytesSent + messageLength > maxFlushSize)
+                break;
+
+            bool enqueued = mavDriver->enqueueMsg(message);
+            // If we reached the maximum queue size, stop flushing
+            if (!enqueued)
+                break;
+
+            queuedMessages.pop();
+            bytesSent += messageLength;
         }
     }
+    catch (std::range_error& e)
+    {
+        // This shouldn't happen, but still try to prevent it
+        LOG_ERR(logger, "Error while flushing packets: %s", e.what());
+    }
 }
 
 void Radio::enqueueAck(const mavlink_message_t& msg)
@@ -127,7 +145,7 @@ void Radio::enqueueAck(const mavlink_message_t& msg)
     mavlink_msg_ack_tm_pack(Config::Radio::MAV_SYSTEM_ID,
                             Config::Radio::MAV_COMPONENT_ID, &ackMsg, msg.msgid,
                             msg.seq);
-    enqueuePacket(ackMsg);
+    enqueueMessage(ackMsg);
 }
 
 void Radio::enqueueNack(const mavlink_message_t& msg, uint8_t errorId)
@@ -136,7 +154,7 @@ void Radio::enqueueNack(const mavlink_message_t& msg, uint8_t errorId)
     mavlink_msg_nack_tm_pack(Config::Radio::MAV_SYSTEM_ID,
                              Config::Radio::MAV_COMPONENT_ID, &nackMsg,
                              msg.msgid, msg.seq, errorId);
-    enqueuePacket(nackMsg);
+    enqueueMessage(nackMsg);
 }
 
 void Radio::enqueueWack(const mavlink_message_t& msg, uint8_t errorId)
@@ -145,7 +163,7 @@ void Radio::enqueueWack(const mavlink_message_t& msg, uint8_t errorId)
     mavlink_msg_wack_tm_pack(Config::Radio::MAV_SYSTEM_ID,
                              Config::Radio::MAV_COMPONENT_ID, &wackMsg,
                              msg.msgid, msg.seq, errorId);
-    enqueuePacket(wackMsg);
+    enqueueMessage(wackMsg);
 }
 
 MavlinkStatus Radio::getMavStatus()
@@ -424,7 +442,7 @@ void Radio::enqueueRegistry()
                 }
             }
 
-            enqueuePacket(msg);
+            enqueueMessage(msg);
         });
 }
 
@@ -447,7 +465,7 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
                 mavlink_msg_sensor_state_tm_encode(
                     Config::Radio::MAV_SYSTEM_ID,
                     Config::Radio::MAV_COMPONENT_ID, &msg, &tm);
-                enqueuePacket(msg);
+                enqueueMessage(msg);
             }
 
             return true;
@@ -477,7 +495,7 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             mavlink_msg_sys_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                       Config::Radio::MAV_COMPONENT_ID, &msg,
                                       &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -503,7 +521,7 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             mavlink_msg_logger_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                          Config::Radio::MAV_COMPONENT_ID, &msg,
                                          &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -531,7 +549,7 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             mavlink_msg_mavlink_stats_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                                 Config::Radio::MAV_COMPONENT_ID,
                                                 &msg, &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -546,7 +564,7 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             tm.timestamp = TimestampTimer::getTimestamp();
 
             // Sensors
-            tm.rocket_mass    = sensors->getOxTankWeight().load;
+            tm.rocket_mass    = sensors->getRocketWeight().load;
             tm.ox_vessel_mass = sensors->getOxVesselWeight().load;
 
             tm.ox_vessel_pressure   = sensors->getOxVesselPressure().pressure;
@@ -621,7 +639,7 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             mavlink_msg_gse_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                       Config::Radio::MAV_COMPONENT_ID, &msg,
                                       &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -636,9 +654,11 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             tm.timestamp = TimestampTimer::getTimestamp();
 
             // Sensors (either CAN or local)
-            tm.ox_tank_top_pressure = sensors->getOxTankTopPressure().pressure;
+            tm.n2_tank_pressure = sensors->getN2TankPressure().pressure;
             tm.ox_tank_bot_pressure =
                 sensors->getOxTankBottomPressure().pressure;
+            tm.ox_tank_top_pressure =
+                sensors->getCanOxTankTopPressure().pressure;
             tm.combustion_chamber_pressure =
                 sensors->getCombustionChamberPressure().pressure;
             tm.ox_tank_temperature =
@@ -662,7 +682,7 @@ bool Radio::enqueueSystemTm(uint8_t tmId)
             mavlink_msg_motor_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                         Config::Radio::MAV_COMPONENT_ID, &msg,
                                         &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -706,7 +726,7 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             mavlink_msg_adc_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                       Config::Radio::MAV_COMPONENT_ID, &msg,
                                       &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
 
             data = getModule<Sensors>()->getADC2LastSample();
 
@@ -732,7 +752,7 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             mavlink_msg_adc_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                       Config::Radio::MAV_COMPONENT_ID, &msg,
                                       &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
 
             return true;
         }
@@ -746,12 +766,12 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
 
             tm.timestamp = data.pressureTimestamp;
             tm.pressure  = data.pressure;
-            strcpy(tm.sensor_name, "VesselPressure");
+            strcpy(tm.sensor_name, "OxVesselPressure");
 
             mavlink_msg_pressure_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                            Config::Radio::MAV_COMPONENT_ID,
                                            &msg, &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -764,12 +784,12 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
 
             tm.timestamp = data.pressureTimestamp;
             tm.pressure  = data.pressure;
-            strcpy(tm.sensor_name, "FillingPressure");
+            strcpy(tm.sensor_name, "OxFillingPressure");
 
             mavlink_msg_pressure_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                            Config::Radio::MAV_COMPONENT_ID,
                                            &msg, &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -782,12 +802,12 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
 
             tm.timestamp = data.pressureTimestamp;
             tm.pressure  = data.pressure;
-            strcpy(tm.sensor_name, "BottomTankPressure");
+            strcpy(tm.sensor_name, "OxTankBotPressure");
 
             mavlink_msg_pressure_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                            Config::Radio::MAV_COMPONENT_ID,
                                            &msg, &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -796,16 +816,16 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             mavlink_message_t msg;
             mavlink_pressure_tm_t tm;
 
-            PressureData data = getModule<Sensors>()->getOxTankTopPressure();
+            PressureData data = getModule<Sensors>()->getCanOxTankTopPressure();
 
             tm.timestamp = data.pressureTimestamp;
             tm.pressure  = data.pressure;
-            strcpy(tm.sensor_name, "TopTankPressure");
+            strcpy(tm.sensor_name, "OxTankTopPressure");
 
             mavlink_msg_pressure_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                            Config::Radio::MAV_COMPONENT_ID,
                                            &msg, &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -823,7 +843,7 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             mavlink_msg_temp_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                        Config::Radio::MAV_COMPONENT_ID, &msg,
                                        &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -836,12 +856,12 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
 
             tm.timestamp = data.loadTimestamp;
             tm.load      = data.load;
-            strcpy(tm.sensor_name, "VesselWeight");
+            strcpy(tm.sensor_name, "OxVesselWeight");
 
             mavlink_msg_load_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                        Config::Radio::MAV_COMPONENT_ID, &msg,
                                        &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -854,12 +874,12 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
 
             tm.timestamp = data.loadTimestamp;
             tm.load      = data.load;
-            strcpy(tm.sensor_name, "TankWeight");
+            strcpy(tm.sensor_name, "OxTankWeight");
 
             mavlink_msg_load_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                        Config::Radio::MAV_COMPONENT_ID, &msg,
                                        &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -877,7 +897,7 @@ bool Radio::enqueueSensorTm(uint8_t tmId)
             mavlink_msg_voltage_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                           Config::Radio::MAV_COMPONENT_ID, &msg,
                                           &tm);
-            enqueuePacket(msg);
+            enqueueMessage(msg);
             return true;
         }
 
@@ -892,14 +912,13 @@ void Radio::handleConrigState(const mavlink_message_t& msg)
 {
     // Acknowledge the state
     enqueueAck(msg);
-
-    // Flush all pending packets
-    flushPackets();
-
     // Send GSE and motor telemetry
     enqueueSystemTm(MAV_GSE_ID);
     enqueueSystemTm(MAV_MOTOR_ID);
 
+    // Flush all pending packets
+    flushMessages();
+
     mavlink_conrig_state_tc_t state;
     mavlink_msg_conrig_state_tc_decode(&msg, &state);
 
diff --git a/src/RIGv2/Radio/Radio.h b/src/RIGv2/Radio/Radio.h
index 37b61efd88fd975781b7d097e29bf8f486a774a1..935a9dcdb36f67417ffaa48e837a9c238ddcef4c 100644
--- a/src/RIGv2/Radio/Radio.h
+++ b/src/RIGv2/Radio/Radio.h
@@ -63,8 +63,8 @@ private:
     void enqueueWack(const mavlink_message_t& msg, uint8_t errorId);
     void enqueueNack(const mavlink_message_t& msg, uint8_t errorId);
 
-    void enqueuePacket(const mavlink_message_t& msg);
-    void flushPackets();
+    void enqueueMessage(const mavlink_message_t& msg);
+    void flushMessages();
 
     void handleMessage(const mavlink_message_t& msg);
     void handleCommand(const mavlink_message_t& msg);
@@ -80,7 +80,7 @@ private:
 
     Boardcore::CircularBuffer<mavlink_message_t,
                               Config::Radio::CIRCULAR_BUFFER_SIZE>
-        queuedPackets;
+        queuedMessages;
 
     std::atomic<bool> started{false};
     std::unique_ptr<Boardcore::SX1278Lora> radio;
diff --git a/src/RIGv2/Sensors/Sensors.cpp b/src/RIGv2/Sensors/Sensors.cpp
index a6f3aed8463e97951d09bc7171b119663598069a..89e22b6491d570854891dfbacd5a8ee3d65707e0 100644
--- a/src/RIGv2/Sensors/Sensors.cpp
+++ b/src/RIGv2/Sensors/Sensors.cpp
@@ -26,6 +26,9 @@
 #include <drivers/timer/TimestampTimer.h>
 #include <interfaces-impl/hwmapping.h>
 
+#include <chrono>
+
+using namespace std::chrono;
 using namespace Boardcore;
 using namespace miosix;
 using namespace RIGv2;
@@ -37,18 +40,26 @@ bool Sensors::start()
     if (Config::Sensors::InternalADC::ENABLED)
         internalAdcInit();
 
-    if (Config::Sensors::ADS131M08::ENABLED)
+    if (Config::Sensors::ADC_1::ENABLED)
     {
         adc1Init();
-        adc2Init();
         oxVesselPressureInit();
         oxFillingPressureInit();
-        oxTankTopPressureInit();
-        oxTankBottomPressureInit();
+        n2Vessel1PressureInit();
+        n2Vessel2PressureInit();
+        n2FillingPressureInit();
         oxVesselWeightInit();
+        rocketWeightInit();
         oxTankWeightInit();
     }
 
+    if (Config::Sensors::ADC_2::ENABLED)
+    {
+        adc2Init();
+        oxTankBottomPressureInit();
+        n2TankPressureInit();
+    }
+
     if (Config::Sensors::MAX31856::ENABLED)
         tc1Init();
 
@@ -112,29 +123,29 @@ PressureData Sensors::getN2FillingPressure()
                              : PressureData{};
 }
 
-PressureData Sensors::getOxTankTopPressure()
+PressureData Sensors::getOxTankBottomPressure()
 {
     if (useCanData)
     {
-        return getCanOxTankTopPressure();
+        return getCanOxTankBottomPressure();
     }
     else
     {
-        return oxTankTopPressure ? oxTankTopPressure->getLastSample()
-                                 : PressureData{};
+        return oxTankBottomPressure ? oxTankBottomPressure->getLastSample()
+                                    : PressureData{};
     }
 }
 
-PressureData Sensors::getOxTankBottomPressure()
+PressureData Sensors::getN2TankPressure()
 {
     if (useCanData)
     {
-        return getCanOxTankBottomPressure();
+        return getCanN2TankPressure();
     }
     else
     {
-        return oxTankBottomPressure ? oxTankBottomPressure->getLastSample()
-                                    : PressureData{};
+        return n2TankPressure ? n2TankPressure->getLastSample()
+                              : PressureData{};
     }
 }
 
@@ -156,18 +167,17 @@ TemperatureData Sensors::getOxTankTemperature()
 
 LoadCellData Sensors::getOxVesselWeight()
 {
-    if (oxVesselWeight)
-        return oxVesselWeight->getLastSample();
-    else
-        return {};
+    return oxVesselWeight ? oxVesselWeight->getLastSample() : LoadCellData{};
+}
+
+LoadCellData Sensors::getRocketWeight()
+{
+    return rocketWeight ? rocketWeight->getLastSample() : LoadCellData{};
 }
 
 LoadCellData Sensors::getOxTankWeight()
 {
-    if (oxTankWeight)
-        return oxTankWeight->getLastSample();
-    else
-        return {};
+    return oxTankWeight ? oxTankWeight->getLastSample() : LoadCellData{};
 }
 
 CurrentData Sensors::getUmbilicalCurrent()
@@ -207,13 +217,19 @@ VoltageData Sensors::getMotorBatteryVoltage()
         return VoltageData{};
 }
 
-PressureData Sensors::getCanOxTankTopPressure()
+PressureData Sensors::getCanN2TankPressure()
 {
     Lock<FastMutex> lock{canMutex};
-    return canOxTankBottomPressure;
+    return canN2TankPressure;
 }
 
 PressureData Sensors::getCanOxTankBottomPressure()
+{
+    Lock<FastMutex> lock{canMutex};
+    return canOxTankBottomPressure;
+}
+
+PressureData Sensors::getCanOxTankTopPressure()
 {
     Lock<FastMutex> lock{canMutex};
     return canOxTankTopPressure;
@@ -237,18 +253,24 @@ VoltageData Sensors::getCanMotorBatteryVoltage()
     return canMotorBatteryVoltage;
 }
 
-void Sensors::setCanOxTankTopPressure(PressureData data)
+void Sensors::setCanOxTankBottomPressure(PressureData data)
 {
     Lock<FastMutex> lock{canMutex};
     canOxTankBottomPressure = data;
 }
 
-void Sensors::setCanOxTankBottomPressure(PressureData data)
+void Sensors::setCanOxTankTopPressure(PressureData data)
 {
     Lock<FastMutex> lock{canMutex};
     canOxTankTopPressure = data;
 }
 
+void Sensors::setCanN2TankPressure(PressureData data)
+{
+    Lock<FastMutex> lock{canMutex};
+    canN2TankPressure = data;
+}
+
 void Sensors::setCanCombustionChamberPressure(PressureData data)
 {
     Lock<FastMutex> lock{canMutex};
@@ -280,7 +302,9 @@ void Sensors::calibrate()
         oxVesselStats.add(oxVesselWeight->getLastSample().load);
         oxTankStats.add(oxTankWeight->getLastSample().load);
 
-        Thread::sleep(Config::Sensors::LoadCell::CALIBRATE_SAMPLE_PERIOD);
+        Thread::sleep(
+            milliseconds{Config::Sensors::LoadCell::CALIBRATE_SAMPLE_PERIOD}
+                .count());
     }
 
     oxVesselWeight->updateOffset(oxVesselStats.getStats().mean);
@@ -297,20 +321,21 @@ std::vector<SensorInfo> Sensors::getSensorInfos()
     if (instance)                                                \
         infos.push_back(manager->getSensorInfo(instance.get())); \
     else                                                         \
-        infos.push_back(SensorInfo { #name, 0, nullptr, false })
+        infos.push_back(SensorInfo{name, 0ns, nullptr, false})
 
-        PUSH_SENSOR_INFO(adc1, "ADC1");
-        PUSH_SENSOR_INFO(adc2, "ADC2");
-        PUSH_SENSOR_INFO(tc1, "TC1");
+        PUSH_SENSOR_INFO(adc1, "ADS131M08_1");
+        PUSH_SENSOR_INFO(adc2, "ADS131M08_2");
+        PUSH_SENSOR_INFO(tc1, "MAX31856_1");
         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(n2TankPressure, "N2TankPressure");
         PUSH_SENSOR_INFO(oxVesselWeight, "OxVesselWeight");
+        PUSH_SENSOR_INFO(rocketWeight, "RocketWeight");
         PUSH_SENSOR_INFO(oxTankWeight, "OxTankWeight");
 
         return infos;
@@ -391,7 +416,7 @@ void Sensors::adc1Init()
         .offset  = 0,
         .gain    = 1.0};
 
-    config.channelsConfig[(int)Config::Sensors::ADC_1::OX_TANK_LC_CHANNEL] = {
+    config.channelsConfig[(int)Config::Sensors::ADC_1::ROCKET_LC_CHANNEL] = {
         .enabled = true,
         .pga     = ADS131M08Defs::PGA::PGA_32,
         .offset  = 0,
@@ -427,14 +452,13 @@ void Sensors::adc2Init()
         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_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] = {
+    config.channelsConfig[(int)Config::Sensors::ADC_2::N2_TANK_PT_CHANNEL] = {
         .enabled = true,
         .pga     = ADS131M08Defs::PGA::PGA_1,
         .offset  = 0,
@@ -559,45 +583,44 @@ void Sensors::n2FillingPressureCallback()
     sdLogger.log(N2FillingPressureData{getN2FillingPressure()});
 }
 
-void Sensors::oxTankTopPressureInit()
+void Sensors::oxTankBottomPressureInit()
 {
-    oxTankTopPressure = std::make_unique<TrafagPressureSensor>(
+    oxTankBottomPressure = std::make_unique<TrafagPressureSensor>(
         [this]()
         {
             auto sample = getADC2LastSample();
             return sample.getVoltage(
-                Config::Sensors::ADC_2::OX_TANK_TOP_PT_CHANNEL);
+                Config::Sensors::ADC_2::OX_TANK_PT_CHANNEL);
         },
-        Config::Sensors::Trafag::OX_TANK_TOP_SHUNT_RESISTANCE,
-        Config::Sensors::Trafag::OX_TANK_TOP_MAX_PRESSURE,
+        Config::Sensors::Trafag::OX_TANK_SHUNT_RESISTANCE,
+        Config::Sensors::Trafag::OX_TANK_MAX_PRESSURE,
         Config::Sensors::Trafag::MIN_CURRENT,
         Config::Sensors::Trafag::MAX_CURRENT);
 }
 
-void Sensors::oxTankTopPressureCallback()
+void Sensors::oxTankBottomPressureCallback()
 {
-    sdLogger.log(OxTankTopPressureData{oxTankTopPressure->getLastSample()});
+    sdLogger.log(OxTankPressureData{oxTankBottomPressure->getLastSample()});
 }
 
-void Sensors::oxTankBottomPressureInit()
+void Sensors::n2TankPressureInit()
 {
-    oxTankBottomPressure = std::make_unique<TrafagPressureSensor>(
+    n2TankPressure = std::make_unique<TrafagPressureSensor>(
         [this]()
         {
             auto sample = getADC2LastSample();
             return sample.getVoltage(
-                Config::Sensors::ADC_2::OX_TANK_BOTTOM_PT_CHANNEL);
+                Config::Sensors::ADC_2::N2_TANK_PT_CHANNEL);
         },
-        Config::Sensors::Trafag::OX_TANK_BOTTOM_SHUNT_RESISTANCE,
-        Config::Sensors::Trafag::OX_TANK_BOTTOM_MAX_PRESSURE,
+        Config::Sensors::Trafag::N2_TANK_SHUNT_RESISTANCE,
+        Config::Sensors::Trafag::N2_TANK_MAX_PRESSURE,
         Config::Sensors::Trafag::MIN_CURRENT,
         Config::Sensors::Trafag::MAX_CURRENT);
 }
 
-void Sensors::oxTankBottomPressureCallback()
+void Sensors::n2TankPressureCallback()
 {
-    sdLogger.log(
-        OxTankBottomPressureData{oxTankBottomPressure->getLastSample()});
+    sdLogger.log(N2TankPressureData{n2TankPressure->getLastSample()});
 }
 
 void Sensors::oxVesselWeightInit()
@@ -620,19 +643,37 @@ void Sensors::oxVesselWeightCallback()
     sdLogger.log(OxVesselWeightData{getOxVesselWeight()});
 }
 
+void Sensors::rocketWeightInit()
+{
+    rocketWeight = std::make_unique<TwoPointAnalogLoadCell>(
+        [this]()
+        {
+            auto sample = getADC1LastSample();
+            return sample.getVoltage(Config::Sensors::ADC_1::ROCKET_LC_CHANNEL);
+        },
+        Config::Sensors::LoadCell::ROCKET_P0_VOLTAGE,
+        Config::Sensors::LoadCell::ROCKET_P0_MASS,
+        Config::Sensors::LoadCell::ROCKET_P1_VOLTAGE,
+        Config::Sensors::LoadCell::ROCKET_P1_MASS);
+}
+
+void Sensors::rocketWeightCallback()
+{
+    sdLogger.log(RocketWeightData{getRocketWeight()});
+}
+
 void Sensors::oxTankWeightInit()
 {
     oxTankWeight = std::make_unique<TwoPointAnalogLoadCell>(
         [this]()
         {
             auto sample = getADC1LastSample();
-            return sample.getVoltage(
-                Config::Sensors::ADC_1::OX_TANK_LC_CHANNEL);
+            return sample.getVoltage(Config::Sensors::ADC_1::ROCKET_LC_CHANNEL);
         },
-        Config::Sensors::LoadCell::TANK_P0_VOLTAGE,
-        Config::Sensors::LoadCell::TANK_P0_MASS,
-        Config::Sensors::LoadCell::TANK_P1_VOLTAGE,
-        Config::Sensors::LoadCell::TANK_P1_MASS);
+        Config::Sensors::LoadCell::ROCKET_P0_VOLTAGE,
+        Config::Sensors::LoadCell::ROCKET_P0_MASS,
+        Config::Sensors::LoadCell::ROCKET_P1_VOLTAGE,
+        Config::Sensors::LoadCell::ROCKET_P1_MASS);
 }
 
 void Sensors::oxTankWeightCallback()
@@ -710,13 +751,6 @@ bool Sensors::sensorManagerInit()
         map.emplace(std::make_pair(n2FillingPressure.get(), info));
     }
 
-    if (oxTankTopPressure)
-    {
-        SensorInfo info("OxTankTopPressure", Config::Sensors::ADS131M08::PERIOD,
-                        [this]() { oxTankTopPressureCallback(); });
-        map.emplace(std::make_pair(oxTankTopPressure.get(), info));
-    }
-
     if (oxTankBottomPressure)
     {
         SensorInfo info("OxTankBotPressure", Config::Sensors::ADS131M08::PERIOD,
@@ -724,6 +758,13 @@ bool Sensors::sensorManagerInit()
         map.emplace(std::make_pair(oxTankBottomPressure.get(), info));
     }
 
+    if (n2TankPressure)
+    {
+        SensorInfo info("N2TankPressure", Config::Sensors::ADS131M08::PERIOD,
+                        [this]() { n2TankPressureCallback(); });
+        map.emplace(std::make_pair(n2TankPressure.get(), info));
+    }
+
     if (oxVesselWeight)
     {
         SensorInfo info("OxVesselWeight", Config::Sensors::ADS131M08::PERIOD,
@@ -731,6 +772,13 @@ bool Sensors::sensorManagerInit()
         map.emplace(std::make_pair(oxVesselWeight.get(), info));
     }
 
+    if (rocketWeight)
+    {
+        SensorInfo info("RocketWeight", Config::Sensors::ADS131M08::PERIOD,
+                        [this]() { rocketWeightCallback(); });
+        map.emplace(std::make_pair(rocketWeight.get(), info));
+    }
+
     if (oxTankWeight)
     {
         SensorInfo info("OxTankWeight", Config::Sensors::ADS131M08::PERIOD,
diff --git a/src/RIGv2/Sensors/Sensors.h b/src/RIGv2/Sensors/Sensors.h
index 06a5ceb1f46d841d454c63717cfd155ad9a94bd5..1c3a2dba87df1e64dbcb8e8f37818a3ff220ec81 100644
--- a/src/RIGv2/Sensors/Sensors.h
+++ b/src/RIGv2/Sensors/Sensors.h
@@ -64,12 +64,13 @@ public:
     Boardcore::PressureData getN2Vessel1Pressure();
     Boardcore::PressureData getN2Vessel2Pressure();
     Boardcore::PressureData getN2FillingPressure();
-    Boardcore::PressureData getOxTankTopPressure();
     Boardcore::PressureData getOxTankBottomPressure();
+    Boardcore::PressureData getN2TankPressure();
     Boardcore::PressureData getCombustionChamberPressure();
 
     Boardcore::TemperatureData getOxTankTemperature();
     Boardcore::LoadCellData getOxVesselWeight();
+    Boardcore::LoadCellData getRocketWeight();
     Boardcore::LoadCellData getOxTankWeight();
 
     Boardcore::CurrentData getUmbilicalCurrent();
@@ -77,16 +78,18 @@ public:
     Boardcore::VoltageData getBatteryVoltage();
     Boardcore::VoltageData getMotorBatteryVoltage();
 
-    Boardcore::PressureData getCanOxTankTopPressure();
     Boardcore::PressureData getCanOxTankBottomPressure();
+    Boardcore::PressureData getCanOxTankTopPressure();
+    Boardcore::PressureData getCanN2TankPressure();
     Boardcore::PressureData getCanCombustionChamberPressure();
     Boardcore::TemperatureData getCanTankTemperature();
     Boardcore::VoltageData getCanMotorBatteryVoltage();
 
     std::vector<Boardcore::SensorInfo> getSensorInfos();
 
-    void setCanOxTankTopPressure(Boardcore::PressureData data);
     void setCanOxTankBottomPressure(Boardcore::PressureData data);
+    void setCanOxTankTopPressure(Boardcore::PressureData data);
+    void setCanN2TankPressure(Boardcore::PressureData data);
     void setCanCombustionChamberPressure(Boardcore::PressureData data);
     void setCanOxTankTemperature(Boardcore::TemperatureData data);
     void setCanMotorBatteryVoltage(Boardcore::VoltageData data);
@@ -108,15 +111,18 @@ private:
     void n2FillingPressureInit();
     void n2FillingPressureCallback();
 
-    void oxTankTopPressureInit();
-    void oxTankTopPressureCallback();
-
     void oxTankBottomPressureInit();
     void oxTankBottomPressureCallback();
 
+    void n2TankPressureInit();
+    void n2TankPressureCallback();
+
     void oxVesselWeightInit();
     void oxVesselWeightCallback();
 
+    void rocketWeightInit();
+    void rocketWeightCallback();
+
     void oxTankWeightInit();
     void oxTankWeightCallback();
 
@@ -142,8 +148,9 @@ private:
     std::atomic<bool> useCanData{false};
     miosix::FastMutex canMutex;
 
-    Boardcore::PressureData canOxTankTopPressure;
     Boardcore::PressureData canOxTankBottomPressure;
+    Boardcore::PressureData canOxTankTopPressure;
+    Boardcore::PressureData canN2TankPressure;
     Boardcore::PressureData canCombustionChamberPressure;
     // TODO: N2 tank pressure from CAN
     Boardcore::TemperatureData canOxTankTemperature;
@@ -155,9 +162,10 @@ private:
     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::TrafagPressureSensor> n2TankPressure;
     std::unique_ptr<Boardcore::TwoPointAnalogLoadCell> oxVesselWeight;
+    std::unique_ptr<Boardcore::TwoPointAnalogLoadCell> rocketWeight;
     std::unique_ptr<Boardcore::TwoPointAnalogLoadCell> oxTankWeight;
 
     // Digital sensors
diff --git a/src/RIGv2/Sensors/SensorsData.h b/src/RIGv2/Sensors/SensorsData.h
index c598c0a2a0f9d87e8fc19f7e0df682450a0a194b..ad36d2177c828ca97d50d0856eaf92c3f5032216 100644
--- a/src/RIGv2/Sensors/SensorsData.h
+++ b/src/RIGv2/Sensors/SensorsData.h
@@ -69,6 +69,16 @@ struct OxVesselWeightData : Boardcore::LoadCellData
     OxVesselWeightData() {}
 };
 
+struct RocketWeightData : Boardcore::LoadCellData
+{
+    explicit RocketWeightData(const Boardcore::LoadCellData& data)
+        : Boardcore::LoadCellData(data)
+    {
+    }
+
+    RocketWeightData() {}
+};
+
 struct OxTankWeightData : Boardcore::LoadCellData
 {
     explicit OxTankWeightData(const Boardcore::LoadCellData& data)
@@ -129,24 +139,24 @@ struct N2FillingPressureData : Boardcore::PressureData
     N2FillingPressureData() {}
 };
 
-struct OxTankTopPressureData : Boardcore::PressureData
+struct OxTankPressureData : Boardcore::PressureData
 {
-    explicit OxTankTopPressureData(const Boardcore::PressureData& data)
+    explicit OxTankPressureData(const Boardcore::PressureData& data)
         : Boardcore::PressureData(data)
     {
     }
 
-    OxTankTopPressureData() {}
+    OxTankPressureData() {}
 };
 
-struct OxTankBottomPressureData : Boardcore::PressureData
+struct N2TankPressureData : Boardcore::PressureData
 {
-    explicit OxTankBottomPressureData(const Boardcore::PressureData& data)
+    explicit N2TankPressureData(const Boardcore::PressureData& data)
         : Boardcore::PressureData(data)
     {
     }
 
-    OxTankBottomPressureData() {}
+    N2TankPressureData() {}
 };
 
 }  // namespace RIGv2
diff --git a/src/RIGv2/rig-v2-adc-test.cpp b/src/RIGv2/rig-v2-adc-test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..5dda0ffe7cbf0b5b609531a14a9f65eb94deb90a
--- /dev/null
+++ b/src/RIGv2/rig-v2-adc-test.cpp
@@ -0,0 +1,275 @@
+/* Copyright (c) 2024 Skyward Experimental Rocketry
+ * Authors: Davide Mor
+ *
+ * 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.
+ */
+
+#include <RIGv2/Actuators/Actuators.h>
+#include <RIGv2/BoardScheduler.h>
+#include <RIGv2/Buses.h>
+#include <RIGv2/CanHandler/CanHandler.h>
+#include <RIGv2/Radio/Radio.h>
+#include <RIGv2/Registry/Registry.h>
+#include <RIGv2/Sensors/Sensors.h>
+#include <RIGv2/StateMachines/GroundModeManager/GroundModeManager.h>
+#include <RIGv2/StateMachines/TARS1/TARS1.h>
+#include <common/Events.h>
+#include <diagnostic/CpuMeter/CpuMeter.h>
+#include <diagnostic/StackLogger.h>
+#include <drivers/timer/TimestampTimer.h>
+#include <events/EventBroker.h>
+#include <events/EventData.h>
+#include <events/utils/EventSniffer.h>
+
+#include <chrono>
+#include <iomanip>
+#include <iostream>
+#include <thread>
+
+using namespace std::chrono;
+using namespace Boardcore;
+using namespace Common;
+using namespace RIGv2;
+using namespace miosix;
+
+int main()
+{
+    DependencyManager manager;
+
+    Buses* buses              = new Buses();
+    BoardScheduler* scheduler = new BoardScheduler();
+
+    Sensors* sensors       = new Sensors();
+    Actuators* actuators   = new Actuators();
+    Registry* registry     = new Registry();
+    CanHandler* canHandler = new CanHandler();
+    GroundModeManager* gmm = new GroundModeManager();
+    TARS1* tars1           = new TARS1();
+    Radio* radio           = new Radio();
+
+    Logger& sdLogger    = Logger::getInstance();
+    EventBroker& broker = EventBroker::getInstance();
+
+    // Setup event sniffer
+    EventSniffer sniffer(broker,
+                         [&](uint8_t event, uint8_t topic)
+                         {
+                             EventData data{TimestampTimer::getTimestamp(),
+                                            event, topic};
+                             sdLogger.log(data);
+                         });
+
+    // Insert modules
+    bool initResult = manager.insert<Buses>(buses) &&
+                      manager.insert<BoardScheduler>(scheduler) &&
+                      manager.insert<Actuators>(actuators) &&
+                      manager.insert<Sensors>(sensors) &&
+                      manager.insert<Radio>(radio) &&
+                      manager.insert<CanHandler>(canHandler) &&
+                      manager.insert<Registry>(registry) &&
+                      manager.insert<GroundModeManager>(gmm) &&
+                      manager.insert<TARS1>(tars1) && manager.inject();
+
+    if (!initResult)
+    {
+        std::cout << "Failed to inject dependencies" << std::endl;
+        return 0;
+    }
+
+    // Status led indicators
+    // led1: Sensors ok
+    // led2: Radio ok
+    // led3: CanBus ok
+    // led4: Everything ok
+
+    // Start modules
+    std::cout << "Starting EventBroker" << std::endl;
+    if (!broker.start())
+    {
+        initResult = false;
+        std::cout << "*** Failed to start EventBroker ***" << std::endl;
+    }
+
+    std::cout << "Starting Registry" << std::endl;
+    if (!registry->start())
+    {
+        initResult = false;
+        std::cout << "*** Failed to start Registry ***" << std::endl;
+    }
+
+    // Perform an initial registry load
+    std::cout << "Loading backed registry" << std::endl;
+    if (registry->load() != RegistryError::OK)
+        std::cout << "* Warning: could not load a saved registry *"
+                  << std::endl;
+
+    std::cout << "Starting Actuators" << std::endl;
+    if (!actuators->start())
+    {
+        initResult = false;
+        std::cout << "*** Failed to start Actuators ***" << std::endl;
+    }
+
+    std::cout << "Starting Sensors" << std::endl;
+    if (!sensors->start())
+    {
+        initResult = false;
+        std::cout << "*** Failed to start Sensors ***" << std::endl;
+    }
+    else
+    {
+        led1On();
+    }
+
+    std::cout << "Starting Radio" << std::endl;
+    if (!radio->start())
+    {
+        initResult = false;
+        std::cout << "*** Failed to start Radio ***" << std::endl;
+    }
+    else
+    {
+        led2On();
+    }
+
+    std::cout << "Starting CanHandler" << std::endl;
+    if (!canHandler->start())
+    {
+        initResult = false;
+        std::cout << "*** Failed to start CanHandler ***" << std::endl;
+    }
+    else
+    {
+        led3On();
+    }
+
+    std::cout << "Starting GroundModeManager" << std::endl;
+    if (!gmm->start())
+    {
+        initResult = false;
+        std::cout << "*** Failed to start GroundModeManager ***" << std::endl;
+    }
+
+    std::cout << "Starting TARS1" << std::endl;
+    if (!tars1->start())
+    {
+        initResult = false;
+        std::cout << "*** Failed to start TARS1 ***" << std::endl;
+    }
+
+    std::cout << "Starting BoardScheduler" << std::endl;
+    if (!scheduler->start())
+    {
+        initResult = false;
+        std::cout << "*** Failed to start BoardScheduler ***" << std::endl;
+    }
+
+    // Start logging when system boots
+    std::cout << "Starting Logger" << std::endl;
+    if (!sdLogger.start())
+    {
+        initResult = false;
+        std::cout << "*** Failed to start Logger ***" << std::endl;
+    }
+    else
+    {
+        sdLogger.resetStats();
+        std::cout << "Logger Ok!\n"
+                  << "\tLog number: " << sdLogger.getStats().logNumber
+                  << std::endl;
+    }
+
+    if (initResult)
+    {
+        broker.post(FMM_INIT_OK, TOPIC_MOTOR);
+        std::cout << "All good!" << std::endl;
+        led4On();
+    }
+    else
+    {
+        broker.post(FMM_INIT_ERROR, TOPIC_MOTOR);
+        std::cout << "*** Init failure ***" << std::endl;
+    }
+
+    std::cout << "Sensor status:" << std::endl;
+    for (auto info : sensors->getSensorInfos())
+    {
+        // The period being 0 means the sensor is disabled
+        auto statusStr = info.period == 0ns   ? "Disabled"
+                         : info.isInitialized ? "Ok"
+                                              : "Error";
+
+        std::cout << "\t" << std::setw(20) << std::left << info.id << " "
+                  << statusStr << std::endl;
+    }
+
+    ADS131M08Data avg{};
+    size_t count = 0;
+
+    std::atomic<bool> reset{false};
+
+    std::thread inputHandler = std::thread(
+        [&]()
+        {
+            while (true)
+            {
+                char command{};
+                std::cin >> command;
+
+                if (command == 'r')
+                    reset = true;
+            }
+        });
+
+    while (true)
+    {
+        Thread::sleep(10);
+
+        // Choose the ADC to sample here
+        auto sample = sensors->getADC1LastSample();
+
+        if (reset == true)
+        {
+            avg   = {};
+            count = 0;
+            reset = false;
+            std::cout << "*** Resetting moving average ***\n";
+        }
+
+        // Perform moving average
+        count++;
+        for (int i = 0; i < 8; i++)
+            avg.voltage[i] += (sample.voltage[i] - avg.voltage[i]) / count;
+
+        if (count % 100 != 0)
+            continue;
+
+        std::cout << std::setw(7) << count;
+        for (int i = 0; i < 8; i++)
+        {
+            auto millivolts = avg.voltage[i] * 1000.0f;
+
+            std::cout << "| CH " << i << ": " << std::setw(10) << std::fixed
+                      << millivolts << "mV ";
+        }
+        std::cout << '\n';
+    }
+
+    return 0;
+}
diff --git a/src/RIGv2/rig-v2-entry.cpp b/src/RIGv2/rig-v2-entry.cpp
index b8ec84e95f5c374fc1cbf0caed1bce28ce6375f1..6548c191f8c6863add690115be2c3471a51d389e 100644
--- a/src/RIGv2/rig-v2-entry.cpp
+++ b/src/RIGv2/rig-v2-entry.cpp
@@ -37,9 +37,11 @@
 #include <events/EventData.h>
 #include <events/utils/EventSniffer.h>
 
+#include <chrono>
 #include <iomanip>
 #include <iostream>
 
+using namespace std::chrono;
 using namespace Boardcore;
 using namespace Common;
 using namespace RIGv2;
@@ -83,8 +85,6 @@ int main()
                       manager.insert<GroundModeManager>(gmm) &&
                       manager.insert<TARS1>(tars1) && manager.inject();
 
-    manager.graphviz(std::cout);
-
     if (!initResult)
     {
         std::cout << "Failed to inject dependencies" << std::endl;
@@ -115,7 +115,8 @@ int main()
     // Perform an initial registry load
     std::cout << "Loading backed registry" << std::endl;
     if (registry->load() != RegistryError::OK)
-        std::cout << "*** Failed to load backed registry ***" << std::endl;
+        std::cout << "* Warning: could not load a saved registry *"
+                  << std::endl;
 
     std::cout << "Starting Actuators" << std::endl;
     if (!actuators->start())
@@ -208,11 +209,12 @@ int main()
     std::cout << "Sensor status:" << std::endl;
     for (auto info : sensors->getSensorInfos())
     {
-        auto statusStr = !info.isEnabled      ? "Disabled"
+        // The period being 0 means the sensor is disabled
+        auto statusStr = info.period == 0ns   ? "Disabled"
                          : info.isInitialized ? "Ok"
                                               : "Error";
 
-        std::cout << "\t" << std::setw(16) << std::left << info.id << " "
+        std::cout << "\t" << std::setw(20) << std::left << info.id << " "
                   << statusStr << std::endl;
     }