diff --git a/conf/airframes/LS/conf.xml b/conf/airframes/LS/conf.xml index 77789f8ec52..2f32a2e08dd 100644 --- a/conf/airframes/LS/conf.xml +++ b/conf/airframes/LS/conf.xml @@ -10,6 +10,17 @@ settings_modules="modules/gps_ubx_ucenter.xml" gui_color="#00000000ffff" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+ + + + + + + + + +
+ + + +
+ +
+ + + + + + + + + + + + + + + + +
+ + + +
+ + + + + + +
+ +
+ + +
+ +
+ + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + +
+ +
+ + + + + + + +
+ +
+ + + +
+ +
+ + + + +
+ +
+ + + + + +
+
diff --git a/conf/messages.xml b/conf/messages.xml index 50c998b964a..4ecac276e97 100644 --- a/conf/messages.xml +++ b/conf/messages.xml @@ -2451,6 +2451,13 @@ + + + + + + + diff --git a/sw/airborne/firmwares/rotorcraft/datalink.c b/sw/airborne/firmwares/rotorcraft/datalink.c index 8cf6f1a6cdd..90962c827db 100644 --- a/sw/airborne/firmwares/rotorcraft/datalink.c +++ b/sw/airborne/firmwares/rotorcraft/datalink.c @@ -131,6 +131,18 @@ void dl_parse_msg(void) break; #endif // RADIO_CONTROL_TYPE_DATALINK #if defined GPS_DATALINK + case DL_REMOTE_GPS_SMALL : + // Check if the GPS is for this AC + if (DL_REMOTE_GPS_SMALL_ac_id(dl_buffer) != AC_ID) { + break; + } + + parse_gps_datalink_small( + DL_REMOTE_GPS_SMALL_numsv(dl_buffer), + DL_REMOTE_GPS_SMALL_pos_xyz(dl_buffer), + DL_REMOTE_GPS_SMALL_speed_xy(dl_buffer)); + break; + case DL_REMOTE_GPS : // Check if the GPS is for this AC if (DL_REMOTE_GPS_ac_id(dl_buffer) != AC_ID) { break; } diff --git a/sw/airborne/subsystems/gps/gps_datalink.c b/sw/airborne/subsystems/gps/gps_datalink.c index 0bccef1c81d..1cb5d7313c2 100644 --- a/sw/airborne/subsystems/gps/gps_datalink.c +++ b/sw/airborne/subsystems/gps/gps_datalink.c @@ -30,20 +30,136 @@ #include "subsystems/gps.h" #include "subsystems/abi.h" +// #include + +#if GPS_USE_DATALINK_SMALL +#ifndef GPS_LOCAL_ECEF_ORIGIN_X +#error Local x coordinate in ECEF of the remote GPS required +#endif + +#ifndef GPS_LOCAL_ECEF_ORIGIN_Y +#error Local y coordinate in ECEF of the remote GPS required +#endif + +#ifndef GPS_LOCAL_ECEF_ORIGIN_Z +#error Local z coordinate in ECEF of the remote GPS required +#endif + +struct EcefCoor_i tracking_ecef; + +struct LtpDef_i tracking_ltp; + +struct EnuCoor_i enu_pos, enu_speed; + +struct EcefCoor_i ecef_pos, ecef_vel; + +struct LlaCoor_i lla_pos; +#endif + +bool_t gps_available; ///< Is set to TRUE when a new REMOTE_GPS packet is received and parsed + /** GPS initialization */ void gps_impl_init(void) { gps.fix = GPS_FIX_NONE; + gps_available = FALSE; gps.gspeed = 700; // To enable course setting gps.cacc = 0; // To enable course setting + + tracking_ecef.x = GPS_LOCAL_ECEF_ORIGIN_X; + tracking_ecef.y = GPS_LOCAL_ECEF_ORIGIN_Y; + tracking_ecef.z = GPS_LOCAL_ECEF_ORIGIN_Z; + + ltp_def_from_ecef_i(&tracking_ltp, &tracking_ecef); +} + +#ifdef GPS_USE_DATALINK_SMALL +// Parse the REMOTE_GPS_SMALL datalink packet +void parse_gps_datalink_small(uint8_t num_sv, uint32_t pos_xyz, uint32_t speed_xy) +{ + + // Position in ENU coordinates + enu_pos.x = (int32_t)((pos_xyz >> 22) & 0x3FF); // bits 31-22 x position in cm + if (enu_pos.x & 0x200) { + enu_pos.x |= 0xFFFFFC00; // fix for twos complements + } + enu_pos.y = (int32_t)((pos_xyz >> 12) & 0x3FF); // bits 21-12 y position in cm + if (enu_pos.y & 0x200) { + enu_pos.y |= 0xFFFFFC00; // fix for twos complements + } + enu_pos.z = (int32_t)(pos_xyz >> 2 & 0x3FF); // bits 11-2 z position in cm + // bits 1 and 0 are free + + // printf("ENU Pos: %u (%d, %d, %d)\n", pos_xyz, enu_pos.x, enu_pos.y, enu_pos.z); + + // Convert the ENU coordinates to ECEF + ecef_of_enu_point_i(&ecef_pos, &tracking_ltp, &enu_pos); + gps.ecef_pos = ecef_pos; + + lla_of_ecef_i(&lla_pos, &ecef_pos); + gps.lla_pos = lla_pos; + + enu_speed.x = (int32_t)((speed_xy >> 22) & 0x3FF); // bits 31-22 speed x in cm/s + if (enu_speed.x & 0x200) { + enu_speed.x |= 0xFFFFFC00; // fix for twos complements + } + enu_speed.y = (int32_t)((speed_xy >> 12) & 0x3FF); // bits 21-12 speed y in cm/s + if (enu_speed.y & 0x200) { + enu_speed.y |= 0xFFFFFC00; // fix for twos complements + } + enu_speed.z = 0; + + // printf("ENU Speed: %u (%d, %d, %d)\n", speed_xy, enu_speed.x, enu_speed.y, enu_speed.z); + + ecef_of_enu_vect_i(&gps.ecef_vel , &tracking_ltp , &enu_speed); + + gps.hmsl = tracking_ltp.hmsl + enu_pos.z * 10; // TODO: try to compensate for the loss in accuracy + + gps.course = (int32_t)((speed_xy >> 2) & 0x3FF); // bits 11-2 heading in rad*1e2 + if (gps.course & 0x200) { + gps.course |= 0xFFFFFC00; // fix for twos complements + } + + // printf("Heading: %d\n", gps.course); + + gps.course *= 1e5; + gps.num_sv = num_sv; + gps.tow = 0; // set time-of-weak to 0 + gps.fix = GPS_FIX_3D; // set 3D fix to true + gps_available = TRUE; // set GPS available to true + +#if GPS_USE_LATLONG + // Computes from (lat, long) in the referenced UTM zone + struct LlaCoor_f lla_f; + LLA_FLOAT_OF_BFP(lla_f, gps.lla_pos); + struct UtmCoor_f utm_f; + utm_f.zone = nav_utm_zone0; + // convert to utm + utm_of_lla_f(&utm_f, &lla_f); + // copy results of utm conversion + gps.utm_pos.east = utm_f.east * 100; + gps.utm_pos.north = utm_f.north * 100; + gps.utm_pos.alt = gps.lla_pos.alt; + gps.utm_pos.zone = nav_utm_zone0; +#endif + + // publish new GPS data + uint32_t now_ts = get_sys_time_usec(); + gps.last_msg_ticks = sys_time.nb_sec_rem; + gps.last_msg_time = sys_time.nb_sec; + if (gps.fix == GPS_FIX_3D) { + gps.last_3dfix_ticks = sys_time.nb_sec_rem; + gps.last_3dfix_time = sys_time.nb_sec; + } + AbiSendMsgGPS(GPS_DATALINK_ID, now_ts, &gps); } +#endif /** Parse the REMOTE_GPS datalink packet */ void parse_gps_datalink(uint8_t numsv, int32_t ecef_x, int32_t ecef_y, int32_t ecef_z, int32_t lat, int32_t lon, int32_t alt, int32_t hmsl, int32_t ecef_xd, int32_t ecef_yd, int32_t ecef_zd, uint32_t tow, int32_t course) { - gps.lla_pos.lat = lat; gps.lla_pos.lon = lon; gps.lla_pos.alt = alt; @@ -61,6 +177,7 @@ void parse_gps_datalink(uint8_t numsv, int32_t ecef_x, int32_t ecef_y, int32_t e gps.num_sv = numsv; gps.tow = tow; gps.fix = GPS_FIX_3D; + gps_available = TRUE; #if GPS_USE_LATLONG // Computes from (lat, long) in the referenced UTM zone diff --git a/sw/airborne/subsystems/gps/gps_datalink.h b/sw/airborne/subsystems/gps/gps_datalink.h index 41c645008b3..504ba49f9ce 100644 --- a/sw/airborne/subsystems/gps/gps_datalink.h +++ b/sw/airborne/subsystems/gps/gps_datalink.h @@ -31,8 +31,13 @@ #define GPS_DATALINK_H #include "std.h" +#include "generated/airframe.h" #define GPS_NB_CHANNELS 0 +extern bool_t gps_available; +#ifdef GPS_USE_DATALINK_SMALL +void parse_gps_datalink_small(uint8_t num_sv, uint32_t pos_xyz, uint32_t speed_xy); +#endif extern void parse_gps_datalink(uint8_t numsv, int32_t ecef_x, int32_t ecef_y, int32_t ecef_z, int32_t lat, int32_t lon, int32_t alt, int32_t hmsl, int32_t ecef_xd, int32_t ecef_yd, int32_t ecef_zd, diff --git a/sw/ground_segment/misc/natnet2ivy.c b/sw/ground_segment/misc/natnet2ivy.c index 8d745de5343..2e4dfb0f1aa 100644 --- a/sw/ground_segment/misc/natnet2ivy.c +++ b/sw/ground_segment/misc/natnet2ivy.c @@ -67,6 +67,7 @@ char *ivy_bus = "127.255.255.255:2010"; /** Sample frequency and derevitive defaults */ uint32_t freq_transmit = 30; ///< Transmitting frequency in Hz uint16_t min_velocity_samples = 4; ///< The amount of position samples needed for a valid velocity +bool small_packets = FALSE; /** Connection timeout when not receiving **/ #define CONNECTION_TIMEOUT .5 @@ -504,21 +505,50 @@ gboolean timeout_transmit_callback(gpointer data) { rigidBodies[i].x, rigidBodies[i].y, rigidBodies[i].z, rigidBodies[i].ecef_vel.x, rigidBodies[i].ecef_vel.y, rigidBodies[i].ecef_vel.z); - // Transmit the REMOTE_GPS packet on the ivy bus - IvySendMsg("0 REMOTE_GPS %d %d %d %d %d %d %d %d %d %d %d %d %d %d", aircrafts[rigidBodies[i].id].ac_id, - rigidBodies[i].nMarkers, //uint8 Number of markers (sv_num) - (int)(ecef_pos.x*100.0), //int32 ECEF X in CM - (int)(ecef_pos.y*100.0), //int32 ECEF Y in CM - (int)(ecef_pos.z*100.0), //int32 ECEF Z in CM - (int)(DegOfRad(lla_pos.lat)*1e7), //int32 LLA latitude in deg*1e7 - (int)(DegOfRad(lla_pos.lon)*1e7), //int32 LLA longitude in deg*1e7 - (int)(lla_pos.alt*1000.0), //int32 LLA altitude in mm above elipsoid - (int)(rigidBodies[i].z*1000.0), //int32 HMSL height above mean sea level in mm - (int)(rigidBodies[i].ecef_vel.x*100.0), //int32 ECEF velocity X in cm/s - (int)(rigidBodies[i].ecef_vel.y*100.0), //int32 ECEF velocity Y in cm/s - (int)(rigidBodies[i].ecef_vel.z*100.0), //int32 ECEF velocity Z in cm/s - 0, - (int)(heading*10000000.0)); //int32 Course in rad*1e7 + // Transmit the REMOTE_GPS packet on the ivy bus (either small or big) + if(small_packets) { + /* The GPS messages are most likely too large to be send over either the datalink + * The local position is an int32 and the 10 LSBs of the x and y axis are compressed into + * a single integer. The z axis is considered unsigned and only the latter 10 LSBs are + * used. + */ + uint32_t pos_xyz = (((uint32_t)(pos.x*100.0)) & 0x3FF) << 22; // bits 31-22 x position in cm + pos_xyz |= (((uint32_t)(pos.y*100.0)) & 0x3FF) << 12; // bits 21-12 y position in cm + pos_xyz |= (((uint32_t)(pos.z*100.0)) & 0x3FF) << 2; // bits 11-2 z position in cm + // bits 1 and 0 are free + + // printf("ENU Pos: %u (%.2f, %.2f, %.2f)\n", pos_xyz, pos.x, pos.y, pos.z); + + uint32_t speed_xy = (((uint32_t)(speed.x*100.0)) & 0x3FF) << 22; // bits 31-21 speed x in cm/s + speed_xy |= (((uint32_t)(speed.x*100.0)) & 0x3FF) << 12; // bits 20-10 speed y in cm/s + speed_xy |= (((uint32_t)(heading*100.0)) & 0x3FF) << 2; // bits 9-0 heading in rad*1e2 (The heading is already subsampled) + // bits 1 and 0 are free + + // printf("ENU Vel: %u (%.2f, %.2f, 0.0)\n", speed_xy, speed.x, speed.y); + + // printf("Heading: %.2f\n", heading); + + IvySendMsg("0 REMOTE_GPS_SMALL %d %d %d %d", aircrafts[rigidBodies[i].id].ac_id, // uint8 rigid body ID (1 byte) + (uint8_t)rigidBodies[i].nMarkers, // status (1 byte) + pos_xyz, //uint32 ENU X, Y and Z in CM (4 bytes) + speed_xy); //uint32 ENU velocity X, Y in cm/s and heading in rad*1e2 (4 bytes) + } + else { + IvySendMsg("0 REMOTE_GPS %d %d %d %d %d %d %d %d %d %d %d %d %d %d", aircrafts[rigidBodies[i].id].ac_id, + rigidBodies[i].nMarkers, //uint8 Number of markers (sv_num) + (int)(ecef_pos.x*100.0), //int32 ECEF X in CM + (int)(ecef_pos.y*100.0), //int32 ECEF Y in CM + (int)(ecef_pos.z*100.0), //int32 ECEF Z in CM + (int)(lla_pos.lat*10000000.0), //int32 LLA latitude in rad*1e7 + (int)(lla_pos.lon*10000000.0), //int32 LLA longitude in rad*1e7 + (int)(rigidBodies[i].z*1000.0), //int32 LLA altitude in mm above elipsoid + (int)(rigidBodies[i].z*1000.0), //int32 HMSL height above mean sea level in mm + (int)(rigidBodies[i].ecef_vel.x*100.0), //int32 ECEF velocity X in m/s + (int)(rigidBodies[i].ecef_vel.y*100.0), //int32 ECEF velocity Y in m/s + (int)(rigidBodies[i].ecef_vel.z*100.0), //int32 ECEF velocity Z in m/s + 0, + (int)(heading*10000000.0)); //int32 Course in rad*1e7 + } // Reset the velocity differentiator if we calculated the velocity if(rigidBodies[i].nVelocitySamples >= min_velocity_samples) { @@ -575,7 +605,8 @@ void print_help(char* filename) { " -offset_angle Tracking system angle offset compared to the North in degrees\n\n" " -tf Transmit frequency to the ivy bus in hertz (60)\n" - " -vel_samples Minimum amount of samples for the velocity differentiator (4)\n\n" + " -vel_samples Minimum amount of samples for the velocity differentiator (4)\n" + " -small Send small packets instead of bigger (FALSE)\n\n" " -ivy_bus Ivy bus address and port (127.255.255.255:2010)\n"; fprintf(stderr, usage, filename); @@ -697,6 +728,10 @@ static void parse_options(int argc, char** argv) { min_velocity_samples = atoi(argv[++i]); } + // Set to use small packets + else if(strcmp(argv[i], "-small") == 0) { + small_packets = TRUE; + } // Set the ivy bus else if(strcmp(argv[i], "-ivy_bus") == 0) {