diff --git a/src/shared/sensors/Vectornav/VN300/VN300.cpp b/src/shared/sensors/Vectornav/VN300/VN300.cpp index fe1d007b6cec4e6a2292d6fb19200bfda607b7f1..d5243bced4c1d5de2f9fa2daf0c5d03c7b969272 100644 --- a/src/shared/sensors/Vectornav/VN300/VN300.cpp +++ b/src/shared/sensors/Vectornav/VN300/VN300.cpp @@ -318,10 +318,8 @@ void VN300::buildBinaryDataReduced(const VN300Defs::BinaryDataReduced& rawData, bool VN300::setAntennaA(VN300Defs::AntennaPosition antPos) { - std::string command; - - command = fmt::format("{}{},{},{}", "VNWRG,57,", antPos.posX, antPos.posY, - antPos.posZ); + std::string command = fmt::format("{}{},{},{}", "VNWRG,57,", antPos.posX, + antPos.posY, antPos.posZ); usart.clearQueue(); if (!sendStringCommand(command)) @@ -338,11 +336,9 @@ bool VN300::setAntennaA(VN300Defs::AntennaPosition antPos) bool VN300::setCompassBaseline(VN300Defs::AntennaPosition antPos) { - std::string command; - - command = fmt::format("{}{},{},{},{},{},{}", "VNWRG,93,", antPos.posX, - antPos.posY, antPos.posZ, antPos.uncX, antPos.uncY, - antPos.uncZ); + std::string command = fmt::format("{}{},{},{},{},{},{}", "VNWRG,93,", + antPos.posX, antPos.posY, antPos.posZ, + antPos.uncX, antPos.uncY, antPos.uncZ); usart.clearQueue(); if (!sendStringCommand(command)) diff --git a/src/shared/sensors/Vectornav/VNCommonSerial.cpp b/src/shared/sensors/Vectornav/VNCommonSerial.cpp index ad1a8cdd2ab70b9ca63c06ba988351b8e8bdb18b..d271510142d11d5d16d9f167e8343c9814d7ab79 100644 --- a/src/shared/sensors/Vectornav/VNCommonSerial.cpp +++ b/src/shared/sensors/Vectornav/VNCommonSerial.cpp @@ -214,10 +214,8 @@ void VNCommonSerial::configDefaultSerialPort() bool VNCommonSerial::configUserSerialPort() { - std::string command; - // I format the command to change baud rate - command = fmt::format("{}{}", "VNWRG,5,", baudRate); + std::string command = fmt::format("{}{}", "VNWRG,5,", baudRate); // I can send the command if (!sendStringCommand(command)) @@ -399,6 +397,173 @@ bool VNCommonSerial::closeAndReset() return true; } +bool VNCommonSerial::startHSIEstimator(uint8_t convergeRate) +{ + D(assert((convergeRate >= 1 && convergeRate <= 5) && + "convergeRate must be between 1 and 5")); + + // Select HSI_RUN, runs the real-time hard/soft + // iron calibration. + const uint8_t hsiMode = 1; + + // Select USE_ONBOARD, Onboard HSI is applied to + // the magnetic measurements. + const uint8_t hsiOutput = 3; + + std::string command = + fmt::format("VNWRG,44,{},{},{}", hsiMode, hsiOutput, convergeRate); + + return writeRegister(command); +} + +bool VNCommonSerial::stopHSIEstimator() +{ + // Select HSI_OFF, real-time hard/soft iron calibration + // algorithm is turned off. + const uint8_t hsiMode = 0; + + // Keep USE_ONBOARD, Onboard HSI is applied to + // the magnetic measurements. + const uint8_t hsiOutput = 3; + + // Not influent, we are stopping the algorithm + const uint8_t convergeRate = 5; + + std::string command = + fmt::format("VNWRG,44,{},{},{}", hsiMode, hsiOutput, convergeRate); + + return writeRegister(command); +} + +std::string VNCommonSerial::getHSIEstimatorValues() +{ + // Clear the receiving queue + usart.clearQueue(); + + if (!sendStringCommand("VNRRG,47")) + { + LOG_ERR(logger, "getHSIEstimatorValues: unable to send string command"); + return ""; + } + + miosix::Thread::sleep(100); + + if (!recvStringCommand(recvString.data(), recvStringMaxDimension)) + { + LOG_WARN(logger, + "getHSIEstimatorValues: unable to receive string command"); + return ""; + } + + if (!verifyChecksum(recvString.data(), recvStringLength)) + { + LOG_ERR(logger, + "getHSIEstimatorValues: checksum verification failed: {}", + recvString.data()); + return ""; + } + + return recvString.data(); +} + +bool VNCommonSerial::setMagnetometerCompensation(const Eigen::Matrix3f& c, + const Eigen::Vector3f& b) +{ + std::string command = + fmt::format("VNWRG,23,{},{},{},{},{},{},{},{},{},{},{},{}", c(0, 0), + c(0, 1), c(0, 2), c(1, 0), c(1, 1), c(1, 2), c(2, 0), + c(2, 1), c(2, 2), b(0), b(1), b(2)); + + return writeRegister(command); +} + +bool VNCommonSerial::setAccelerometerCompensation(const Eigen::Matrix3f& c, + const Eigen::Vector3f& b) +{ + std::string command = + fmt::format("VNWRG,25,{},{},{},{},{},{},{},{},{},{},{},{}", c(0, 0), + c(0, 1), c(0, 2), c(1, 0), c(1, 1), c(1, 2), c(2, 0), + c(2, 1), c(2, 2), b(0), b(1), b(2)); + + return writeRegister(command); +} + +bool VNCommonSerial::setGyroscopeCompensation(const Eigen::Matrix3f& c, + const Eigen::Vector3f& b) +{ + std::string command = + fmt::format("VNWRG,84,{},{},{},{},{},{},{},{},{},{},{},{}", c(0, 0), + c(0, 1), c(0, 2), c(1, 0), c(1, 1), c(1, 2), c(2, 0), + c(2, 1), c(2, 2), b(0), b(1), b(2)); + + return writeRegister(command); +} + +bool VNCommonSerial::saveConfiguration() +{ + // Clear the receiving queue + usart.clearQueue(); + + if (!sendStringCommand("VNWNV")) + { + LOG_ERR(logger, "saveConfiguration: unable to send string command"); + return false; + } + + // The write settings command takes ~500ms to complete + miosix::Thread::sleep(500); + + if (!recvStringCommand(recvString.data(), recvStringMaxDimension)) + { + LOG_WARN(logger, "saveConfiguration: unable to receive string command"); + return false; + } + + if (!verifyChecksum(recvString.data(), recvStringLength)) + { + LOG_ERR(logger, "saveConfiguration: checksum verification failed: {}", + recvString.data()); + return false; + } + + return true; +} + +bool VNCommonSerial::restoreFactorySettings() +{ + // Clear the receiving queue + usart.clearQueue(); + + if (!sendStringCommand("VNRFS")) + { + LOG_ERR(logger, + "restoreFactorySettings: unable to send string command"); + return false; + } + + miosix::Thread::sleep(100); + + if (!recvStringCommand(recvString.data(), recvStringMaxDimension)) + { + LOG_WARN(logger, + "restoreFactorySettings: unable to receive string command"); + return false; + } + + if (!verifyChecksum(recvString.data(), recvStringLength)) + { + LOG_ERR(logger, + "restoreFactorySettings: checksum verification failed: {}", + recvString.data()); + return false; + } + + // Everything is fine, let the sensor restart + miosix::Thread::sleep(2000); + + return true; +} + bool VNCommonSerial::sendStringCommand(std::string command) { if (crc == CRCOptions::CRC_ENABLE_8) @@ -470,4 +635,28 @@ bool VNCommonSerial::recvStringCommand(char* command, int maxLength) return true; } +bool VNCommonSerial::writeRegister(const std::string& command) +{ + usart.clearQueue(); + if (!sendStringCommand(command)) + { + LOG_ERR(logger, "Write register failed: could not send the command"); + return false; + } + + if (!recvStringCommand(recvString.data(), recvStringMaxDimension)) + { + LOG_ERR(logger, "Write register failed: recvStringCommand() failed"); + return false; + } + + if (checkErrorVN(recvString.data())) + { + LOG_ERR(logger, "Write register failed: {}", recvString.data()); + return false; + } + + return true; +} + } // namespace Boardcore diff --git a/src/shared/sensors/Vectornav/VNCommonSerial.h b/src/shared/sensors/Vectornav/VNCommonSerial.h index 66ab3a6ac685818df5256ff7536f35e57f5421b8..6fa6c14f2f1a46956b0470560e1073938eabf0ba 100644 --- a/src/shared/sensors/Vectornav/VNCommonSerial.h +++ b/src/shared/sensors/Vectornav/VNCommonSerial.h @@ -62,6 +62,83 @@ public: */ bool closeAndReset(); + /** + * @brief Start the real-time hard/soft iron calibration. The algorithm + * will continue until stopHSIEstimator() is called. + * + * @param convergeRate Controls how quickly the hard/soft iron solution + * is allowed to converge onto a new solution. + * Only values between 1 and 5 are allowed. + * 1 = Solution converges slowly over approximately 60-90 seconds. + * 5 = Solution converges rapidly over approximately 15-20 seconds. + * + * @return True if the algorithm started successfully. + */ + bool startHSIEstimator(uint8_t convergeRate); + + /** + * @brief Real-time hard/soft iron calibration algorithm is turned off. + * + * @return True if the command is accepted by the sensor. + */ + bool stopHSIEstimator(); + + /** + * @return The raw string containing the estimated hard and soft + * iron compensation parameters. + */ + std::string getHSIEstimatorValues(); + + /** + * @brief Set custom compensation parameters for the magnetometer. + * + * @param c The hard and soft iron compensation parameters. See the + * datasheet for details. + * @param b The hard and soft iron compensation parameters. See the + * datasheet for details. Unit of measurement [Gauss] + * @return True if operation succeeded. + */ + bool setMagnetometerCompensation(const Eigen::Matrix3f& c, + const Eigen::Vector3f& b); + + /** + * @brief Set custom compensation parameters for the accelerometer. + * + * @param c The accelerometer compensation parameters. See the + * datasheet for details. + * @param b The accelerometer compensation parameters. See the + * datasheet for details. Unit of measurement [m/s^2] + * @return True if operation succeeded. + */ + bool setAccelerometerCompensation(const Eigen::Matrix3f& c, + const Eigen::Vector3f& b); + + /** + * @brief Set custom compensation parameters for the gyroscope. + * + * @param c The gyroscope compensation parameters. See the + * datasheet for details. + * @param b The gyroscope compensation parameters. See the + * datasheet for details. Unit of measurement [rad/s] + * @return True if operation succeeded. + */ + bool setGyroscopeCompensation(const Eigen::Matrix3f& c, + const Eigen::Vector3f& b); + + /** + * @brief Write the current register settings into non-volatile + * memory. Once the settings are stored in non-volatile (Flash) + * memory, the VN module can be power cycled or reset, and + * the register will be reloaded from non-volatile memory. + */ + bool saveConfiguration(); + + /** + * @brief Restore the VN module’s factory default settings and + * reset the module. + */ + bool restoreFactorySettings(); + protected: /** * @brief Calculate the 8bit checksum on the given array. @@ -204,6 +281,17 @@ protected: */ bool recvStringCommand(char* command, int maxLength); + /** + * @brief Utility function used to set a register on the sensor. + * This function relies on sendStringCommand: DO NOT USE THIS FUNCTION + * IF LOW EXECUTION TIME IS NEEDED. + * + * @param command Write command to be sent to the sensor. + * + * @return True if operation succeeded. + */ + bool writeRegister(const std::string& command); + /** * @brief Serial interface that is needed to communicate * with the sensor via ASCII codes.