Skyward boardcore
Loading...
Searching...
No Matches
VN300.cpp
Go to the documentation of this file.
1/* Copyright (c) 2023 Skyward Experimental Rocketry
2 * Authors: Lorenzo Cucchi, Fabrizio Monti
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#include "VN300.h"
24
26#include <utils/Debug.h>
27
28namespace Boardcore
29{
30
31VN300::VN300(USART& usart, int userBaudRate,
32 VN300Defs::SampleOptions sampleOption, CRCOptions crc,
33 std::chrono::milliseconds timeout,
34 const VN300Defs::AntennaPosition antPosA,
35 const VN300Defs::AntennaPosition antPosB,
36 const Eigen::Matrix3f rotMat)
37 : VNCommonSerial(usart, userBaudRate, "VN300", crc, timeout),
38 sampleOption(sampleOption), antPosA(antPosA), antPosB(antPosB),
39 rotMat(rotMat)
40{
41}
42
44{
45 SensorErrors backup = lastError;
46
47 // If already initialized
48 if (isInit)
49 {
51 LOG_WARN(logger, "Sensor VN300 already initialized");
52 return false;
53 }
54
55 // Allocate the pre loaded strings based on the user selected crc
57 preSampleBin1 = "$VNBOM,1*749D\n";
58 else
59 preSampleBin1 = "$VNBOM,1*45\n";
60
61 // Set the error to init fail and if the init process goes without problem
62 // i restore it to the last error
64
65 if (recvString.data() == NULL)
66 {
67 LOG_ERR(logger, "Unable to initialize the receive VN300 string");
68 return false;
69 }
70
72
73 if (!setCrc(false))
74 {
75 LOG_ERR(logger, "Unable to set the vn300 user selected CRC");
76 return false;
77 }
78
79 if (!disableAsyncMessages(false))
80 {
81 LOG_ERR(logger, "Unable to disable async messages from vn300");
82 return false;
83 }
84
86 {
87 LOG_ERR(logger, "Unable to config the user vn300 serial port");
88 return false;
89 }
90
91 if (!verifyModelNumber("VN-300T-CR"))
92 {
93 LOG_ERR(logger, "Error, model number not corresponding");
95 return false;
96 }
97
98 if (!setBinaryOutput())
99 {
100 LOG_ERR(logger, "Unable to set binary output register");
101 return false;
102 }
103
104 if (!setAntennaA(antPosA))
105 {
106 LOG_ERR(logger, "Unable to set antenna A position");
107 return false;
108 }
109
110 if (!setCompassBaseline(antPosB))
111 {
112 LOG_ERR(logger, "Unable to set compass baseline");
113 return false;
114 }
115
116 if (!setReferenceFrame(rotMat))
117 {
118 LOG_ERR(logger, "Unable to set reference frame rotation");
119 return false;
120 }
121
122 // I need to repeat this in case of a non default
123 // serial port communication at the beginning
124 if (!setCrc(true))
125 {
126 LOG_ERR(logger, "Unable to set the vn300 user selected CRC");
127 return false;
128 }
129
130 if (!disableAsyncMessages(true))
131 {
132 LOG_ERR(logger, "Unable to disable async messages from vn300");
133 return false;
134 }
135
136 isInit = true;
137
138 // All good i restore the actual last error
139 lastError = backup;
140
141 return true;
142}
143
144bool VN300::selfTest() { return true; }
145
147{
148 D(assert(isInit && "init() was not called"));
149
150 // Reset any errors
152
153 if (sampleOption == VN300Defs::SampleOptions::FULL)
154 {
155 return sampleFull();
156 }
157 else if (sampleOption == VN300Defs::SampleOptions::REDUCED)
158 {
159 return sampleReduced();
160 }
161 else
162 {
163 // Sample option not implemented
165 return lastSample;
166 }
167}
168
169VN300Data VN300::sampleFull()
170{
171 VN300Data data;
172 VN300Defs::BinaryDataFull bindataFull;
173
174 const uint64_t timestamp = TimestampTimer::getTimestamp();
175
176 bool sampleOutcome =
177 false; // True if a valid sample was retrieved from the sensor
178 bool validChecksum = false;
179
180 sampleOutcome =
181 getBinaryOutput<VN300Defs::BinaryDataFull>(bindataFull, preSampleBin1);
182 if (!sampleOutcome)
184
185 validChecksum =
187 calculateChecksum16(reinterpret_cast<uint8_t*>(&bindataFull),
188 sizeof(bindataFull)) == 0;
189 if (sampleOutcome && !validChecksum)
191
192 // Verify if the sample is valid
193 sampleOutcome = sampleOutcome && validChecksum;
194
195 if (sampleOutcome)
196 {
197 buildBinaryDataFull(bindataFull, data, timestamp);
198 return data;
199 }
200 else
201 {
202 // Last error is already set
203 return lastSample;
204 }
205}
206
207VN300Data VN300::sampleReduced()
208{
209 VN300Data data;
210 VN300Defs::BinaryDataReduced binDataReduced;
211
212 const uint64_t timestamp = TimestampTimer::getTimestamp();
213
214 bool sampleOutcome =
215 false; // True if a valid sample was retrieved from the sensor
216 bool validChecksum = false;
217
218 sampleOutcome = getBinaryOutput<VN300Defs::BinaryDataReduced>(
219 binDataReduced, preSampleBin1);
220 if (!sampleOutcome)
222
223 validChecksum =
225 calculateChecksum16(reinterpret_cast<uint8_t*>(&binDataReduced),
226 sizeof(binDataReduced)) == 0;
227 if (sampleOutcome && !validChecksum)
229
230 // Verify if the sample is valid
231 sampleOutcome = sampleOutcome && validChecksum;
232
233 if (sampleOutcome)
234 {
235 buildBinaryDataReduced(binDataReduced, data, timestamp);
236 return data;
237 }
238 else
239 {
240 // Last error is already set
241 return lastSample;
242 }
243}
244
245void VN300::buildBinaryDataFull(const VN300Defs::BinaryDataFull& rawData,
246 VN300Data& data, const uint64_t timestamp)
247{
248 // Quaternion
249 data.quaternionTimestamp = timestamp;
250 data.quaternionW = rawData.quaternionW;
251 data.quaternionX = rawData.quaternionX;
252 data.quaternionY = rawData.quaternionY;
253 data.quaternionZ = rawData.quaternionZ;
254
255 // Accelerometer
256 data.accelerationTimestamp = timestamp;
257 data.accelerationX = rawData.accelX;
258 data.accelerationY = rawData.accelY;
259 data.accelerationZ = rawData.accelZ;
260
261 // Magnetometer
262 data.magneticFieldTimestamp = timestamp;
263 data.magneticFieldX = rawData.magneticX;
264 data.magneticFieldY = rawData.magneticY;
265 data.magneticFieldZ = rawData.magneticZ;
266
267 // Gyroscope
268 data.angularSpeedTimestamp = timestamp;
269 data.angularSpeedX = rawData.angularX;
270 data.angularSpeedY = rawData.angularY;
271 data.angularSpeedZ = rawData.angularZ;
272
273 // Gps
274 data.insTimestamp = timestamp;
275 data.gpsFix = rawData.gpsFix;
276 data.insStatus = rawData.insStatus;
277 data.yaw = rawData.yaw;
278 data.pitch = rawData.pitch;
279 data.roll = rawData.roll;
280 data.latitude = rawData.latitude;
281 data.longitude = rawData.longitude;
282 data.altitude = rawData.altitude;
283 data.velocityX = rawData.velocityX;
284 data.velocityY = rawData.velocityY;
285 data.velocityZ = rawData.velocityZ;
286}
287
288void VN300::buildBinaryDataReduced(const VN300Defs::BinaryDataReduced& rawData,
289 VN300Data& data, const uint64_t timestamp)
290{
291 data = VN300Data();
292
293 // Gps
294 data.insTimestamp = timestamp;
295 data.latitude = rawData.latitude;
296 data.longitude = rawData.longitude;
297 data.altitude = rawData.altitude;
298 data.gpsFix = rawData.gpsFix;
299
300 // Angular
301 data.angularSpeedTimestamp = timestamp;
302 data.angularSpeedX = rawData.angularX;
303 data.angularSpeedY = rawData.angularY;
304 data.angularSpeedZ = rawData.angularZ;
305
306 // Yaw pith roll
307 data.yaw = rawData.yaw;
308 data.pitch = rawData.pitch;
309 data.roll = rawData.roll;
310
311 // Quaternion
312 data.quaternionTimestamp = timestamp;
313 data.quaternionW = rawData.quaternionW;
314 data.quaternionX = rawData.quaternionX;
315 data.quaternionY = rawData.quaternionY;
316 data.quaternionZ = rawData.quaternionZ;
317
318 // Accelerometer
319 data.accelerationTimestamp = timestamp;
320 data.accelerationX = rawData.accelX;
321 data.accelerationY = rawData.accelY;
322 data.accelerationZ = rawData.accelZ;
323}
324
325bool VN300::setAntennaA(VN300Defs::AntennaPosition antPos)
326{
327 std::string command = fmt::format("{}{},{},{}", "VNWRG,57,", antPos.posX,
328 antPos.posY, antPos.posZ);
329
331 if (!sendStringCommand(command))
332 return false;
333
335 return false;
336
337 if (checkErrorVN(recvString.data()))
338 return false;
339
340 return true;
341}
342
343bool VN300::setCompassBaseline(VN300Defs::AntennaPosition antPos)
344{
345 std::string command = fmt::format("{}{},{},{},{},{},{}", "VNWRG,93,",
346 antPos.posX, antPos.posY, antPos.posZ,
347 antPos.uncX, antPos.uncY, antPos.uncZ);
348
350 if (!sendStringCommand(command))
351 return false;
352
354 return false;
355
356 if (checkErrorVN(recvString.data()))
357 return false;
358
359 return true;
360}
361
362bool VN300::setReferenceFrame(Eigen::Matrix3f rotMat)
363{
364 std::string command =
365 fmt::format("{}{},{},{},{},{},{},{},{},{}", "VNWRG,26,", rotMat(0, 0),
366 rotMat(0, 1), rotMat(0, 2), rotMat(1, 0), rotMat(1, 1),
367 rotMat(1, 2), rotMat(2, 0), rotMat(2, 1), rotMat(2, 2));
368
370 if (!sendStringCommand(command))
371 return false;
372
374 return false;
375
376 if (checkErrorVN(recvString.data()))
377 return false;
378
379 return true;
380}
381
382bool VN300::setBinaryOutput()
383{
384 uint16_t outputGroup = 0, commonGroup = 0, gnssGroup = 0;
385
386 switch (sampleOption)
387 {
389 outputGroup =
391
399
402 break;
404 outputGroup =
411
412 break;
413 }
414
415 // "0" means that no asynchronous message is active
416 // "8" represents the divider at which the asynchronous message is sent with
417 // respect to the max rate
418 const char* const comp = "VNWRG,75,0,8";
419
420 std::string command = fmt::format("{},{},{:x},{:x}", comp, outputGroup,
421 commonGroup, gnssGroup);
422
424
425 if (!sendStringCommand(command))
426 return false;
427
429 {
430 LOG_WARN(logger, "Unable to sample due to serial communication error");
431 return false;
432 }
433
434 if (checkErrorVN(recvString.data()) != 0)
435 {
436 LOG_WARN(logger, "Error while setting binary output: {}",
437 recvString.data());
438 return false;
439 }
440
441 return true;
442}
443
444} // namespace Boardcore
#define D(x)
Definition Debug.h:57
#define LOG_WARN(logger,...)
#define LOG_ERR(logger,...)
SensorErrors lastError
Definition Sensor.h:54
Driver for STM32F4 low level USART/UART peripheral.
Definition USART.h:170
void clearQueue()
Clears the rxQueue.
Definition USART.cpp:616
VN300(USART &usart, int userBaudRate, VN300Defs::SampleOptions sampleOption, CRCOptions crc, std::chrono::milliseconds timeout, VN300Defs::AntennaPosition antPosA={0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, VN300Defs::AntennaPosition antPosB={1.0, 0.0, 0.0, 0.0, 0.0, 0.0}, Eigen::Matrix3f rotMat=Eigen::Matrix3f::Identity())
Constructor.
Definition VN300.cpp:31
bool selfTest() override
Check if the sensor is working.
Definition VN300.cpp:144
bool init() override
Initialize the sensor.
Definition VN300.cpp:43
VN300Data sampleImpl() override
Sample action implementation.
Definition VN300.cpp:146
uint8_t checkErrorVN(const char *message)
Check if the message received from the sensor contains an error.
uint16_t calculateChecksum16(const uint8_t *message, int length)
Calculate the 16bit array on the given array.
bool setCrc(bool waitResponse=true)
Sets the user selected crc method.
static const uint8_t recvStringMaxDimension
Maximum size of the receiving string.
bool verifyModelNumber(const char *expectedModelNumber)
Verify the model number of the sensor.
bool disableAsyncMessages(bool waitResponse)
Disables the async messages that the sensor is default configured to send at 40Hz on startup.
std::array< char, recvStringMaxDimension > recvString
Buffer used to store the string received from the sensor.
bool recvStringCommand(char *command, int maxLength)
Receives a command from the sensor but swaps the first with a \0 to close the message.
bool configUserSerialPort()
Configures the user defined serial communication.
void configDefaultSerialPort()
Configures the default serial communication.
bool sendStringCommand(std::string command)
Sends the command to the sensor with the correct checksum added so '*' symbol is not needed at the en...
USART & usart
Serial interface that is needed to communicate with the sensor via ASCII codes.
uint64_t getTimestamp()
Returns the current timer value in microseconds.
@ COMMONGROUP_VELOCITY
Velocity.
Definition VN300Defs.h:59
@ COMMONGROUP_YAWPITCHROLL
Yaw pitch roll.
Definition VN300Defs.h:55
@ COMMONGROUP_ACCEL
Acceleration compensated (body).
Definition VN300Defs.h:60
@ COMMONGROUP_ANGULARRATE
Angular Rate.
Definition VN300Defs.h:57
@ COMMONGROUP_INSSTATUS
Ins status.
Definition VN300Defs.h:65
@ COMMONGROUP_QUATERNION
Quaternion.
Definition VN300Defs.h:56
@ COMMONGROUP_MAGPRES
Compensated magnetic, temperature and pressure.
Definition VN300Defs.h:62
@ BINARYGROUP_COMMON
Common group.
Definition VN300Defs.h:36
@ BINARYGROUP_GPS
GPS group.
Definition VN300Defs.h:39
SampleOptions
Sample options (data output packets) available.
Definition VN300Defs.h:210
@ REDUCED
Only data needed for the reduced data packet.
@ GPSGROUP_NUMSATS
Number of tracked satellites.
Definition VN300Defs.h:119
@ GPSGROUP_POSLLA
Gps position (latitude, longitude, altitude).
Definition VN300Defs.h:121
@ GPSGROUP_FIX
Gps fix.
Definition VN300Defs.h:120
This file includes all the types the logdecoder script will decode.
SensorErrors
Generic error codes that a sensor can generate.
Definition SensorData.h:38
@ INVALID_WHOAMI
Definition SensorData.h:40
@ COMMAND_FAILED
Definition SensorData.h:49
Data class for VN300.
Definition VN300Data.h:51
Structure to handle antenna A position units [m].
Definition VN300Defs.h:178