Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
nps_ivy.c
Go to the documentation of this file.
1#include "nps_ivy.h"
2
3#include <stdlib.h>
4#include <stdio.h>
5#include <sys/types.h>
6#include <unistd.h>
7#include <Ivy/ivy.h>
8
9#include <Ivy/ivyloop.h>
10#include <Ivy/timer.h>
11
12#include "generated/airframe.h"
15#include "nps_main.h"
16#include "nps_autopilot.h"
17#include "nps_fdm.h"
18#include "nps_sensors.h"
19#include "nps_atmosphere.h"
20
21#include "generated/settings.h"
22#include "pprzlink/dl_protocol.h"
24
25#if USE_GPS
26#include "modules/gps/gps.h"
27#endif
28
31static int seq = 1;
32static int ap_launch_index;
33
34/* Gaia Ivy functions */
35static void on_WORLD_ENV(IvyClientPtr app __attribute__((unused)),
36 void *user_data __attribute__((unused)),
37 int argc, char *argv[]);
38
39/* Datalink Ivy functions */
40static void on_DL_SETTING(IvyClientPtr app __attribute__((unused)),
41 void *user_data __attribute__((unused)),
42 int argc, char *argv[]);
43
44/* Telemetry display period in milliseconds (10 Hz). */
45#define NPS_IVY_DISPLAY_PERIOD_MS ((long)(3 * DISPLAY_DT * 1000))
46
47/* Repeating Ivy timer that drives the periodic telemetry. */
49
50int find_launch_index(void);
51
52/*
53 * Periodic telemetry callback.
54 *
55 * Driven by an Ivy timer instead of a before-select hook: IvyMainLoop bounds
56 * its select() timeout with TimerGetSmallestTimeout(), so this fires on
57 * schedule even when the Ivy bus is completely idle (no telemetry lag). It
58 * runs in the IvyMainLoop thread, so IvySendMsg stays single-threaded.
59 */
60static void nps_ivy_display_cb(TimerId id __attribute__((unused)),
61 void *user_data __attribute__((unused)),
62 unsigned long delta __attribute__((unused)))
63{
64#ifdef PRINT_TIME
65 if ((long)delta > NPS_IVY_DISPLAY_PERIOD_MS) {
66 printf("IVY DISPLAY: timer late, %lu [ms] elapsed for a %ld [ms] period\n",
68 }
69#endif
71}
72
73void nps_ivy_init(char *ivy_bus, bool nodisplay)
74{
75 const char *agent_name = AIRFRAME_NAME"_NPS";
76 const char *ready_msg = AIRFRAME_NAME"_NPS Ready";
78
79 // bind on a general WORLD_ENV (not a reply to request)
80 IvyBindMsg(on_WORLD_ENV, NULL, "^(\\S*) WORLD_ENV (\\S*) (\\S*) (\\S*) (\\S*) (\\S*) (\\S*)");
81
82 // to be able to change datalink_enabled setting back on
83 IvyBindMsg(on_DL_SETTING, NULL, "^(\\S*) DL_SETTING (\\S*) (\\S*) (\\S*)");
84
85 // Drive periodic telemetry from a repeating Ivy timer (only if display is on).
86 // The timer bounds IvyMainLoop's select() timeout via TimerGetSmallestTimeout(),
87 // guaranteeing the telemetry cadence regardless of bus activity (no lag on a
88 // completely idle bus).
89 if (!nodisplay) {
92 }
93
94#ifdef __APPLE__
95 const char *default_ivy_bus = "224.255.255.255";
96#else
97 const char *default_ivy_bus = "127.255.255.255";
98#endif
99 if (ivy_bus == NULL) {
101 } else {
102 IvyStart(ivy_bus);
103 }
104
106
108}
109
110/*
111 * Parse WORLD_ENV message from gaia.
112 *
113 */
114static void on_WORLD_ENV(IvyClientPtr app __attribute__((unused)),
115 void *user_data __attribute__((unused)),
116 int argc, char *argv[])
117{
118 if (argc < 6) { return; }
119
120 // wind speed in m/s
121 struct FloatVect3 wind;
122 wind.x = atof(argv[1]); //east
123 wind.y = atof(argv[2]); //north
124 wind.z = atof(argv[3]); //up
125
126 /* set wind speed in NED */
127 nps_atmosphere_set_wind_ned(wind.y, wind.x, -wind.z);
128
129 /* not used so far */
130 //float ir_contrast = atof(argv[4]);
131
132 /* set new time factor */
134
135#if USE_GPS
136 // directly set gps fix in modules/gps/gps_sim_nps.h
137 gps_has_fix = atoi(argv[6]); // gps_availability
138#endif
139
140}
141
142/*
143 * Send a WORLD_ENV_REQ message
144 */
145
146
148{
149 // First unbind from previous request if needed
150 if (ivyPtr != NULL) {
152 ivyPtr = NULL;
153 }
154
155 int pid = (int)getpid();
156
157 // Bind to the reply
158 ivyPtr = IvyBindMsg(on_WORLD_ENV, NULL, "^%d_%d (\\S*) WORLD_ENV (\\S*) (\\S*) (\\S*) (\\S*) (\\S*) (\\S*)", pid, seq);
159
160 // Send actual request
161 struct NpsFdm fdm_ivy;
163 memcpy(&fdm_ivy, &fdm, sizeof(struct NpsFdm));
165
166 IvySendMsg("nps %d_%d WORLD_ENV_REQ %f %f %f %f %f %f",
167 pid, seq,
168 DegOfRad(fdm_ivy.lla_pos_pprz.lat),
169 DegOfRad(fdm_ivy.lla_pos_pprz.lon),
170 (fdm_ivy.hmsl),
171 (fdm_ivy.ltpprz_pos.x),
172 (fdm_ivy.ltpprz_pos.y),
173 (fdm_ivy.ltpprz_pos.z));
174 seq++;
175}
176
178{
179#ifdef AP_LAUNCH
180 return AP_LAUNCH - 1; // index of AP_LAUNCH starts at 1, but it should be 0 here
181#else
182#if NB_SETTING > 0
183 static const char ap_launch[] = "aut_lau"; // short name
185
186 // list through the settings
187 // TODO: maybe search for a substring with if(strstr(sent, word) != NULL)
188 for (uint8_t idx=0;idx<NB_SETTING;idx++) {
189 if (strcmp(ap_settings[idx],ap_launch) == 0) {
190 return (int)idx;
191 }
192 }
193#endif
194 return -1;
195#endif
196}
197
198static void on_DL_SETTING(IvyClientPtr app __attribute__((unused)),
199 void *user_data __attribute__((unused)),
200 int argc, char *argv[])
201{
202 if (argc < 3) { return; }
203
204 if (atoi(argv[1]) != AC_ID) {
205 return;
206 }
207
208 /* HACK:
209 * we actually don't want to allow changing settings if datalink is disabled,
210 * but since we currently change this variable via settings we have to allow it
211 * TODO: only allow changing the datalink_enabled setting
212 */
213 uint8_t index = atoi(argv[2]);
214 float value = atof(argv[3]);
215#ifndef HITL
216 if (!datalink_enabled) {
217 DlSetting(index, value);
219 }
220#endif
221 printf("setting %d %f\n", index, value);
222
223 /*
224 * In case of HITL, update nps_autopilot.launch from DL_SETTINGS
225 * so the plane can be properly launched.
226 *
227 * In case of STIL nps_update_launch_from_dl() is an empty function
228 */
229 if ((ap_launch_index >= 0) || (ap_launch_index < NB_SETTING)) {
230 if (index==ap_launch_index){
232 }
233 }
234}
235
236
238{
239 struct NpsFdm fdm_ivy;
240 struct NpsSensors sensors_ivy;
241
242 // make a local copy with mutex
243 bool do_world_env_req;
245 memcpy(&fdm_ivy, fdm_data, sizeof(fdm));
250
251 IvySendMsg("%d NPS_RATE_ATTITUDE %f %f %f %f %f %f",
252 AC_ID,
253 DegOfRad(fdm_ivy.body_ecef_rotvel.p),
254 DegOfRad(fdm_ivy.body_ecef_rotvel.q),
255 DegOfRad(fdm_ivy.body_ecef_rotvel.r),
256 DegOfRad(fdm_ivy.ltp_to_body_eulers.phi),
257 DegOfRad(fdm_ivy.ltp_to_body_eulers.theta),
258 DegOfRad(fdm_ivy.ltp_to_body_eulers.psi));
259 IvySendMsg("%d NPS_POS_LLH %f %f %f %f %f %f %f %f %f",
260 AC_ID,
261 (fdm_ivy.lla_pos_pprz.lat),
262 (fdm_ivy.lla_pos_geod.lat),
263 (fdm_ivy.lla_pos_geoc.lat),
264 (fdm_ivy.lla_pos_pprz.lon),
265 (fdm_ivy.lla_pos_geod.lon),
266 (fdm_ivy.lla_pos_pprz.alt),
267 (fdm_ivy.lla_pos_geod.alt),
268 (fdm_ivy.agl),
269 (fdm_ivy.hmsl));
270 IvySendMsg("%d NPS_SPEED_POS %f %f %f %f %f %f %f %f %f",
271 AC_ID,
272 (fdm_ivy.ltpprz_ecef_accel.x),
273 (fdm_ivy.ltpprz_ecef_accel.y),
274 (fdm_ivy.ltpprz_ecef_accel.z),
275 (fdm_ivy.ltpprz_ecef_vel.x),
276 (fdm_ivy.ltpprz_ecef_vel.y),
277 (fdm_ivy.ltpprz_ecef_vel.z),
278 (fdm_ivy.ltpprz_pos.x),
279 (fdm_ivy.ltpprz_pos.y),
280 (fdm_ivy.ltpprz_pos.z));
281 IvySendMsg("%d NPS_GYRO_BIAS %f %f %f",
282 AC_ID,
283 DegOfRad(RATE_FLOAT_OF_BFP(sensors_ivy.gyro.bias_random_walk_value.x) + sensors_ivy.gyro.bias_initial.x),
284 DegOfRad(RATE_FLOAT_OF_BFP(sensors_ivy.gyro.bias_random_walk_value.y) + sensors_ivy.gyro.bias_initial.y),
285 DegOfRad(RATE_FLOAT_OF_BFP(sensors_ivy.gyro.bias_random_walk_value.z) + sensors_ivy.gyro.bias_initial.z));
286
287 /* transform magnetic field to body frame */
288 struct DoubleVect3 h_body;
289 double_quat_vmult(&h_body, &fdm_ivy.ltp_to_body_quat, &fdm_ivy.ltp_h);
290
291 IvySendMsg("%d NPS_SENSORS_SCALED %f %f %f %f %f %f",
292 AC_ID,
293 ((sensors_ivy.accel.value.x - sensors_ivy.accel.neutral.x) / NPS_ACCEL_SENSITIVITY_XX),
294 ((sensors_ivy.accel.value.y - sensors_ivy.accel.neutral.y) / NPS_ACCEL_SENSITIVITY_YY),
295 ((sensors_ivy.accel.value.z - sensors_ivy.accel.neutral.z) / NPS_ACCEL_SENSITIVITY_ZZ),
296 h_body.x,
297 h_body.y,
298 h_body.z);
299
300 IvySendMsg("%d NPS_WIND %f %f %f",
301 AC_ID,
302 fdm_ivy.wind.x,
303 fdm_ivy.wind.y,
304 fdm_ivy.wind.z);
305
306 if (do_world_env_req) {
308 }
309}
310
311void nps_ivy_run(void)
312{
313 IvyMainLoop();
314}
#define sensors(...)
Device independent GPS code (interface)
bool gps_has_fix
Definition gps_sim_nps.c:30
void double_quat_vmult(struct DoubleVect3 *v_out, struct DoubleQuat *q, struct DoubleVect3 *v_in)
#define RATE_FLOAT_OF_BFP(_ai)
uint16_t foo
Definition main_demo5.c:58
void nps_atmosphere_set_wind_ned(double wind_north, double wind_east, double wind_down)
Atmosphere model (pressure, wind) for NPS.
struct NpsFdm fdm
Holds all necessary NPS FDM state information.
void nps_ivy_init(char *ivy_bus, bool nodisplay)
Definition nps_ivy.c:73
static void on_DL_SETTING(IvyClientPtr app, void *user_data, int argc, char *argv[])
Definition nps_ivy.c:198
#define NPS_IVY_DISPLAY_PERIOD_MS
Definition nps_ivy.c:45
void nps_ivy_run(void)
Definition nps_ivy.c:311
static TimerId nps_ivy_display_timer
Definition nps_ivy.c:48
void nps_ivy_send_WORLD_ENV_REQ(void)
Definition nps_ivy.c:147
static void nps_ivy_display_cb(TimerId id, void *user_data, unsigned long delta)
Definition nps_ivy.c:60
static void on_WORLD_ENV(IvyClientPtr app, void *user_data, int argc, char *argv[])
Definition nps_ivy.c:114
bool nps_ivy_send_world_env
Definition nps_ivy.c:29
static MsgRcvPtr ivyPtr
Definition nps_ivy.c:30
static int seq
Definition nps_ivy.c:31
static int ap_launch_index
Definition nps_ivy.c:32
void nps_ivy_display(struct NpsFdm *fdm_data, struct NpsSensors *sensors_data)
Definition nps_ivy.c:237
int find_launch_index(void)
Definition nps_ivy.c:177
void nps_update_launch_from_dl(uint8_t value)
void nps_set_time_factor(float time_factor)
pthread_mutex_t fdm_mutex
static uint32_t idx
Paparazzi double precision floating point algebra.
Paparazzi floating point algebra.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.