#include "SIM_config.h" #if AP_SIM_GPS_UBLOX_ENABLED #include "SIM_GPS_UBLOX.h" #include using namespace SITL; /* send a UBLOX GPS message */ void GPS_UBlox::send_ubx(uint8_t msgid, uint8_t *buf, uint16_t size) { const uint8_t PREAMBLE1 = 0xb5; const uint8_t PREAMBLE2 = 0x62; const uint8_t CLASS_NAV = 0x1; uint8_t hdr[6], chk[2]; hdr[0] = PREAMBLE1; hdr[1] = PREAMBLE2; hdr[2] = CLASS_NAV; hdr[3] = msgid; hdr[4] = size & 0xFF; hdr[5] = size >> 8; chk[0] = chk[1] = hdr[2]; chk[1] += (chk[0] += hdr[3]); chk[1] += (chk[0] += hdr[4]); chk[1] += (chk[0] += hdr[5]); for (uint16_t i=0; ilongitude * 1.0e7; pos.latitude = d->latitude * 1.0e7; pos.altitude_ellipsoid = d->altitude * 1000.0f; pos.altitude_msl = d->altitude * 1000.0f; pos.horizontal_accuracy = d->horizontal_acc*1000; pos.vertical_accuracy = d->vertical_acc*1000; status.time = gps_tow.ms; status.fix_type = d->have_lock?3:0; status.fix_status = d->have_lock?1:0; status.differential_status = 0; status.res = 0; status.time_to_first_fix = 0; status.uptime = AP_HAL::millis(); velned.time = gps_tow.ms; velned.ned_north = 100.0f * d->speedN; velned.ned_east = 100.0f * d->speedE; velned.ned_down = 100.0f * d->speedD; velned.speed_2d = norm(d->speedN, d->speedE) * 100; velned.speed_3d = norm(d->speedN, d->speedE, d->speedD) * 100; velned.heading_2d = ToDeg(atan2f(d->speedE, d->speedN)) * 100000.0f; if (velned.heading_2d < 0.0f) { velned.heading_2d += 360.0f * 100000.0f; } velned.speed_accuracy = d->speed_acc * 100; // m/s -> cm/s velned.heading_accuracy = 4; memset(&sol, 0, sizeof(sol)); sol.fix_type = d->have_lock?3:0; sol.fix_status = 221; sol.satellites = d->have_lock ? d->num_sats : 3; sol.time = gps_tow.ms; sol.week = gps_tow.week; dop.time = gps_tow.ms; dop.gDOP = 65535; dop.pDOP = 65535; dop.tDOP = 65535; dop.vDOP = 200; dop.hDOP = 121; dop.nDOP = 65535; dop.eDOP = 65535; pvt.itow = gps_tow.ms; pvt.year = 0; pvt.month = 0; pvt.day = 0; pvt.hour = 0; pvt.min = 0; pvt.sec = 0; pvt.valid = 0; // invalid utc date pvt.t_acc = 0; pvt.nano = 0; pvt.fix_type = d->have_lock? 0x3 : 0; pvt.flags = 0b10000011; // carrsoln=fixed, psm = na, diffsoln and fixok pvt.flags2 =0; pvt.num_sv = d->have_lock ? d->num_sats : 3; pvt.lon = d->longitude * 1.0e7; pvt.lat = d->latitude * 1.0e7; pvt.height = d->altitude * 1000.0f; pvt.h_msl = d->altitude * 1000.0f; pvt.h_acc = d->horizontal_acc * 1000; pvt.v_acc = d->vertical_acc * 1000; pvt.velN = 1000.0f * d->speedN; pvt.velE = 1000.0f * d->speedE; pvt.velD = 1000.0f * d->speedD; pvt.gspeed = norm(d->speedN, d->speedE) * 1000; pvt.head_mot = ToDeg(atan2f(d->speedE, d->speedN)) * 1.0e5; pvt.s_acc = velned.speed_accuracy; pvt.head_acc = 38 * 1.0e5; pvt.p_dop = 65535; memset(pvt.reserved1, '\0', ARRAY_SIZE(pvt.reserved1)); pvt.headVeh = 0; memset(pvt.reserved2, '\0', ARRAY_SIZE(pvt.reserved2)); if (_sitl->gps_hdg_enabled[instance] > SITL::SIM::GPS_HEADING_NONE) { const Vector3f ant1_pos = _sitl->gps_pos_offset[instance^1].get(); const Vector3f ant2_pos = _sitl->gps_pos_offset[instance].get(); Vector3f rel_antenna_pos = ant2_pos - ant1_pos; Matrix3f rot; // project attitude back using gyros to get antenna orientation at time of GPS sample Vector3f gyro(radians(_sitl->state.rollRate), radians(_sitl->state.pitchRate), radians(_sitl->state.yawRate)); rot.from_euler(radians(_sitl->state.rollDeg), radians(_sitl->state.pitchDeg), radians(d->yaw_deg)); const float lag = _sitl->gps_delay_ms[instance] * 0.001; rot.rotate(gyro * (-lag)); rel_antenna_pos = rot * rel_antenna_pos; relposned.version = 1; relposned.iTOW = gps_tow.ms; relposned.relPosN = rel_antenna_pos.x * 100; relposned.relPosE = rel_antenna_pos.y * 100; relposned.relPosD = rel_antenna_pos.z * 100; relposned.relPosLength = rel_antenna_pos.length() * 100; relposned.relPosHeading = degrees(Vector2f(rel_antenna_pos.x, rel_antenna_pos.y).angle()) * 1.0e5; relposned.flags = gnssFixOK | diffSoln | carrSolnFixed | isMoving | relPosValid | relPosHeadingValid; } send_ubx(MSG_POSLLH, (uint8_t*)&pos, sizeof(pos)); send_ubx(MSG_STATUS, (uint8_t*)&status, sizeof(status)); send_ubx(MSG_VELNED, (uint8_t*)&velned, sizeof(velned)); send_ubx(MSG_SOL, (uint8_t*)&sol, sizeof(sol)); send_ubx(MSG_DOP, (uint8_t*)&dop, sizeof(dop)); send_ubx(MSG_PVT, (uint8_t*)&pvt, sizeof(pvt)); if (_sitl->gps_hdg_enabled[instance] > SITL::SIM::GPS_HEADING_NONE) { send_ubx(MSG_RELPOSNED, (uint8_t*)&relposned, sizeof(relposned)); } if (gps_tow.ms > _next_nav_sv_info_time) { svinfo.itow = gps_tow.ms; svinfo.numCh = 32; svinfo.globalFlags = 4; // u-blox 8/M8 // fill in the SV's with some data even though firmware does not currently use it // note that this is not using num_sats as we aren't dynamically creating this to match for (uint8_t i = 0; i < SV_COUNT; i++) { svinfo.sv[i].chn = i; svinfo.sv[i].svid = i; svinfo.sv[i].flags = (i < d->num_sats) ? 0x7 : 0x6; // sv used, diff correction data, orbit information svinfo.sv[i].quality = 7; // code and carrier lock and time synchronized svinfo.sv[i].cno = MAX(20, 30 - i); svinfo.sv[i].elev = MAX(30, 90 - i); svinfo.sv[i].azim = i; // not bothering to fill in prRes } send_ubx(MSG_SVINFO, (uint8_t*)&svinfo, sizeof(svinfo)); _next_nav_sv_info_time = gps_tow.ms + 10000; // 10 second delay } } #endif // AP_SIM_GPS_UBLOX_ENABLED