diff --git a/src/shared/sensors/VN300/VN300.cpp b/src/shared/sensors/VN300/VN300.cpp
index 16a4946c898415f21af1879f8b2b0ebcb9ac297a..881aad08a4e50b2354de876956845ee901a7956f 100644
--- a/src/shared/sensors/VN300/VN300.cpp
+++ b/src/shared/sensors/VN300/VN300.cpp
@@ -26,11 +26,13 @@
 
 namespace Boardcore
 {
-VN300::VN300(USARTType *portNumber, USARTInterface::Baudrate baudRate,
-             CRCOptions crc, uint16_t samplePeriod)
-    : portNumber(portNumber), baudRate(baudRate), crc(crc)
+
+VN300::VN300(USART &usart, int baudRate, CRCOptions crc, uint16_t samplePeriod,
+             AntennaPosition antPosA, AntennaPosition antPosB,
+             Eigen::Matrix3f rotMat)
+    : usart(usart), baudRate(baudRate), samplePeriod(samplePeriod), crc(crc),
+      antPosA(antPosA), antPosB(antPosB), rotMat(rotMat)
 {
-    this->samplePeriod = samplePeriod;
 }
 
 bool VN300::init()
@@ -41,7 +43,7 @@ bool VN300::init()
     if (isInit)
     {
         lastError = SensorErrors::ALREADY_INIT;
-        LOG_WARN(logger, "Sensor vn300 already initilized");
+        LOG_WARN(logger, "Sensor VN300 already initilized");
         return true;
     }
 
@@ -51,13 +53,13 @@ bool VN300::init()
     // Allocate the pre loaded strings based on the user selected crc
     if (crc == CRCOptions::CRC_ENABLE_16)
     {
-        preSampleImuString       = new string("$VNRRG,15*92EA\n");
-        preSampleTempPressString = new string("$VNRRG,54*4E0F\n");
+        preSampleImuString = new string("$VNRRG,15*92EA\n");
+        preSampleINSlla    = new string("$VNRRG,63*6BBB\n");
     }
     else
     {
-        preSampleImuString       = new string("$VNRRG,15*77\n");
-        preSampleTempPressString = new string("$VNRRG,54*72\n");
+        preSampleImuString = new string("$VNRRG,15*77\n");
+        preSampleINSlla    = new string("$VNRRG,63*76\n");
     }
 
     // Set the error to init fail and if the init process goes without problem
@@ -66,31 +68,43 @@ bool VN300::init()
 
     if (recvString == NULL)
     {
-        LOG_ERR(logger, "Unable to initialize the receive vn300 string");
+        LOG_ERR(logger, "Unable to initialize the receive VN300 string");
         return false;
     }
 
     if (!configDefaultSerialPort())
     {
-        LOG_ERR(logger, "Unable to config the default vn100 serial port");
+        LOG_ERR(logger, "Unable to config the default VN300 serial port");
         return false;
     }
 
     if (!setCrc(false))
     {
-        LOG_ERR(logger, "Unable to set the vn300 user selected CRC");
+        LOG_ERR(logger, "Unable to set the VN300 user selected CRC");
         return false;
     }
 
     if (!disableAsyncMessages(false))
     {
-        LOG_ERR(logger, "Unable to disable async messages from vn100");
+        LOG_ERR(logger, "Unable to disable async messages from VN300");
+        return false;
+    }
+
+    if (!setReferenceFrame(rotMat))
+    {
+        LOG_ERR(logger, "Unable to set reference frame rotation");
+        return false;
+    }
+
+    if (!writeSettingsCommand())
+    {
+        LOG_ERR(logger, "Unable to save settings to non-volatile memory");
         return false;
     }
 
     if (!configUserSerialPort())
     {
-        LOG_ERR(logger, "Unable to config the user vn100 serial port");
+        LOG_ERR(logger, "Unable to config the user VN300 serial port");
         return false;
     }
 
@@ -98,19 +112,25 @@ bool VN300::init()
     // serial port communication at the beginning
     if (!setCrc(true))
     {
-        LOG_ERR(logger, "Unable to set the vn100 user selected CRC");
+        LOG_ERR(logger, "Unable to set the VN300 user selected CRC");
         return false;
     }
 
     if (!disableAsyncMessages(true))
     {
-        LOG_ERR(logger, "Unable to disable async messages from vn100");
+        LOG_ERR(logger, "Unable to disable async messages from VN300");
         return false;
     }
 
-    if (!this->start())
+    if (!setAntennaA(antPosA))
     {
-        LOG_ERR(logger, "Unable to start the sampling thread");
+        LOG_ERR(logger, "Unable to set antenna A position");
+        return false;
+    }
+
+    if (!setCompassBaseline(antPosB))
+    {
+        LOG_ERR(logger, "Unable to set compass baseline");
         return false;
     }
 
@@ -128,23 +148,128 @@ void VN300::run()
     while (!shouldStop())
     {
         long long initialTime = miosix::getTick();
-
-        // Sample the data locking the mutex
-        miosix::Lock<FastMutex> l(mutex);
-        threadSample = sampleData();
-
+        {
+            // Sample the data locking the mutex
+            miosix::Lock<FastMutex> l(mutex);
+            threadSample = sampleData();
+        }
         // Sleep for the sampling period
         miosix::Thread::sleepUntil(initialTime + samplePeriod);
     }
 }
 
+bool VN300::sampleRaw()
+{
+    // Sensor not init
+    if (!isInit)
+    {
+        lastError = SensorErrors::NOT_INIT;
+        LOG_WARN(logger,
+                 "Unable to sample due to not initialized VN300 sensor");
+        return false;
+    }
+
+    // Send the IMU sampling command
+    usart.writeString(preSampleImuString->c_str());
+
+    // Wait some time
+    // TODO dimension the time
+    miosix::Thread::sleep(1);
+
+    // Receive the string
+    if (!recvStringCommand(recvString, recvStringMaxDimension))
+    {
+        LOG_WARN(logger, "Unable to sample due to serial communication error");
+        return false;
+    }
+
+    return true;
+}
+
+string VN300::getLastRawSample()
+{
+    // If not init i return the void string
+    if (!isInit)
+    {
+        return string("");
+    }
+
+    return string(recvString, recvStringLength);
+}
+
+bool VN300::closeAndReset()
+{
+    // Sensor not init
+    if (!isInit)
+    {
+        lastError = SensorErrors::NOT_INIT;
+        LOG_WARN(logger, "Sensor VN300 already not initilized");
+        return true;
+    }
+
+    // Send the reset command to the VN300
+    if (!sendStringCommand("VNRST"))
+    {
+        LOG_WARN(logger, "Impossible to reset the VN300");
+        return false;
+    }
+
+    isInit = false;
+
+    // Free the recvString memory
+    delete recvString;
+
+    return true;
+}
+
+bool VN300::writeSettingsCommand()
+{
+    if (!sendStringCommand("VNWNV"))
+    {
+        LOG_WARN(logger, "Impossible to save settings");
+    }
+
+    // Write settings command takes approximately 500ms
+    miosix::Thread::sleep(500);
+
+    // Send the reset command to the VN300 in order to restart the Kalman filter
+    if (!sendStringCommand("VNRST"))
+    {
+        LOG_WARN(logger, "Impossible to reset the VN300");
+
+        return false;
+    }
+
+    miosix::Thread::sleep(1000);
+
+    return true;
+}
+
+bool VN300::selfTest()
+{
+    if (!selfTestImpl())
+    {
+        lastError = SensorErrors::SELF_TEST_FAIL;
+        LOG_WARN(logger, "Unable to perform a successful VN300 self test");
+        return false;
+    }
+
+    return true;
+}
+
+VN300Data VN300::sampleImpl()
+{
+    miosix::Lock<FastMutex> l(mutex);
+    return threadSample;
+}
+
 VN300Data VN300::sampleData()
 {
     if (!isInit)
     {
         lastError = SensorErrors::NOT_INIT;
         LOG_WARN(logger,
-                 "Unable to sample due to not initialized vn100 sensor");
+                 "Unable to sample due to not initialized VN300 sensor");
         return lastSample;
     }
 
@@ -155,11 +280,7 @@ VN300Data VN300::sampleData()
     }
 
     // Returns Quaternion, Magnetometer, Accelerometer and Gyro
-    if (!(serialInterface->writeString(preSampleImuString->c_str())))
-    {
-        // If something goes wrong i return the last sampled data
-        return lastSample;
-    }
+    usart.writeString(preSampleImuString->c_str());
 
     // Wait some time
     // TODO dimension the time
@@ -173,25 +294,18 @@ VN300Data VN300::sampleData()
 
     if (!verifyChecksum(recvString, recvStringLength))
     {
-        LOG_WARN(logger, "Vn100 sampling message invalid checksum");
+        LOG_WARN(logger, "VN300 sampling message invalid checksum");
         // If something goes wrong i return the last sampled data
         return lastSample;
     }
 
-    // Now i have to parse the data
     QuaternionData quat   = sampleQuaternion();
     MagnetometerData mag  = sampleMagnetometer();
     AccelerometerData acc = sampleAccelerometer();
     GyroscopeData gyro    = sampleGyroscope();
 
-    // Returns Magnetometer, Accelerometer, Gyroscope, Temperature and Pressure
-    // (UNCOMPENSATED) DO NOT USE THESE MAGNETOMETER, ACCELEROMETER AND
-    // GYROSCOPE VALUES
-    if (!(serialInterface->writeString(preSampleTempPressString->c_str())))
-    {
-        // If something goes wrong i return the last sampled data
-        return lastSample;
-    }
+    // Returns INS LLA message
+    usart.writeString(preSampleINSlla->c_str());
 
     // Wait some time
     // TODO dimension the time
@@ -199,22 +313,19 @@ VN300Data VN300::sampleData()
 
     if (!recvStringCommand(recvString, recvStringMaxDimension))
     {
-        // If something goes wrong i return the last sampled data
         return lastSample;
     }
 
     if (!verifyChecksum(recvString, recvStringLength))
     {
-        LOG_WARN(logger, "Vn100 sampling message invalid checksum");
-        // If something goes wrong i return the last sampled data
+        LOG_WARN(logger, "VN300 sampling message invalid checksum");
+
         return lastSample;
     }
 
-    // Parse the data
-    TemperatureData temp = sampleTemperature();
-    PressureData press   = samplePressure();
+    Ins_Lla ins = sampleIns();
 
-    return VN100Data(quat, mag, acc, gyro, temp, press);
+    return VN300Data(quat, mag, acc, gyro, ins);
 }
 
 bool VN300::disableAsyncMessages(bool waitResponse)
@@ -233,32 +344,9 @@ bool VN300::disableAsyncMessages(bool waitResponse)
     if (waitResponse)
     {
         recvStringCommand(recvString, recvStringMaxDimension);
-    }
 
-    return true;
-}
-
-bool VN300::AsyncPauseCommand(bool waitResponse, bool selection)
-{
-    if (selection)
-    {
-        if (!sendStringCommand(ASYNC_PAUSE_COMMAND))
-        {
+        if (checkErrorVN(recvString))
             return false;
-        }
-    }
-    else
-    {
-        if (!sendStringCommand(ASYNC_RESUME_COMMAND))
-        {
-            return false;
-        }
-    }
-
-    // Read the answer
-    if (waitResponse)
-    {
-        recvStringCommand(recvString, recvStringMaxDimension);
     }
 
     return true;
@@ -267,10 +355,10 @@ bool VN300::AsyncPauseCommand(bool waitResponse, bool selection)
 bool VN300::configDefaultSerialPort()
 {
     // Initial default settings
-    serialInterface = new USART(portNumber, USARTInterface::Baudrate::B115200);
+    usart.setBaudrate(115200);
 
     // Check correct serial init
-    return serialInterface->init();
+    return true;
 }
 
 /**
@@ -282,7 +370,7 @@ bool VN300::configUserSerialPort()
     std::string command;
 
     // I format the command to change baud rate
-    command = fmt::format("{}{}", "VNWRG,5,", static_cast<int>(baudRate));
+    command = fmt::format("{}{}", "VNWRG,5,2", baudRate);
 
     // I can send the command
     if (!sendStringCommand(command))
@@ -290,14 +378,11 @@ bool VN300::configUserSerialPort()
         return false;
     }
 
-    // Destroy the serial object
-    delete serialInterface;
-
     // I can open the serial with user's baud rate
-    serialInterface = new USART(portNumber, baudRate);
+    usart.setBaudrate(baudRate);
 
     // Check correct serial init
-    return serialInterface->init();
+    return true;
 }
 
 bool VN300::setCrc(bool waitResponse)
@@ -311,14 +396,14 @@ bool VN300::setCrc(bool waitResponse)
     {
         // The 3 inside the command is the 16bit select. The others are default
         // values
-        command = "VNRRG,30,0,0,0,0,3,0,1";
+        command = "VNWRG,30,0,0,0,0,3,0,1";
     }
     else
     {
         // Even if the CRC is not enabled i put the 8 bit
         // checksum because i need to know how many 'X' add at the end
         // of every command sent
-        command = "VNRRG,30,0,0,0,0,1,0,1";
+        command = "VNWRG,30,0,0,0,0,1,0,1";
     }
 
     // I need to send the command in both crc because i don't know what type
@@ -336,6 +421,7 @@ bool VN300::setCrc(bool waitResponse)
     if (waitResponse)
     {
         recvStringCommand(recvString, recvStringMaxDimension);
+        checkErrorVN(recvString);
     }
 
     crc = CRCOptions::CRC_ENABLE_16;
@@ -350,6 +436,7 @@ bool VN300::setCrc(bool waitResponse)
     if (waitResponse)
     {
         recvStringCommand(recvString, recvStringMaxDimension);
+        checkErrorVN(recvString);
     }
 
     // Restore the crc
@@ -358,6 +445,253 @@ bool VN300::setCrc(bool waitResponse)
     return true;
 }
 
+bool VN300::setAntennaA(AntennaPosition antPos)
+{
+    std::string command;
+
+    command = fmt::format("{}{},{},{}", "VNWRG,57,", antPos.posX, antPos.posY,
+                          antPos.posZ);
+
+    if (!sendStringCommand(command))
+    {
+        return false;
+    }
+
+    return true;
+}
+
+bool VN300::setCompassBaseline(AntennaPosition antPos)
+{
+    std::string command;
+
+    command = fmt::format("{}{},{},{},{},{},{}", "VNWRG,93,", antPos.posX,
+                          antPos.posY, antPos.posZ, antPos.uncX, antPos.uncY,
+                          antPos.uncZ);
+
+    if (!sendStringCommand(command))
+    {
+        return false;
+    }
+
+    return true;
+}
+
+bool VN300::setReferenceFrame(Eigen::Matrix3f rotMat)
+{
+    std::string command;
+
+    command =
+        fmt::format("{}{},{},{},{},{},{},{},{},{}", "VNWRG, 26", rotMat(0, 0),
+                    rotMat(0, 1), rotMat(0, 2), rotMat(1, 0), rotMat(1, 1),
+                    rotMat(1, 2), rotMat(2, 0), rotMat(2, 1), rotMat(2, 2));
+
+    // I can send the command
+    if (!sendStringCommand(command))
+    {
+        return false;
+    }
+
+    return true;
+}
+
+bool VN300::selfTestImpl()
+{
+    char modelNumber[]          = "VN-300T-CR";
+    const int modelNumberOffset = 10;
+
+    // Check the init status
+    if (!isInit)
+    {
+        lastError = SensorErrors::NOT_INIT;
+        LOG_WARN(
+            logger,
+            "Unable to perform VN300 self test due to not initialized sensor");
+        return false;
+    }
+
+    // removing junk
+    usart.clearQueue();
+
+    // I check the model number
+    if (!sendStringCommand("VNRRG,01"))
+    {
+        LOG_WARN(logger, "Unable to send string command");
+        return false;
+    }
+
+    miosix::Thread::sleep(100);
+
+    if (!recvStringCommand(recvString, recvStringMaxDimension))
+    {
+        LOG_WARN(logger, "Unable to receive string command");
+        return false;
+    }
+
+    // Now i check that the model number is VN-100 starting from the 10th
+    // position because of the message structure
+    if (strncmp(modelNumber, recvString + modelNumberOffset,
+                strlen(modelNumber)) != 0)
+    {
+        LOG_ERR(logger, "VN-300 not corresponding: {} != {}", recvString,
+                modelNumber);
+        return false;
+    }
+
+    // I check the checksum
+    if (!verifyChecksum(recvString, recvStringLength))
+    {
+        LOG_ERR(logger, "Checksum verification failed: {}", recvString);
+        return false;
+    }
+
+    return true;
+}
+
+QuaternionData VN300::sampleQuaternion()
+{
+    unsigned int indexStart = 0;
+    char *nextNumber;
+    QuaternionData data;
+
+    // Look for the second ',' in the string
+    // I can avoid the string control because it has already been done in
+    // sampleImpl
+    for (int i = 0; i < 2; i++)
+    {
+        while (indexStart < recvStringLength && recvString[indexStart] != ',')
+        {
+            indexStart++;
+        }
+        indexStart++;
+    }
+
+    // Parse the data
+    data.quatTimestamp = TimestampTimer::getTimestamp();
+    data.quatX         = strtod(recvString + indexStart + 1, &nextNumber);
+    data.quatY         = strtod(nextNumber + 1, &nextNumber);
+    data.quatZ         = strtod(nextNumber + 1, &nextNumber);
+    data.quatW         = strtod(nextNumber + 1, NULL);
+
+    return data;
+}
+
+MagnetometerData VN300::sampleMagnetometer()
+{
+    unsigned int indexStart = 0;
+    char *nextNumber;
+    MagnetometerData data;
+
+    // Look for the sixth ',' in the string
+    // I can avoid the string control because it has already been done in
+    // sampleImpl
+    for (int i = 0; i < 6; i++)
+    {
+        while (indexStart < recvStringLength && recvString[indexStart] != ',')
+        {
+            indexStart++;
+        }
+        indexStart++;
+    }
+
+    // Parse the data
+    data.magneticFieldTimestamp = TimestampTimer::getTimestamp();
+    data.magneticFieldX = strtod(recvString + indexStart + 1, &nextNumber);
+    data.magneticFieldY = strtod(nextNumber + 1, &nextNumber);
+    data.magneticFieldZ = strtod(nextNumber + 1, NULL);
+
+    return data;
+}
+
+AccelerometerData VN300::sampleAccelerometer()
+{
+    unsigned int indexStart = 0;
+    char *nextNumber;
+    AccelerometerData data;
+
+    // Look for the ninth ',' in the string
+    // I can avoid the string control because it has already been done in
+    // sampleImpl
+    for (int i = 0; i < 9; i++)
+    {
+        while (indexStart < recvStringLength && recvString[indexStart] != ',')
+        {
+            indexStart++;
+        }
+        indexStart++;
+    }
+
+    // Parse the data
+    data.accelerationTimestamp = TimestampTimer::getTimestamp();
+    data.accelerationX = strtod(recvString + indexStart + 1, &nextNumber);
+    data.accelerationY = strtod(nextNumber + 1, &nextNumber);
+    data.accelerationZ = strtod(nextNumber + 1, NULL);
+
+    return data;
+}
+
+GyroscopeData VN300::sampleGyroscope()
+{
+    unsigned int indexStart = 0;
+    char *nextNumber;
+    GyroscopeData data;
+
+    // Look for the twelfth ',' in the string
+    // I can avoid the string control because it has already been done in
+    // sampleImpl
+    for (int i = 0; i < 12; i++)
+    {
+        while (indexStart < recvStringLength && recvString[indexStart] != ',')
+        {
+            indexStart++;
+        }
+        indexStart++;
+    }
+
+    // Parse the data
+    data.angularSpeedTimestamp = TimestampTimer::getTimestamp();
+    data.angularSpeedX = strtod(recvString + indexStart + 1, &nextNumber);
+    data.angularSpeedY = strtod(nextNumber + 1, &nextNumber);
+    data.angularSpeedZ = strtod(nextNumber + 1, NULL);
+
+    return data;
+}
+
+Ins_Lla VN300::sampleIns()
+{
+    unsigned int indexStart = 0;
+    char *nextNumber;
+    Ins_Lla data;
+
+    // Look for the eleventh ',' in the string
+    // I can avoid the string control because it has already been done in
+    // sampleImpl
+    for (int i = 0; i < 2; i++)
+    {
+        while (indexStart < recvStringLength && recvString[indexStart] != ',')
+        {
+            indexStart++;
+        }
+        indexStart++;
+    }
+
+    // Parse the data
+    data.insTimestamp = TimestampTimer::getTimestamp();
+    data.time_gps     = strtod(recvString + indexStart + 1, &nextNumber);
+    data.week         = strtod(nextNumber + 1, &nextNumber);
+    data.status       = strtod(nextNumber + 1, &nextNumber);
+    data.yaw          = strtof(nextNumber + 1, &nextNumber);
+    data.pitch        = strtof(nextNumber + 1, &nextNumber);
+    data.roll         = strtof(nextNumber + 1, &nextNumber);
+    data.latitude     = strtof(nextNumber + 1, &nextNumber);
+    data.longitude    = strtof(nextNumber + 1, &nextNumber);
+    data.altitude     = strtof(nextNumber + 1, &nextNumber);
+    data.nedVelX      = strtof(nextNumber + 1, &nextNumber);
+    data.nedVelY      = strtof(nextNumber + 1, &nextNumber);
+    data.nedVelZ      = strtof(nextNumber + 1, NULL);
+
+    return data;
+}
+
 bool VN300::sendStringCommand(std::string command)
 {
     if (crc == CRCOptions::CRC_ENABLE_8)
@@ -388,20 +722,103 @@ bool VN300::sendStringCommand(std::string command)
         // in cas of CRC_NO the enabled crc is 8 bit
         command = fmt::format("{}{}{}", "$", command, "*XX\n");
     }
-
+    printf("%s\n", command.c_str());
     // I send the final command
-    if (!serialInterface->writeString(command.c_str()))
+    usart.writeString(command.c_str());
+
+    // Wait some time
+    // TODO dimension the time
+    // miosix::Thread::sleep(1);
+
+    return true;
+}
+
+bool VN300::recvStringCommand(char *command, int maxLength)
+{
+    int i = 0;
+    // Read the buffer
+    if (!usart.readBlocking(command, maxLength))
     {
         return false;
     }
 
-    // Wait some time
-    // TODO dimension the time
-    miosix::Thread::sleep(500);
+    // Iterate until i reach the end or i find \n then i substitute it with a \0
+    while (i < maxLength && command[i] != '\n')
+    {
+        i++;
+    }
+
+    // Terminate the string
+    command[i] = '\0';
+
+    // Assing the length
+    recvStringLength = i - 1;
 
     return true;
 }
 
+bool VN300::checkErrorVN(const char *message)
+{
+    if (strncmp(message, "$VNERR,", 7) == 0)
+    {
+        // Extract the error code
+        int errorCode = atoi(&message[7]);
+        string error;
+        // Handle the error based on the error code
+        switch (errorCode)
+        {
+            case 1:
+                error = "VN300 Hard Fault";
+                break;
+            case 2:
+                error = "VN300 Serial Buffer Overflow";
+                break;
+            case 3:
+                error = "VN300 Invalid Checksum";
+                break;
+            case 4:
+                error = "VN300 Invalid Command";
+                break;
+            case 5:
+                error = "VN300 Not Enough Parameters";
+                break;
+            case 6:
+                error = "VN300 Too Many Parameters";
+                break;
+            case 7:
+                error = "VN300 Invalid Parameter";
+                break;
+            case 8:
+                error = "VN300 Invalid Register";
+                break;
+            case 9:
+                error = "VN300 Unauthorized Access";
+                break;
+            case 10:
+                error = "VN300 Watchdog Reset";
+                break;
+            case 11:
+                error = "VN300 Output Buffer Overflow";
+                break;
+            case 12:
+                error = "VN300 Insufficient Baud Rate";
+                break;
+            case 255:
+                error = "VN300 Error Buffer Overflow";
+                break;
+            default:
+                error = "VN300 Unknown error";
+                break;
+        }
+
+        printf("%s\n", error.c_str());
+
+        return true;  // Error detected
+    }
+
+    return false;  // No error detected
+}
+
 bool VN300::verifyChecksum(char *command, int length)
 {
     int checksumOffset = 0;
@@ -493,4 +910,4 @@ uint16_t VN300::calculateChecksum16(uint8_t *message, int length)
     return result;
 }
 
-}  // namespace Boardcore
\ No newline at end of file
+}  // namespace Boardcore
diff --git a/src/shared/sensors/VN300/VN300.h b/src/shared/sensors/VN300/VN300.h
index b503615defca42196d686d5c794cdaff6790e528..af43c56f7202357a7755bb5bb7d4d2646335ce97 100644
--- a/src/shared/sensors/VN300/VN300.h
+++ b/src/shared/sensors/VN300/VN300.h
@@ -23,15 +23,18 @@
 #pragma once
 
 /**
- * @brief Driver for the VN300 IMU.
+ * @brief Driver for the VN300S IMU.
  *
- * The VN-300 is a miniature, surface-mount, high-performance GPS-Aided Inertial
- * Navigation System (GPS/INS). Incorporating the latest solid-state MEMS sensor
- * technology, the VN-300 combines a set of 3-axis accelerometers, 3-axis gyros,
- * 3-axis magnetometer, a barometric pressure sensor, two separate 50-channel L1
- * GPS receivers, as well as a 32-bit processor into a miniature aluminum
- * enclosure.
- * The VN300 supports both binary and ASCII encoding for communication but via
+ * The VN300S sensor is a calibrated IMU which includes accelerometer,
+ * magnetometer, gyroscope, barometer and temperature sensor. The device
+ * provides also a calibration matrix and an anti-drift matrix for the gyroscope
+ * values. The goal of this driver though is to interface the sensor in its
+ * basic use. Things like asynchronous data and anti-drift techniques haven't
+ * been implemented yet. The driver is intended to be used with the "Rugged
+ * sensor" version (aka only UART communication) although the actual VN300S chip
+ * is capable also of SPI communication.
+ *
+ * The VN300S supports both binary and ASCII encoding for communication but via
  * serial and with the asynchronous mode disabled only ASCII is available. The
  * protocol also provides two algorithms to verify the integrity of the messages
  * (8 bit checksum and 16 bit CRC-CCITT) both selectable by the user using the
@@ -55,218 +58,75 @@
 #include <string.h>
 #include <utils/Debug.h>
 
+#include <Eigen/Core>
+
 #include "VN300Data.h"
 #include "drivers/usart/USART.h"
 
 namespace Boardcore
 {
+
 /**
- * @brief Driver class for VN300
+ * @brief Driver class for VN300 IMU.
  */
 class VN300 : public Sensor<VN300Data>, public ActiveObject
 {
 public:
-    /**
-     * @brief Checksum Options
-     */
     enum class CRCOptions : uint8_t
     {
         CRC_NO        = 0x00,
         CRC_ENABLE_8  = 0x08,
         CRC_ENABLE_16 = 0x10
     };
-    /**
-     * @brief Async options
-     * ASYNC_NO corresponds to no Async communication
-     * ASYNC_P1 corresponds to Async comm only on serial port 1
-     * ASYNC_P2 corresponds to Async comm only on serial port 2
-     * ASYNC_BOTH both serial port are used
-     */
-    enum class AsyncOptions : uint16_t
-    {
-        ASYNC_NO   = 0x00,
-        ASYNC_P1   = 0x01,
-        ASYNC_P2   = 0x02,
-        ASYNC_BOTH = 0x03
-    };
-
-    enum class RateDivisor : uint16_t
-    {
-        RDIV_400_HZ = 0x01,
-        RDIV_200_HZ = 0x02,
-        RDIV_100_HZ = 0x04,
-        RDIV_50_HZ  = 0x08,
-        RDIV_40_HZ  = 0x0A
-    };
 
     /**
-     * @brief Group's bit for binary register setup
-     */
-    enum OutputGroup : uint16_t
-    {
-        GROUP_1 = 1 << 0,
-        GROUP_2 = 1 << 1,
-        GROUP_3 = 1 << 2,
-        GROUP_4 = 1 << 3,
-        GROUP_5 = 1 << 4,
-        GROUP_6 = 1 << 5,
-        GROUP_7 = 1 << 6
-    };
-
-    /**
-     * @brief Common Group
-     */
-    enum GroupField_1 : uint16_t
-    {
-        T_START     = 1 << 0,
-        T_GPS       = 1 << 1,
-        T_SYNC      = 1 << 2,
-        Y_P_R       = 1 << 3,
-        QUAT        = 1 << 4,
-        ANG_RATE    = 1 << 5,
-        POS         = 1 << 6,
-        VEL         = 1 << 7,
-        ACCEL       = 1 << 8,
-        IMU         = 1 << 9,
-        MAGPRES     = 1 << 10,
-        DELT_TH     = 1 << 11,
-        INS_STAT    = 1 << 12,
-        SYNC_IN_CNT = 1 << 13,
-        T_GPS_PPS   = 1 << 14
-    };
-
-    /**
-     * @brief TIME Group
+     * @brief Constructor.
+     *
+     * @param usart Serial bus used for the sensor.
+     * @param BaudRate different from the sensor's default [9600, 19200, 38400,
+     * 57600, 115200, 128000, 230400, 460800, 921600].
+     * @param Redundancy check option.
+     * @param samplePeriod Sampling period in ms
+     * @param antPos antenna A position
      */
-    enum GroupField_2 : uint16_t
-    {
-        T_START      = 1 << 0,
-        T_GPS        = 1 << 1,
-        GPS_TOW      = 1 << 2,
-        GPS_WEEK     = 1 << 3,
-        T_SYNC       = 1 << 4,
-        T_GPS_PPS    = 1 << 5,
-        T_UTC        = 1 << 6,
-        SYNC_IN_CNT  = 1 << 7,
-        SYNC_OUT_CNT = 1 << 8,
-        T_STATUS     = 1 << 9,
-    };
+    VN300(USART &usart, int baudrate, CRCOptions crc = CRCOptions::CRC_ENABLE_8,
+          uint16_t samplePeriod   = 1,
+          AntennaPosition antPosA = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+          AntennaPosition antPosB = {1.0, 0.0, 0.0, 0.0, 0.0, 0.0},
+          Eigen::Matrix3f rotMat  = Eigen::Matrix3f::Identity());
 
-    /**
-     * @brief IMU Group
-     */
-    enum GroupField_3 : uint16_t
-    {
-        IMU_STAT  = 1 << 0,
-        UNC_MAG   = 1 << 1,
-        UNC_ACC   = 1 << 2,
-        UNC_GYRO  = 1 << 3,
-        TEMP      = 1 << 4,
-        PRES      = 1 << 5,
-        DELTA_TH  = 1 << 6,
-        DELTA_VEL = 1 << 7,
-        MAG       = 1 << 8,
-        ACCEL     = 1 << 9,
-        ANG_RATE  = 1 << 10,
-    };
-
-    /**
-     * @brief GNSS1 Group
-     */
-    enum GroupField_4 : uint16_t
-    {
-        UTC       = 1 << 0,
-        TOW       = 1 << 1,
-        WEEK      = 1 << 2,
-        N_SATS    = 1 << 3,
-        FIX       = 1 << 4,
-        POS_LLA   = 1 << 5,
-        POS_ECEF  = 1 << 6,
-        VEL_NED   = 1 << 7,
-        VEL_ECEF  = 1 << 8,
-        POS_U     = 1 << 9,
-        VEL_U     = 1 << 10,
-        TIME_U    = 1 << 11,
-        TIME_INFO = 1 << 12,
-        DOP       = 1 << 13,
-        SAT_INFO  = 1 << 14,
-        RAW_MEAS  = 1 << 15
-    };
+    bool init() override;
 
     /**
-     * @brief Attitude Group
+     * @brief Method to sample the raw data without parsing.
+     *
+     * @return True if operation succeeded.
      */
-    enum GroupField_5 : uint16_t
-    {
-        RESERVED    = 1 << 0,
-        Y_P_R       = 1 << 1,
-        QUAT        = 1 << 2,
-        DCM         = 1 << 3,
-        MAG_NED     = 1 << 4,
-        ACC_NED     = 1 << 5,
-        LIN_ACC_BOD = 1 << 6,
-        LIN_ACC_NED = 1 << 7,
-        YprU        = 1 << 8,
-        RESERVED    = 1 << 9,
-        RESERVED    = 1 << 10,
-        RESERVED    = 1 << 11
-    };
+    bool sampleRaw();
 
     /**
-     * @brief INS Group
+     * @brief Method to get the raw sample.
+     *
+     * @return String that represents the sample.
      */
-    enum GroupField_6 : uint16_t
-    {
-        INS_STATUS   = 1 << 0,
-        POS_LLA      = 1 << 1,
-        POS_ECEF     = 1 << 2,
-        VEL_BODY     = 1 << 3,
-        VEL_NED      = 1 << 4,
-        VEL_ECEF     = 1 << 5,
-        MAG_ECEF     = 1 << 6,
-        ACC_ECEF     = 1 << 7,
-        LIN_ACC_ECEF = 1 << 8,
-        POS_U        = 1 << 9,
-        VEL_U        = 1 << 10
-    };
+    string getLastRawSample();
 
     /**
-     * @brief GNSS2 Group
+     * @brief Method to reset the sensor to default values and to close
+     * the connection. Used if you need to close and re initialize the sensor.
+     *
+     * @return True if operation succeeded.
      */
-    enum GroupField_7 : uint16_t
-    {
-        UTC       = 1 << 0,
-        TOW       = 1 << 1,
-        WEEK      = 1 << 2,
-        N_SATS    = 1 << 3,
-        FIX       = 1 << 4,
-        POS_LLA   = 1 << 5,
-        POS_ECEF  = 1 << 6,
-        VEL_NED   = 1 << 7,
-        VEL_ECEF  = 1 << 8,
-        POS_U     = 1 << 9,
-        VEL_U     = 1 << 10,
-        TIME_U    = 1 << 11,
-        TIME_INFO = 1 << 12,
-        DOP       = 1 << 13,
-        SAT_INFO  = 1 << 14,
-        RAW_MEAS  = 1 << 15
-    };
-
-    VN300(USARTType *portNumber    = USART1,
-          USART::Baudrate baudRate = USART::Baudrate::B921600,
-          CRCOptions crc           = CRCOptions::CRC_ENABLE_8,
-          uint16_t samplePeriod    = 50);
-
-    bool init() override;
-
-    bool sampleRaw();
-
     bool closeAndReset();
 
     bool selfTest() override;
 
 private:
+    /**
+     * @brief Sample action implementation.
+     */
+    VN300Data sampleImpl() override;
+
     /**
      * @brief Active object method, about the thread execution
      */
@@ -275,12 +135,12 @@ private:
     /**
      * @brief Sampling method used by the thread
      *
-     * @return VN100Data The sampled data
+     * @return VN300Data The sampled data
      */
     VN300Data sampleData();
 
     /**
-     * @brief Disables the async messages that the vn100 is default configured
+     * @brief Disables the async messages that the VN300 is default configured
      * to send at 40Hz on startup.
      *
      * @param waitResponse If true wait for a serial response.
@@ -289,20 +149,6 @@ private:
      */
     bool disableAsyncMessages(bool waitResponse = true);
 
-    /**
-     * @brief Pause async messages in order to write command without receiving
-     * continuous data transmission
-     *
-     * @param waitResponse If true wait for a serial response.
-     *
-     * @param selection if true pause the async output, if false restart the
-     * output
-     *
-     * @return True if operation succeeded.
-     *
-     */
-    bool VN300::AsyncPauseCommand(bool waitResponse = false, bool selection);
-
     /**
      * @brief Configures the default serial communication.
      *
@@ -326,6 +172,44 @@ private:
      */
     bool setCrc(bool waitResponse = true);
 
+    /**
+     * @brief Write the settings on the non volatile-memory.
+     *
+     * @return True if operation succeeded.
+     */
+    bool writeSettingsCommand();
+
+    /**
+     * @brief Sets the antenna A offset.
+     *
+     * @param antPos antenna position.
+     *
+     * @return True if operation succeeded.
+     */
+    bool setAntennaA(AntennaPosition antPos);
+
+    /**
+     * @brief Sets the compass baseline, position offset of antenna B respect to
+     * antenna A. Uncertainty must be higher than actual measurement error,
+     * possibly twice as the error.
+     * All measures are in meters [m].
+     *
+     * @param antPos antenna position.
+     *
+     * @return True if operation succeeded.
+     */
+    bool setCompassBaseline(AntennaPosition antPos);
+
+    /**
+     * @brief set the reference frame rotation of the sensor in order to have
+     * all the data on the desired reference frame.
+     *
+     * @param rotMat rotation matrix.
+     *
+     * @return if operation succeeded.
+     */
+    bool setReferenceFrame(Eigen::Matrix3f rotMat);
+
     /**
      * @brief Method implementation of self test.
      *
@@ -333,6 +217,15 @@ private:
      */
     bool selfTestImpl();
 
+    QuaternionData sampleQuaternion();
+
+    MagnetometerData sampleMagnetometer();
+
+    AccelerometerData sampleAccelerometer();
+
+    GyroscopeData sampleGyroscope();
+
+    Ins_Lla sampleIns();
     /**
      * @brief Sends the command to the sensor with the correct checksum added
      * so '*' symbol is not needed at the end of the string as well as the '$'
@@ -345,7 +238,7 @@ private:
     bool sendStringCommand(std::string command);
 
     /**
-     * @brief Receives a command from the VN100 serialInterface->recv() but
+     * @brief Receives a command from the VN300 serialInterface->recv() but
      * swaps the first \n with a \0 to close the message.
      *
      * @param command The char array which will be filled with the command.
@@ -355,6 +248,18 @@ private:
      */
     bool recvStringCommand(char *command, int maxLength);
 
+    /**
+     * @brief check if the VN-300 returned an error and differentiate between
+     * them. The error is formatted as $VNERR,xx*XX
+     *
+     * xx can go from 01 to 12 and 255 and XX is the checksum.
+     *
+     * @param message to be checked.
+     *
+     * @return True if error are present.
+     */
+    bool checkErrorVN(const char *message);
+
     /**
      * @brief Method to verify the crc validity of a command.
      *
@@ -385,14 +290,32 @@ private:
      */
     uint16_t calculateChecksum16(uint8_t *message, int length);
 
-    USARTType *portNumber;
-    USART::Baudrate baudRate;
+    /**
+     * @brief Serial interface that is needed to communicate
+     * with the sensor via ASCII codes.
+     */
+    USART &usart;
+    int baudRate;
+
     uint16_t samplePeriod;
     CRCOptions crc;
     bool isInit = false;
 
-    std::string ASYNC_PAUSE_COMMAND  = "VNASY,0";
-    std::string ASYNC_RESUME_COMMAND = "VNASY,1";
+    AntennaPosition antPosA;
+    AntennaPosition antPosB;
+    Eigen::Matrix3f rotMat;
+
+    /**
+     * @brief IMU pre-elaborated sample string for efficiency reasons.
+     */
+    string *preSampleImuString = nullptr;
+
+    /**
+     * @brief Temperature and pressure pre-elaborated sample string for
+     * efficiency reasons.
+     */
+    string *preSampleINSlla = nullptr;
+
     /**
      * @brief Pointer to the received string by the sensor. Allocated 1 time
      * only (200 bytes).
@@ -404,20 +327,14 @@ private:
      */
     unsigned int recvStringLength = 0;
 
-    /**
-     * @brief Serial interface that is needed to communicate
-     * with the sensor via ASCII codes.
-     */
-    USARTInterface *serialInterface = nullptr;
-
     /**
      * @brief Mutex to synchronize the reading and writing of the threadSample
      */
     mutable miosix::FastMutex mutex;
     VN300Data threadSample;
 
-    PrintLogger logger = Logging::getLogger("vn300");
+    PrintLogger logger = Logging::getLogger("VN300");
 
     static const unsigned int recvStringMaxDimension = 200;
 };
-}  // namespace Boardcore
\ No newline at end of file
+}  // namespace Boardcore
diff --git a/src/shared/sensors/VN300/VN300Data.h b/src/shared/sensors/VN300/VN300Data.h
index 3df6e3968f71259b12e55150459408c66205e40e..106ee67c672693c2293323add7c6b73c404f81f5 100644
--- a/src/shared/sensors/VN300/VN300Data.h
+++ b/src/shared/sensors/VN300/VN300Data.h
@@ -40,15 +40,43 @@ struct QuaternionData
 };
 
 /**
- * @brief Structure to handle quaternion data
+ * @brief Structure to handle antenna A position units [m]
  */
+struct AntennaPosition
+{
+    float posX;
+    float posY;
+    float posZ;
+    float uncX;
+    float uncY;
+    float uncZ;
+};
 
+struct Ins_Lla
+{
+    uint64_t insTimestamp;
+    double time_gps;
+    uint16_t week;
+    uint16_t status;
+    float yaw;
+    float pitch;
+    float roll;
+    float latitude;
+    float longitude;
+    float altitude;
+    float nedVelX;
+    float nedVelY;
+    float nedVelZ;
+};
+
+/**
+ * @brief data type class
+ */
 struct VN300Data : public QuaternionData,
                    public MagnetometerData,
                    public AccelerometerData,
                    public GyroscopeData,
-                   public TemperatureData,
-                   public PressureData
+                   public Ins_Lla
 {
 
     /**
@@ -56,10 +84,12 @@ struct VN300Data : public QuaternionData,
      */
     // cppcheck-suppress uninitDerivedMemberVar
     VN300Data()
-        : QuaternionData{0, 0.0, 0.0, 0.0, 0.0}, MagnetometerData{0, 0.0, 0.0,
-                                                                  0.0},
-          AccelerometerData{0, 0.0, 0.0, 0.0}, GyroscopeData{0, 0.0, 0.0, 0.0},
-          TemperatureData{0, 0.0}, PressureData{0, 0.0}
+        : QuaternionData{0, 0.0, 0.0, 0.0, 0.0},
+          MagnetometerData{0, 0.0, 0.0, 0.0}, AccelerometerData{0, 0.0, 0.0,
+                                                                0.0},
+          GyroscopeData{0, 0.0, 0.0, 0.0}, Ins_Lla{0,   0.0, 0,   0,   0.0, 0.0,
+                                                   0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
+                                                   0.0}
     {
     }
 
@@ -71,11 +101,9 @@ struct VN300Data : public QuaternionData,
     // cppcheck-suppress passedByValue
     // cppcheck-suppress uninitDerivedMemberVar
     VN300Data(QuaternionData quat, MagnetometerData magData,
-              AccelerometerData accData, GyroscopeData gyro,
-              TemperatureData temp, PressureData pres)
+              AccelerometerData accData, GyroscopeData gyro, Ins_Lla ins)
         : QuaternionData(quat), MagnetometerData(magData),
-          AccelerometerData(accData), GyroscopeData(gyro),
-          TemperatureData(temp), PressureData(pres)
+          AccelerometerData(accData), GyroscopeData(gyro), Ins_Lla(ins)
     {
     }
 
@@ -85,9 +113,11 @@ struct VN300Data : public QuaternionData,
                "magneticFieldX,magneticFieldY,magneticFieldZ,"
                "accelerationTimestamp,accelerationX,accelerationY,"
                "accelerationZ,angularSpeedTimestamp,angularSpeedX,"
-               "angularSpeedY,angularSpeedZ,temperatureTimestamp,"
-               "temperature,pressureTimestamp,pressure\n";
+               "angularSpeedY,angularSpeedZ,insTimeStamp,"
+               "time_gps,week,status,yaw,pitch,roll,latitude,"
+               "longitude,altitude,nedVelX,nedVelY,nedVelZ\n";
     }
+
     void print(std::ostream& os) const
     {
         os << quatTimestamp << "," << quatX << "," << quatY << "," << quatZ
@@ -96,10 +126,11 @@ struct VN300Data : public QuaternionData,
            << "," << accelerationTimestamp << "," << accelerationX << ","
            << accelerationY << "," << accelerationZ << ","
            << angularSpeedTimestamp << "," << angularSpeedX << ","
-           << angularSpeedY << "," << angularSpeedZ << ","
-           << temperatureTimestamp << "," << temperature << ","
-           << pressureTimestamp << "," << pressure << "\n";
+           << angularSpeedY << "," << angularSpeedZ << "," << insTimestamp
+           << "," << time_gps << "," << week << "," << status << yaw << pitch
+           << roll << latitude << longitude << altitude << nedVelX << nedVelY
+           << nedVelZ << "\n";
     }
 };
 
-}  // namespace Boardcore
\ No newline at end of file
+}  // namespace Boardcore