Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
NEOM9N_thread.cpp
- Committer:
- pmic
- Date:
- 2022-06-16
- Revision:
- 70:cfeea856d624
- Parent:
- 69:2cda20c51989
- Child:
- 71:4bc51407bff0
File content as of revision 70:cfeea856d624:
#include "NEOM9N_thread.h" #include <cstdint> NEOM9N::NEOM9N(PinName Tx, PinName Rx) : m_bufferedSerial(Tx, Rx), thread(osPriorityLow, 4096) { m_Ts = 0.005; // GNSS runs at 25 Hz := 0.04 sec, make sure that modulo(0.04 / m_Ts) = 0 e.g. m_Ts = 0.02, 0.005, 0.0025 m_bufferedSerial.set_baud(38400); m_bufferedSerial.set_format(8, BufferedSerial::None, 1); m_bufferedSerial.set_blocking(false); #if PRINT_FOR_DEBUG m_run_timer.start(); #endif m_pos_ecef_0.setZero(); m_pos_ecef.setZero(); m_pos_enu.setZero(); m_R_ecefToLocal_0.setIdentity(); } NEOM9N::~NEOM9N() { ticker.detach(); } void NEOM9N::StartThread() { thread.start(callback(this, &NEOM9N::update)); ticker.attach(callback(this, &NEOM9N::sendThreadFlag), std::chrono::microseconds{ static_cast<long int>( 1.0e6f * m_Ts ) }); } void NEOM9N::ZeroLocal() { // copy so it can not be updated during calculations (maybe mutex this) ubxNavPVT_t ubxNavPVT = m_ubxNavPVT; m_pos_ecef_0 = transformWGS84ToECEF(ubxNavPVT); m_R_ecefToLocal_0 = getR_ECEFToLocal(ubxNavPVT); } NEOM9N::ubxNavPVT_t NEOM9N::GetUbxNavPVT() { return m_ubxNavPVT; } bool NEOM9N::CheckAndToggleHasNewData() { if (m_has_new_data) { m_has_new_data = false; return true; } return false; } // Position in ECEF in m Eigen::Vector3f NEOM9N::GetPosECEF() { return m_pos_ecef.cast<float>(); } // Position in East-North-Up in m Eigen::Vector3f NEOM9N::GetPosENU() { return m_pos_enu.cast<float>(); } // Velocity in East-North-Up in m Eigen::Vector3f NEOM9N::GetVelENU() { Eigen::Vector3f vel_enu; vel_enu << static_cast<float>( m_ubxNavPVT.velE ) * 1e-3f, static_cast<float>( m_ubxNavPVT.velN ) * 1e-3f, -static_cast<float>( m_ubxNavPVT.velD ) * 1e-3f; return vel_enu; } // 20 - - GNSSfix Type uint8_t NEOM9N::GetFixType() { return m_ubxNavPVT.fixType; } // 23 - - Number of satellites used in Nav Solution uint8_t NEOM9N::GetNumSV() { return m_ubxNavPVT.numSV; } // 0 - ms GPS time of week of the navigation epoch uint8_t NEOM9N::GetGPSTimeOfWeek() { return m_ubxNavPVT.iTOW; } // Heading of motion (2-D) in rad wrapped to (-pi, pi) float NEOM9N::GetHeadMot() { float headMot = static_cast<float>( m_ubxNavPVT.headMot ) * 1e-5f * M_PI / 180.0f; return atan2f( sinf(headMot), cosf(headMot) ); } // 72 Heading accuracy estimate in rad (both motion and vehicle) float NEOM9N::GetHeadAcc() { return static_cast<float>( m_ubxNavPVT.headAcc ) * 1e-5f * M_PI / 180.0f; } // 40 Horizontal accuracy estimate in m float NEOM9N::GethAcc() { return static_cast<float>( m_ubxNavPVT.hAcc ) * 1e-3f; } // 44 Vertical accuracy estimate in m float NEOM9N::GetvAcc() { return static_cast<float>( m_ubxNavPVT.vAcc ) * 1e-3f; } // 68 Speed accuracy estimate in m/s float NEOM9N::GetsAcc() { return static_cast<float>( m_ubxNavPVT.sAcc ) * 1e-3f; } void NEOM9N::update() { static char buffer[256]; // buffer to readout from the SerialBuffer static char check_buffer[4]; // buffer to check if a seuenz is starting const static int msg_buffer_len = 96; // message length 94 + 2 (UBX_PAYLOAD_INDEX), do not know why +2, do not care static char msg_buffer[msg_buffer_len]; // buffer to decode message // ? | ? | PAYLOAD 92 | CK_A | CK_B static uint8_t msg_buffer_cntr = 0; static bool is_msg_sequenz = false; while(true) { ThisThread::flags_wait_any(threadFlag); if (m_bufferedSerial.readable()) { uint32_t read_len = m_bufferedSerial.read(buffer, sizeof(buffer)); for (uint32_t i = 0; i < read_len; i++) { if (is_msg_sequenz) { msg_buffer[msg_buffer_cntr++] = buffer[i]; if (msg_buffer_cntr == msg_buffer_len) { ubxNavPVT_t ubxNavPVT = decodeUbxNavPVTmsg(msg_buffer); // update fixType and numSV always m_ubxNavPVT.fixType = ubxNavPVT.fixType; m_ubxNavPVT.numSV = ubxNavPVT.numSV; if(ubxNavPVT.fixType == 3 && ubxNavPVT.numSV >= M_MIN_SATS) { m_ubxNavPVT = ubxNavPVT; m_pos_ecef = transformWGS84ToECEF(m_ubxNavPVT); m_pos_enu = m_R_ecefToLocal_0 * ( m_pos_ecef - m_pos_ecef_0 ); m_has_new_data = true; } else { m_has_new_data = false; } is_msg_sequenz = false; #if PRINT_FOR_DEBUG printf("%d, %d, %d, %d\r\n", ubxNavPVT.numSV, ubxNavPVT.lon, ubxNavPVT.lat, ubxNavPVT.height); #endif } } // shift past readings and check if a message starts check_buffer[3] = check_buffer[2]; // UBX_PVT_HEADER_0 check_buffer[2] = check_buffer[1]; // UBX_PVT_HEADER_1 check_buffer[1] = check_buffer[0]; // UBX_PVT_CLASS check_buffer[0] = buffer[i]; // UBX_PVT_ID if(check_buffer[3] == UBX_PVT_HEADER_0 && check_buffer[2] == UBX_PVT_HEADER_1 && check_buffer[1] == UBX_PVT_CLASS && check_buffer[0] == UBX_PVT_ID) { #if PRINT_FOR_DEBUG int run_time = std::chrono::duration_cast<std::chrono::microseconds>(m_run_timer.elapsed_time()).count(); m_run_timer.reset(); printf("Time since last received package: %d, MSG len: %d\r\n", run_time, msg_buffer_cntr); /* printf("%02x, %02x, %02x, %02x\r\n", msg_buffer[msg_buffer_len-4], // this makes only sense if you use msg_buffer_len = 100 msg_buffer[msg_buffer_len-3], msg_buffer[msg_buffer_len-2], msg_buffer[msg_buffer_len-1]); */ #endif is_msg_sequenz = true; msg_buffer_cntr = 0; //memset(msg_buffer, 0, sizeof(msg_buffer)); } } } } } Eigen::Vector3d NEOM9N::transformWGS84ToECEF(const ubxNavPVT_t& ubxNavPVT) { // persistent within this function const static double a = 6378137.0; // WGS | 84 Earth semimajor axis const static double e = 8.1819191 * 1e-2; // eccentricity double lon = static_cast<double>( ubxNavPVT.lon ) * 1e-7 * M_PI / 180.0; double lat = static_cast<double>( ubxNavPVT.lat ) * 1e-7 * M_PI / 180.0; double h = static_cast<double>( ubxNavPVT.height ) * 1e-3; double sin_lat = sin(lat); double cos_lat = cos(lat); double N = a / sqrt(1 - e * e * sin_lat * sin_lat); Eigen::Vector3d pos_ecef; pos_ecef << (h + N) * cos_lat * cos(lon), (h + N) * cos_lat * sin(lon), (h + (1.0 - e*e)*N) * sin_lat; return pos_ecef; } Eigen::Matrix3d NEOM9N::getR_ECEFToLocal(const ubxNavPVT_t& ubxNavPVT) { double lon = static_cast<double>(ubxNavPVT.lon) * 1e-7 * M_PI / 180.0; double lat = static_cast<double>(ubxNavPVT.lat) * 1e-7 * M_PI / 180.0; double sin_lat = sin(lat); double cos_lat = cos(lat); double sin_lon = sin(lon); double cos_lon = cos(lon); Eigen::Matrix3d R_ECEFToLocal; R_ECEFToLocal << -sin_lon, cos_lon, 0, -cos_lon*sin_lat, -sin_lat*sin_lon, cos_lat, cos_lat*cos_lon, cos_lat*sin_lon, sin_lat; return R_ECEFToLocal; } NEOM9N::ubxNavPVT_t NEOM9N::decodeUbxNavPVTmsg(const char *buf) { static ubxNavPVT_t ubxNavPVT; static uint8_t index; /* example from u-center: len = 6*16+4 = 100 = 4 + 94 + 2 09:41:53 0000 B5 62 01 07 5C 00 C8 72 AE 16 E6 07 06 09 09 29 µb..\.Èr®.æ....) 0010 35 F3 FF FF FF FF 00 84 D7 17 00 00 A4 00 00 00 5óÿÿÿÿ..×...¤... 0020 00 00 00 00 00 00 00 00 00 00 98 BD FF FF FF FF ...........½ÿÿÿÿ 0030 FF FF 00 34 F8 DF 00 00 00 00 00 00 00 00 00 00 ÿÿ.4øß.......... 0040 00 00 00 00 00 00 00 00 00 00 58 3E 0F 00 80 A8 ..........X>...¨ 0050 12 01 0F 27 00 00 EE 13 4F 2F 00 00 00 00 00 00 ...'..î.O/...... 0060 00 00 B9 53 */ // uint32_t iTOW; // 0 - - GPS time of week of the navigation epoch index = UBX_PAYLOAD_INDEX + 0; ubxNavPVT.iTOW = buf[index++]; ubxNavPVT.iTOW |= (buf[index++] << 8); ubxNavPVT.iTOW |= (buf[index++] << 16); ubxNavPVT.iTOW |= (buf[index++] << 24); // uint16_t year; // 4 - - Year (UTC) index = UBX_PAYLOAD_INDEX + 4; ubxNavPVT.year = buf[index++]; ubxNavPVT.year |= (buf[index++] << 8); // uint8_t month; // 6 - - Month, range 1..12 (UTC) index = UBX_PAYLOAD_INDEX + 6; ubxNavPVT.month = buf[index++]; // uint8_t day; // 7 - - Day of month, range 1..31 (UTC) index = UBX_PAYLOAD_INDEX + 7; ubxNavPVT.day = buf[index++]; // uint8_t hour; // 8 - - Hour of day, range 0..23 (UTC) index = UBX_PAYLOAD_INDEX + 8; ubxNavPVT.hour = buf[index++]; // uint8_t min; // 9 - - Minute of hour, range 0..59 (UTC) index = UBX_PAYLOAD_INDEX + 9; ubxNavPVT.min = buf[index++]; // uint8_t sec; // 10 - - Seconds of minute, range 0..60 (UTC) index = UBX_PAYLOAD_INDEX + 10; ubxNavPVT.sec = buf[index++]; // uint8_t fixType; // 20 - - GNSSfix Type index = UBX_PAYLOAD_INDEX + 20; ubxNavPVT.fixType = buf[index]; // uint8_t numSV; // 23 - - Number of satellites used in Nav Solution index = UBX_PAYLOAD_INDEX + 23; ubxNavPVT.numSV = buf[index]; // int32_t lon; // 24 1e-7 deg Longitude index = UBX_PAYLOAD_INDEX + 24; ubxNavPVT.lon = buf[index++]; ubxNavPVT.lon |= (buf[index++] << 8); ubxNavPVT.lon |= (buf[index++] << 16); ubxNavPVT.lon |= (buf[index++] << 24); // int32_t lat; // 28 1e-7 deg Latitude index = UBX_PAYLOAD_INDEX + 28; ubxNavPVT.lat = buf[index++]; ubxNavPVT.lat |= (buf[index++] << 8); ubxNavPVT.lat |= (buf[index++] << 16); ubxNavPVT.lat |= (buf[index++] << 24); // int32_t height; // 32 - mm Height above ellipsoid index = UBX_PAYLOAD_INDEX + 32; ubxNavPVT.height = buf[index++]; ubxNavPVT.height |= (buf[index++] << 8); ubxNavPVT.height |= (buf[index++] << 16); ubxNavPVT.height |= (buf[index++] << 24); // uint32_t hAcc; // 40 - mm Horizontal accuracy estimate index = UBX_PAYLOAD_INDEX + 40; ubxNavPVT.hAcc = buf[index++]; ubxNavPVT.hAcc |= (buf[index++] << 8); ubxNavPVT.hAcc |= (buf[index++] << 16); ubxNavPVT.hAcc |= (buf[index++] << 24); // uint32_t vAcc; // 44 - mm Vertical accuracy estimate index = UBX_PAYLOAD_INDEX + 44; ubxNavPVT.vAcc = buf[index++]; ubxNavPVT.vAcc |= (buf[index++] << 8); ubxNavPVT.vAcc |= (buf[index++] << 16); ubxNavPVT.vAcc |= (buf[index++] << 24); // int32_t velN; // 48 - mm/s NED north velocity index = UBX_PAYLOAD_INDEX + 48; ubxNavPVT.velN = buf[index++]; ubxNavPVT.velN |= (buf[index++] << 8); ubxNavPVT.velN |= (buf[index++] << 16); ubxNavPVT.velN |= (buf[index++] << 24); // int32_t velE; // 52 - mm/s NED east velocity index = UBX_PAYLOAD_INDEX + 52; ubxNavPVT.velE = buf[index++]; ubxNavPVT.velE |= (buf[index++] << 8); ubxNavPVT.velE |= (buf[index++] << 16); ubxNavPVT.velE |= (buf[index++] << 24); // int32_t velD; // 56 - mm/s NED down velocity index = UBX_PAYLOAD_INDEX + 56; ubxNavPVT.velD = buf[index++]; ubxNavPVT.velD |= (buf[index++] << 8); ubxNavPVT.velD |= (buf[index++] << 16); ubxNavPVT.velD |= (buf[index++] << 24); // int32_t gSpeed; // 60 - mm/s Ground Speed (2-D) index = UBX_PAYLOAD_INDEX + 60; ubxNavPVT.gSpeed = buf[index++]; ubxNavPVT.gSpeed |= (buf[index++] << 8); ubxNavPVT.gSpeed |= (buf[index++] << 16); ubxNavPVT.gSpeed |= (buf[index++] << 24); // int32_t headMot; // 64 1e-5 deg Heading of motion (2-D) index = UBX_PAYLOAD_INDEX + 64; ubxNavPVT.headMot = buf[index++]; ubxNavPVT.headMot |= (buf[index++] << 8); ubxNavPVT.headMot |= (buf[index++] << 16); ubxNavPVT.headMot |= (buf[index++] << 24); // uint32_t sAcc; // 68 - mm/s Speed accuracy estimate index = UBX_PAYLOAD_INDEX + 68; ubxNavPVT.sAcc = buf[index++]; ubxNavPVT.sAcc |= (buf[index++] << 8); ubxNavPVT.sAcc |= (buf[index++] << 16); ubxNavPVT.sAcc |= (buf[index++] << 24); // uint32_t headAcc; // 72 1e-5 deg Heading accuracy estimate (both motion and vehicle) index = UBX_PAYLOAD_INDEX + 72; ubxNavPVT.headAcc = buf[index++]; ubxNavPVT.headAcc |= (buf[index++] << 8); ubxNavPVT.headAcc |= (buf[index++] << 16); ubxNavPVT.headAcc |= (buf[index++] << 24); /* // int16_t magDec; // 88 1e-2 deg Magnetic declination. index = UBX_PAYLOAD_INDEX + 88; ubxNavPVT.magDec = buf[index++]; ubxNavPVT.magDec |= (buf[index++] << 8); // uint16_t magAcc; // 90 1e-2 deg Magnetic declination accuracy index = UBX_PAYLOAD_INDEX + 90; ubxNavPVT.magAcc = buf[index++]; ubxNavPVT.magAcc |= (buf[index++] << 8); */ return ubxNavPVT; } void NEOM9N::sendThreadFlag() { thread.flags_set(threadFlag); }