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) {