diff --git a/src/boards/RIGv2/Actuators/Actuators.cpp b/src/boards/RIGv2/Actuators/Actuators.cpp
index 62a214341945a756e752e92f672dedf8970e6d56..10cf616a9774265eb2cc0e21a2629a807705f756 100644
--- a/src/boards/RIGv2/Actuators/Actuators.cpp
+++ b/src/boards/RIGv2/Actuators/Actuators.cpp
@@ -213,6 +213,18 @@ bool Actuators::setOpeningTime(ServosList servo, uint64_t time)
     return true;
 }
 
+bool Actuators::isServoOpen(ServosList servo)
+{
+    Lock<FastMutex> lock(infosMutex);
+    ServoInfo *info = getServo(servo);
+    if (info == nullptr)
+    {
+        return false;
+    }
+
+    return info->servo->getPosition() > Config::Servos::SERVO_OPEN_THRESHOLD;
+}
+
 void Actuators::openServoInner(ServoInfo *info, uint64_t time)
 {
     long long currentTime = getTime();
diff --git a/src/boards/RIGv2/Actuators/Actuators.h b/src/boards/RIGv2/Actuators/Actuators.h
index f443cf348e053b91684fd165330276c13ed6ac26..ab3ecb80dc1c9b34af0e5a31827ce09cd96cbfa6 100644
--- a/src/boards/RIGv2/Actuators/Actuators.h
+++ b/src/boards/RIGv2/Actuators/Actuators.h
@@ -68,6 +68,7 @@ public:
     bool openServoAtomic(ServosList servo, uint64_t time);
     bool setMaxAperture(ServosList servo, float aperture);
     bool setOpeningTime(ServosList servo, uint64_t time);
+    bool isServoOpen(ServosList servo);
 
 private:
     ServoInfo *getServo(ServosList servo);
diff --git a/src/boards/RIGv2/Configs/ActuatorsConfig.h b/src/boards/RIGv2/Configs/ActuatorsConfig.h
index b29b1655b38128bc8e1ae10affcf9a4940a7e7c6..979d69ed92b22ac0c580f89b4c9dd5b838bb237d 100644
--- a/src/boards/RIGv2/Configs/ActuatorsConfig.h
+++ b/src/boards/RIGv2/Configs/ActuatorsConfig.h
@@ -36,8 +36,10 @@ static constexpr unsigned int MIN_PULSE = 500;
 static constexpr unsigned int MAX_PULSE = 2500;
 
 static constexpr uint32_t SERVO_TIMINGS_CHECK_PERIOD = 100;
-static constexpr long long SERVO_CONFIDENCE_TIME     = 500;       // 0.5s
-static constexpr float SERVO_CONFIDENCE              = 1 / 50.0;  // 2%
+static constexpr long long SERVO_CONFIDENCE_TIME     = 500;   // 0.5s
+static constexpr float SERVO_CONFIDENCE              = 0.02;  // 2%
+// More than 10% is considered open
+static constexpr float SERVO_OPEN_THRESHOLD = 0.10;  // 10%
 
 static constexpr uint32_t DEFAULT_FILLING_OPENING_TIME    = 15000;  // 15s
 static constexpr uint32_t DEFAULT_VENTING_OPENING_TIME    = 15000;  // 15s
diff --git a/src/boards/RIGv2/Configs/SensorsConfig.h b/src/boards/RIGv2/Configs/SensorsConfig.h
index 28712cd8f496f7b662f29ab88cdc5019eb6c7ddc..5ccb05156c07a9e9cdc11ec889dda77ddb5ed8bb 100644
--- a/src/boards/RIGv2/Configs/SensorsConfig.h
+++ b/src/boards/RIGv2/Configs/SensorsConfig.h
@@ -36,6 +36,22 @@ namespace Sensors
 static constexpr uint32_t ADC_SAMPLE_PERIOD = 10;
 static constexpr uint32_t TC_SAMPLE_PERIOD = 100;
 
+static constexpr float ADC1_CH1_SHUNT_RESISTANCE = 30;
+static constexpr float ADC1_CH2_SHUNT_RESISTANCE = 30;
+static constexpr float ADC1_CH3_SHUNT_RESISTANCE = 30;
+static constexpr float ADC1_CH4_SHUNT_RESISTANCE = 30;
+
+static constexpr float PT_MIN_CURRENT = 4;
+static constexpr float PT_MAX_CURRENT = 20;
+
+static constexpr float FILLING_MAX_PRESSURE     = 100;  // bar
+static constexpr float TANK_TOP_MAX_PRESSURE    = 100;  // bar
+static constexpr float TANK_BOTTOM_MAX_PRESSURE = 100;  // bar
+static constexpr float VESSEL_MAX_PRESSURE      = 400;  // bar
+
+static constexpr unsigned int LC_CALIBRATE_SAMPLE_COUNT = 10;
+static constexpr unsigned int LC_CALIBRATE_SAMPLE_PERIOD = 40;
+
 }
 
 }  // namespace Config
diff --git a/src/boards/RIGv2/Radio/Radio.cpp b/src/boards/RIGv2/Radio/Radio.cpp
index a4f98607e3a86b1b425ef943e4ca0a25723a517e..9e98aa18cc48cb33e8b5845e40f777e1d3ebcfa1 100644
--- a/src/boards/RIGv2/Radio/Radio.cpp
+++ b/src/boards/RIGv2/Radio/Radio.cpp
@@ -262,7 +262,8 @@ void Radio::handleMessage(const mavlink_message_t& msg)
 
 void Radio::handleCommand(const mavlink_message_t& msg)
 {
-    uint8_t cmd = mavlink_msg_command_tc_get_command_id(&msg);
+    ModuleManager& modules = ModuleManager::getInstance();
+    uint8_t cmd            = mavlink_msg_command_tc_get_command_id(&msg);
     switch (cmd)
     {
         case MAV_CMD_START_LOGGING:
@@ -287,8 +288,8 @@ void Radio::handleCommand(const mavlink_message_t& msg)
 
         case MAV_CMD_CALIBRATE:
         {
-            // TODO: Implement calibrate
-            sendNack(msg);
+            modules.get<Sensors>()->calibrate();
+            sendAck(msg);
             break;
         }
 
@@ -378,9 +379,22 @@ bool Radio::packSystemTm(uint8_t tmId, mavlink_message_t& msg)
         {
             mavlink_gse_tm_t tm = {0};
 
-            tm.timestamp       = TimestampTimer::getTimestamp();
-            tm.loadcell_rocket = 69;
-            tm.loadcell_vessel = 420;
+            Sensors* sensors     = modules.get<Sensors>();
+            Actuators* actuators = modules.get<Actuators>();
+
+            tm.timestamp        = TimestampTimer::getTimestamp();
+            tm.loadcell_rocket  = sensors->getTankWeight().load;
+            tm.loadcell_vessel  = sensors->getVesselWeight().load;
+            tm.filling_pressure = sensors->getFillingPress().pressure;
+            tm.vessel_pressure  = sensors->getVesselPress().pressure;
+            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.main_valve_state =
+                actuators->isServoOpen(ServosList::MAIN_VALVE) ? 1 : 0;
             // TODO(davide.mor): Add the rest of these
 
             mavlink_msg_gse_tm_encode(Config::Radio::MAV_SYSTEM_ID,
@@ -391,14 +405,16 @@ bool Radio::packSystemTm(uint8_t tmId, mavlink_message_t& msg)
 
         case MAV_MOTOR_ID:
         {
-            mavlink_motor_tm_t tm;
+            mavlink_motor_tm_t tm = {0};
 
-            auto tc1 = modules.get<Sensors>()->getTc1LastSample();
+            Sensors* sensors = modules.get<Sensors>();
 
             tm.timestamp            = TimestampTimer::getTimestamp();
-            tm.tank_temperature     = tc1.temperature;
-            tm.top_tank_pressure    = 69;
-            tm.bottom_tank_pressure = 420;
+            tm.tank_temperature     = sensors->getTc1LastSample().temperature;
+            tm.top_tank_pressure    = sensors->getTankTopPress().pressure;
+            tm.bottom_tank_pressure = sensors->getTankBottomPress().pressure;
+            tm.floating_level       = 69.0f;  // Lol
+            // TODO(davide.mor): Add the rest of these
 
             mavlink_msg_motor_tm_encode(Config::Radio::MAV_SYSTEM_ID,
                                         Config::Radio::MAV_COMPONENT_ID, &msg,
@@ -439,21 +455,25 @@ void Radio::handleConrigState(const mavlink_message_t& msg)
             (Config::Radio::LAST_COMMAND_THRESHOLD * Constants::NS_IN_MS))
     {
         // Ok we can accept new commands
-        if(oldConrigState.arm_switch == 0 && state.arm_switch == 1) {
+        if (oldConrigState.arm_switch == 0 && state.arm_switch == 1)
+        {
             // The ARM switch was pressed
             // TODO(davide.mor): Arm the system
 
             lastManualActuation = currentTime;
         }
 
-        if(oldConrigState.ignition_btn == 0 && state.ignition_btn == 1) {
+        if (oldConrigState.ignition_btn == 0 && state.ignition_btn == 1)
+        {
             // The ignition switch was pressed
             // TODO(davide.mor): Perform ignition
 
             lastManualActuation = currentTime;
         }
 
-        if(oldConrigState.filling_valve_btn == 0 && state.filling_valve_btn == 1) {
+        if (oldConrigState.filling_valve_btn == 0 &&
+            state.filling_valve_btn == 1)
+        {
             // The filling switch was pressed
             // TODO(davide.mor): Notify everybody of a manual actuation
 
@@ -462,7 +482,9 @@ void Radio::handleConrigState(const mavlink_message_t& msg)
             lastManualActuation = currentTime;
         }
 
-        if(oldConrigState.quick_connector_btn == 0 && state.quick_connector_btn == 1) {
+        if (oldConrigState.quick_connector_btn == 0 &&
+            state.quick_connector_btn == 1)
+        {
             // The quick conector switch was pressed
             // TODO(davide.mor): Notify everybody of a manual actuation
 
@@ -471,7 +493,9 @@ void Radio::handleConrigState(const mavlink_message_t& msg)
             lastManualActuation = currentTime;
         }
 
-        if(oldConrigState.release_pressure_btn == 0 && state.release_pressure_btn == 1) {
+        if (oldConrigState.release_pressure_btn == 0 &&
+            state.release_pressure_btn == 1)
+        {
             // The release switch was pressed
             // TODO(davide.mor): Notify everybody of a manual actuation
 
@@ -480,7 +504,9 @@ void Radio::handleConrigState(const mavlink_message_t& msg)
             lastManualActuation = currentTime;
         }
 
-        if(oldConrigState.venting_valve_btn == 0 && state.venting_valve_btn == 1) {
+        if (oldConrigState.venting_valve_btn == 0 &&
+            state.venting_valve_btn == 1)
+        {
             // The venting switch was pressed
             // TODO(davide.mor): Notify everybody of a manual actuation
 
@@ -491,7 +517,8 @@ void Radio::handleConrigState(const mavlink_message_t& msg)
     }
 
     // Special case for disarming, that can be done bypassing the timeout
-    if(oldConrigState.arm_switch == 1 && state.arm_switch == 0) {
+    if (oldConrigState.arm_switch == 1 && state.arm_switch == 0)
+    {
         // TODO(davide.mor): Disarm the system
 
         lastManualActuation = currentTime;
diff --git a/src/boards/RIGv2/Sensors/Sensors.cpp b/src/boards/RIGv2/Sensors/Sensors.cpp
index 1add36cc4dc14597c28ae1fbfa37fc7a9c05ac71..fb401182ca91cf0c96da5c2994f5e8c24f356947 100644
--- a/src/boards/RIGv2/Sensors/Sensors.cpp
+++ b/src/boards/RIGv2/Sensors/Sensors.cpp
@@ -31,6 +31,19 @@ using namespace Boardcore;
 using namespace miosix;
 using namespace RIGv2;
 
+float pressureFromVoltage(float voltage, float shuntResistance,
+                          float minCurrent, float maxCurrent, float maxPressure)
+{
+    // First convert voltage to current [mA]
+    float current = (voltage / shuntResistance) * 1000.0f;
+
+    // Convert to a value between [0, 1] based on the min and max current
+    float value = (current - minCurrent) / (maxCurrent - minCurrent);
+
+    // Finally remap to the range [0, maxPressure]
+    return value * maxPressure;
+}
+
 bool Sensors::isStarted() { return started; }
 
 bool Sensors::start()
@@ -62,6 +75,85 @@ Boardcore::MAX31856Data Sensors::getTc1LastSample()
     return tc1->getLastSample();
 }
 
+Boardcore::PressureData Sensors::getVesselPress()
+{
+    auto sample = getADC1LastSample();
+
+    float pressure = pressureFromVoltage(
+        sample.voltage[0], Config::Sensors::ADC1_CH1_SHUNT_RESISTANCE,
+        Config::Sensors::PT_MIN_CURRENT, Config::Sensors::PT_MAX_CURRENT,
+        Config::Sensors::VESSEL_MAX_PRESSURE);
+    return {sample.timestamp, pressure};
+}
+
+Boardcore::PressureData Sensors::getFillingPress()
+{
+    auto sample = getADC1LastSample();
+
+    float pressure = pressureFromVoltage(
+        sample.voltage[1], Config::Sensors::ADC1_CH2_SHUNT_RESISTANCE,
+        Config::Sensors::PT_MIN_CURRENT, Config::Sensors::PT_MAX_CURRENT,
+        Config::Sensors::FILLING_MAX_PRESSURE);
+    return {sample.timestamp, pressure};
+}
+
+Boardcore::PressureData Sensors::getTankTopPress()
+{
+    auto sample = getADC1LastSample();
+
+    float pressure = pressureFromVoltage(
+        sample.voltage[2], Config::Sensors::ADC1_CH3_SHUNT_RESISTANCE,
+        Config::Sensors::PT_MIN_CURRENT, Config::Sensors::PT_MAX_CURRENT,
+        Config::Sensors::FILLING_MAX_PRESSURE);
+    return {sample.timestamp, pressure};
+}
+
+Boardcore::PressureData Sensors::getTankBottomPress()
+{
+    auto sample = getADC1LastSample();
+
+    float pressure = pressureFromVoltage(
+        sample.voltage[3], Config::Sensors::ADC1_CH4_SHUNT_RESISTANCE,
+        Config::Sensors::PT_MIN_CURRENT, Config::Sensors::PT_MAX_CURRENT,
+        Config::Sensors::FILLING_MAX_PRESSURE);
+    return {sample.timestamp, pressure};
+}
+
+Boardcore::LoadCellData Sensors::getVesselWeight()
+{
+    auto sample             = getADC1LastSample();
+    float calibratedVoltage = sample.voltage[6] - vesselLcOffset;
+
+    return {sample.timestamp, calibratedVoltage};
+}
+
+Boardcore::LoadCellData Sensors::getTankWeight()
+{
+    auto sample             = getADC1LastSample();
+    float calibratedVoltage = sample.voltage[7] - tankLcOffset;
+
+    return {sample.timestamp, calibratedVoltage};
+}
+
+void Sensors::calibrate()
+{
+    Stats channel6, channel7;
+
+    for (unsigned int i = 0; i < Config::Sensors::LC_CALIBRATE_SAMPLE_COUNT;
+         i++)
+    {
+        auto sample = getADC1LastSample();
+
+        channel6.add(sample.voltage[6]);
+        channel7.add(sample.voltage[7]);
+
+        Thread::sleep(Config::Sensors::LC_CALIBRATE_SAMPLE_PERIOD);
+    }
+
+    vesselLcOffset = channel6.getStats().mean;
+    tankLcOffset   = channel7.getStats().mean;
+}
+
 void Sensors::adc1Init(SensorManager::SensorMap_t &map)
 {
     ModuleManager &modules = ModuleManager::getInstance();
diff --git a/src/boards/RIGv2/Sensors/Sensors.h b/src/boards/RIGv2/Sensors/Sensors.h
index 794213747d6757961aca406eb4eb6fd1d7c951d7..4383c8788623c9da2f8b48c4b27bef9a28735ac9 100644
--- a/src/boards/RIGv2/Sensors/Sensors.h
+++ b/src/boards/RIGv2/Sensors/Sensors.h
@@ -26,8 +26,8 @@
 #include <sensors/MAX31856/MAX31856.h>
 #include <sensors/SensorManager.h>
 
-#include <memory>
 #include <atomic>
+#include <memory>
 #include <utils/ModuleManager/ModuleManager.hpp>
 
 namespace RIGv2
@@ -36,26 +36,42 @@ namespace RIGv2
 class Sensors : public Boardcore::Module
 {
 public:
-    explicit Sensors(Boardcore::TaskScheduler &scheduler) : scheduler{scheduler} {}
+    explicit Sensors(Boardcore::TaskScheduler &scheduler) : scheduler{scheduler}
+    {
+    }
 
     [[nodiscard]] bool start();
 
     bool isStarted();
 
+    // Getters for raw data coming from sensors
     Boardcore::ADS131M08Data getADC1LastSample();
     Boardcore::MAX31856Data getTc1LastSample();
 
+    // Getters for processed data
+    Boardcore::PressureData getVesselPress();
+    Boardcore::PressureData getFillingPress();
+    Boardcore::PressureData getTankTopPress();
+    Boardcore::PressureData getTankBottomPress();
+    Boardcore::LoadCellData getVesselWeight();
+    Boardcore::LoadCellData getTankWeight();
+
+    void calibrate();
+
 private:
     void adc1Init(Boardcore::SensorManager::SensorMap_t &map);
     void adc1Callback();
-    
+
     void tc1Init(Boardcore::SensorManager::SensorMap_t &map);
     void tc1Callback();
 
-    Boardcore::Logger &sdLogger = Boardcore::Logger::getInstance();
+    Boardcore::Logger &sdLogger   = Boardcore::Logger::getInstance();
     Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("sensors");
     Boardcore::TaskScheduler &scheduler;
 
+    std::atomic<float> vesselLcOffset{0.0f};
+    std::atomic<float> tankLcOffset{0.0f};
+
     std::atomic<bool> started{false};
     std::unique_ptr<Boardcore::ADS131M08> adc1;
     std::unique_ptr<Boardcore::MAX31856> tc1;