Paparazzi UAS v7.1_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
nps_fdm_crrcsim.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2013 Gautier Hattenberger
3 *
4 * Mixed with modified version of MNAV
5 *
6 * This file is part of paparazzi.
7 *
8 * paparazzi is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2, or (at your option)
11 * any later version.
12 *
13 * paparazzi is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with paparazzi; see the file COPYING. If not, write to
20 * the Free Software Foundation, 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 */
23
24
31#include "nps_fdm.h"
32
33#include <stdlib.h>
34#include <stdio.h>
35#include <netinet/in.h>
36#include <arpa/inet.h>
37#include <fcntl.h>
38#include <sys/socket.h>
39#include <sys/types.h>
40#include <unistd.h>
41
42#include "math/pprz_geodetic.h"
45#include "math/pprz_algebra.h"
47#include "math/pprz_isa.h"
48
49#include "generated/airframe.h"
50#include "generated/flight_plan.h"
51
52#ifndef NPS_CRRCSIM_HOST_IP
53#define NPS_CRRCSIM_HOST_IP "127.0.0.1"
54#endif
55
56#ifndef NPS_CRRCSIM_HOST_PORT
57#define NPS_CRRCSIM_HOST_PORT 9002
58#endif
59
60#ifndef NPS_CRRCSIM_ROLL_NEUTRAL
61#define NPS_CRRCSIM_ROLL_NEUTRAL 0.
62#endif
63
64#ifndef NPS_CRRCSIM_PITCH_NEUTRAL
65#define NPS_CRRCSIM_PITCH_NEUTRAL 0.
66#endif
67
68/* blocking */
69#define UDP_BLOCKING 0
70#define UDP_NONBLOCKING 1
71
72// type
73#define word unsigned short
74#define byte unsigned char
75
76// uNAV packet length definition
77#define IMU_PACKET_LENGTH 51
78#define GPS_PACKET_LENGTH 86
79#define AHRS_PACKET_LENGTH 93
80#define FULL_PACKET_SIZE 93
81
82
83// NpsFdm structure
84struct NpsFdm fdm;
85
86#define INPUT_BUFFER_SIZE (3*FULL_PACKET_SIZE)
87// Input buffer
88struct inputbuf {
90 byte start;
91 int length;
92};
93
94// Socket structure
101
102static struct _crrcsim crrcsim;
103
104// Reference point
105static struct LtpDef_d ltpdef;
106
107// static functions declaration
108static void open_udp(char *host, int port, int blocking);
109static void inputbuf_init(struct inputbuf *c);
110static void read_into_buffer(struct _crrcsim *io);
111static void init_ltp(void);
112static int get_msg(struct _crrcsim *io, byte *data_buffer);
113static void decode_imupacket(struct NpsFdm *fdm, byte *buffer);
114static void decode_gpspacket(struct NpsFdm *fdm, byte *buffer);
115static void decode_ahrspacket(struct NpsFdm *fdm, byte *buffer);
116static void send_servo_cmd(struct _crrcsim *io, double *commands);
117
118// NPS FDM interface
119void nps_fdm_init(double dt)
120{
121 fdm.init_dt = dt;
122 fdm.curr_dt = dt;
123 fdm.nan_count = 0;
124 fdm.pressure = -1;
126 fdm.total_pressure = -1;
128 fdm.temperature = -1;
129
130 init_ltp();
131
132 // init circfuf
134
135 printf("Starting to connect to CRRCsim server.\n");
137
138 if (crrcsim.socket < 0) {
139 printf("Connection to CRRCsim failed\n");
140 exit(0);
141 } else {
142 printf("Connection to CRRCsim succed\n");
143 }
144
145 // Send something to let crrcsim that we are here
146 double zero[] = { 0., 0., 0. };
147 send_servo_cmd(&crrcsim, zero);
148}
149
151{
152 // nothing to do
153}
154
155void nps_fdm_run_step(bool launch __attribute__((unused)), double *commands, int commands_nb)
156{
157 // read state
158 if (get_msg(&crrcsim, crrcsim.data_buffer) <= 0) {
159 return; // nothing on the socket
160 }
161
162 // send commands
164
165 //printf("new data %c %c\n", crrcsim.data_buffer[2], crrcsim.data_buffer[33]);
166 switch (crrcsim.data_buffer[2]) {
167 case 'S': /* IMU packet without GPS */
169 break;
170
171 case 'N': /* IMU packet with GPS */
172
174
175 /******************************************
176 *check GPS data packet
177 ******************************************/
178 //if(data_buffer[31]==(byte)0x55 && data_buffer[32]==(byte)0x55 && data_buffer[33]=='G')
179 if (crrcsim.data_buffer[33] == 'G') {
181 }
182 break;
183
184 case 'I': /* IMU packet with GPS and AHRS */
185
187
188 /******************************************
189 *check GPS data packet
190 ******************************************/
191 if (crrcsim.data_buffer[33] == 'G') {
193 }
194 if (crrcsim.data_buffer[66] == 'A') {
196 }
197 break;
198
199 default :
200 printf("invalid data packet...!\n");
201 } /* end case */
202
203}
204
205void nps_fdm_set_wind(double speed __attribute__((unused)),
206 double dir __attribute__((unused)))
207{
208}
209
211 double wind_east __attribute__((unused)),
212 double wind_down __attribute__((unused)))
213{
214}
215
216void nps_fdm_set_turbulence(double wind_speed __attribute__((unused)),
217 int turbulence_severity __attribute__((unused)))
218{
219}
220
221/***************************************************************************
222 ** Open and configure UDP connection
223 ****************************************************************************/
224
225static void open_udp(char *host, int port, int blocking)
226{
227 int flags;
228
229 bzero((char *) &crrcsim.addr, sizeof(crrcsim.addr));
230 crrcsim.addr.sin_family = AF_INET;
231 crrcsim.addr.sin_addr.s_addr = inet_addr(host);
232 crrcsim.addr.sin_port = htons(port);
233 crrcsim.socket = socket(AF_INET, SOCK_DGRAM, 0);
234
235 //make a nonblocking connection
236 flags = fcntl(crrcsim.socket, F_GETFL, 0);
238
239 if (connect(crrcsim.socket, (struct sockaddr *)&crrcsim.addr, sizeof(crrcsim.addr)) < 0) {
241 crrcsim.socket = -1;
242 }
243
244 if (crrcsim.socket != -1 && blocking == UDP_BLOCKING) {
245 //restore
246 fcntl(crrcsim.socket, F_SETFL, flags);
247 }
248}
249
250static void inputbuf_init(struct inputbuf *c)
251{
252 c->start = 0;
253 c->length = 0;
254}
255
256static void read_into_buffer(struct _crrcsim *io)
257{
258 struct inputbuf *c = &io->buf;
259 int res;
260
261 if (io->socket >= 0) {
262 // get latest data from the buffer (crapy but working)
263 while ((res = recv(io->socket, c->buf, INPUT_BUFFER_SIZE, 0)) > 0) {
264 c->start = 0;
265 c->length = res;
266 }
267 }
268}
269
270static void init_ltp(void)
271{
272
273 struct LlaCoor_d llh_nav0; /* Height above the ellipsoid */
274 llh_nav0.lat = RadOfDeg((double)NAV_LAT0 / 1e7);
275 llh_nav0.lon = RadOfDeg((double)NAV_LON0 / 1e7);
276 /* NAV_ALT0 = ground alt above msl, NAV_MSL0 = geoid-height (msl) over ellipsoid */
277 llh_nav0.alt = (NAV_ALT0 + NAV_MSL0) / 1000.;
278
279 struct EcefCoor_d ecef_nav0;
281
283
284 fdm.ltp_g.x = 0.;
285 fdm.ltp_g.y = 0.;
286 fdm.ltp_g.z = 0.; // accel data are already with the correct format
287
288#ifdef AHRS_H_X
289#pragma message "Using magnetic field as defined in airframe file."
293#else
294 fdm.ltp_h.x = 0.4912;
295 fdm.ltp_h.y = 0.1225;
296 fdm.ltp_h.z = 0.8624;
297#endif
298
299}
300
301static int get_msg(struct _crrcsim *io, byte *data_buffer)
302{
303 struct inputbuf *c = &io->buf;
304 int count = 0;
305 int packet_len;
306 int i;
307
309
310 while (1) {
311 /*********************************************************************
312 * Find start of packet: the header (2 bytes) starts with 0x5555
313 *********************************************************************/
314 while (c->length >= 4 && (c->buf[c->start] != (byte)0x55 || c->buf[(byte)(c->start + 1)] != (byte)0x55)) {
315 c->start++;
316 c->length--;
317 }
318 if (c->length < 4) {
319 return count;
320 }
321
322 /*********************************************************************
323 * Read packet contents
324 *********************************************************************/
325 packet_len = 0;
326 switch (c->buf[(byte)(c->start + 2)]) {
327 case 'S':
329 break;
330
331 case 'N':
333 break;
334
335 case 'I':
337 break;
338
339 default:
340 break;
341 }
342
343 if (packet_len > 0 && c->length < packet_len) {
344 return count; // not enough data
345 }
346 if (packet_len > 0) {
347 byte ib;
348 word rcvchecksum = 0;
349 word sum = 0;
350
351 for (i = 2, ib = c->start + (byte)2; i < packet_len - 2; i++, ib++) {
352 sum += c->buf[ib];
353 }
354 rcvchecksum = c->buf[ib++] << 8;
355 rcvchecksum = rcvchecksum | c->buf[ib++];
356
357 if (rcvchecksum != sum) {
358 packet_len = 0;
359 printf("checksum error\n");
360 }
361 }
362 // fill data buffer or go to next bytes
363 if (packet_len > 0) {
364 for (i = 0; i < packet_len; i++) {
365 data_buffer[i] = c->buf[c->start];
366 c->start++;
367 c->length--;
368 }
369 count++;
370 } else {
371 c->start += 3;
372 c->length -= 3;
373 }
374 }
375
376 return count;
377}
378
379// Long (32bits) in buffer are little endian in gps message
380#define LongOfBuf(_buf,_idx) (int32_t)(((uint32_t)_buf[_idx+3]<<24)|((uint32_t)_buf[_idx+2]<<16)|((uint32_t)_buf[_idx+1]<<8)|((uint32_t)_buf[_idx]))
381// Unsigned short (16bits) in buffer are little endian in gps message
382#define UShortOfBuf(_buf,_idx) (uint16_t)(((uint16_t)_buf[_idx+1]<<8)|((uint16_t)_buf[_idx]))
383// Short (16bits) in buffer are big endian in other messages
384#define ShortOfBuf(_buf,_idx) (int16_t)(((uint16_t)_buf[_idx]<<8)|((uint16_t)_buf[_idx+1]))
385
386/***************************************************************************************
387 *decode the gps data packet
388 ***************************************************************************************/
389static void decode_gpspacket(struct NpsFdm *fdm, byte *buffer)
390{
391 /* gps velocity (1e2 m/s to m/s */
392 struct NedCoor_d vel;
393 vel.x = (double)LongOfBuf(buffer, 3) * 1.0e-2;
394 vel.y = (double)LongOfBuf(buffer, 7) * 1.0e-2;
395 vel.z = (double)LongOfBuf(buffer, 11) * 1.0e-2;
396 fdm->ltp_ecef_vel = vel;
398
399 /* No airspeed from CRRCSIM?
400 * use ground speed for now, since we also don't know wind
401 */
405
406 /* gps position (1e7 deg to rad and 1e3 m to m) */
407 struct LlaCoor_d pos;
408 pos.lon = (double)LongOfBuf(buffer, 15) * 1.74533e-9;
409 pos.lat = (double)LongOfBuf(buffer, 19) * 1.74533e-9;
410 pos.alt = (double)LongOfBuf(buffer, 23) * 1.0e-3;
411
412 pos.lat += ltpdef.lla.lat;
413 pos.lon += ltpdef.lla.lon;
414 pos.alt += ltpdef.lla.alt;
415
416 fdm->lla_pos = pos;
417 ecef_of_lla_d(&fdm->ecef_pos, &pos);
418 fdm->hmsl = pos.alt - NAV_MSL0 / 1000.;
419
421
422 /* gps time */
423 fdm->time = (double)UShortOfBuf(buffer, 27);
424
425 /* in LTP pprz */
427 fdm->lla_pos_pprz = pos;
429
430#if NPS_CRRCSIM_DEBUG
431 printf("decode gps | pos %f %f %f | vel %f %f %f | time %f\n",
432 57.3 * fdm->lla_pos.lat,
433 57.3 * fdm->lla_pos.lon,
434 fdm->lla_pos.alt,
438 fdm->time);
439#endif
440}
441
442/***************************************************************************************
443 *decode the ahrs data packet
444 ***************************************************************************************/
445static void decode_ahrspacket(struct NpsFdm *fdm, byte *buffer)
446{
447 /* euler angles (0.9387340515702713e04 rad to rad) */
450 fdm->ltp_to_body_eulers.psi = (double)ShortOfBuf(buffer, 5) * 0.000106526;
452
453#if NPS_CRRCSIM_DEBUG
454 printf("decode ahrs %f %f %f\n",
455 fdm->ltp_to_body_eulers.phi * 57.3,
457 fdm->ltp_to_body_eulers.psi * 57.3);
458#endif
459}
460
461/***************************************************************************************
462 *decode the imu data packet
463 ***************************************************************************************/
464void decode_imupacket(struct NpsFdm *fdm, byte *buffer)
465{
466 /* acceleration (0.1670132517315938e04 m/s^2 to m/s^2) */
467 fdm->body_accel.x = (double)ShortOfBuf(buffer, 3) * 5.98755e-04;
468 fdm->body_accel.y = (double)ShortOfBuf(buffer, 5) * 5.98755e-04;
469 fdm->body_accel.z = (double)ShortOfBuf(buffer, 7) * 5.98755e-04;
470
471 /* since we don't get acceleration in ecef frame, use ECI for now */
475
476
477 /* angular rate (0.9387340515702713e4 rad/s to rad/s) */
478 fdm->body_inertial_rotvel.p = (double)ShortOfBuf(buffer, 9) * 1.06526e-04;
479 fdm->body_inertial_rotvel.q = (double)ShortOfBuf(buffer, 11) * 1.06526e-04;
480 fdm->body_inertial_rotvel.r = (double)ShortOfBuf(buffer, 13) * 1.06526e-04;
481
482 /* since we don't get angular velocity in ECEF frame, use the rotvel in ECI frame for now */
486
487 /* magnetic field in Gauss */
488 //fdm->mag.x = (double)ShortOfBuf(buffer,15)*6.10352e-05;
489 //fdm->mag.y = (double)ShortOfBuf(buffer,17)*6.10352e-05;
490 //fdm->mag.z = (double)ShortOfBuf(buffer,19)*6.10352e-05;
491
492 /* pressure in m and m/s */
493 //data->Ps = (double)ShortOfBuf(buffer,27)*3.05176e-01;
494 //data->Pt = (double)ShortOfBuf(buffer,29)*2.44141e-03;
495
496#if NPS_CRRCSIM_DEBUG
497 printf("decode imu | accel %f %f %f | gyro %f %f %f\n",
504#endif
505}
506
507// compatibility with OSX
508#ifdef __APPLE__
509#define MSG_NOSIGNAL SO_NOSIGPIPE
510#endif
511
512/***************************************************************************************
513 * send servo command over udp
514 ***************************************************************************************/
515static void send_servo_cmd(struct _crrcsim *io, double *commands)
516{
517 //cnt_cmd[1] = ch1:elevator, cnt_cmd[0] = ch0:aileron, cnt_cmd[2] = ch2:throttle
518 word cnt_cmd[3];
519 byte data[24] = {0,};
520 short i = 0;
521 word sum = 0;
522
523 word roll = (word)((65535 / 4) * commands[NPS_CRRCSIM_COMMAND_ROLL] + (65536 / 2));
524 word pitch = (word)((65535 / 4) * commands[NPS_CRRCSIM_COMMAND_PITCH] + (65536 / 2));
525
526 cnt_cmd[0] = roll;
527 cnt_cmd[1] = -pitch;
529
530#if NPS_CRRCSIM_DEBUG
531 printf("send servo %f %f %f | %d %d %d | %d %d\n",
532 commands[0],
533 commands[1],
534 commands[2],
535 cnt_cmd[0],
536 cnt_cmd[1],
537 cnt_cmd[2],
538 roll, pitch);
539#endif
540
541 data[0] = 0x55;
542 data[1] = 0x55;
543 data[2] = 0x53;
544 data[3] = 0x53;
545
546 //aileron ch#0,elevator ch#1,throttle ch#2
547 //aileron
548 data[4] = (byte)(cnt_cmd[0] >> 8);
549 data[5] = (byte)cnt_cmd[0];
550 //elevator
551 data[6] = (byte)(cnt_cmd[1] >> 8);
552 data[7] = (byte)cnt_cmd[1];
553 //throttle
554 data[8] = (byte)(cnt_cmd[2] >> 8);
555 data[9] = (byte)cnt_cmd[2];
556
557 //checksum
558 sum = 0xa6; //0x53+0x53
559 for (i = 4; i < 22; i++) { sum += data[i]; }
560
561 data[22] = (byte)(sum >> 8);
562 data[23] = (byte)sum;
563
564 //sendout the command packet
565 if (io->socket >= 0) {
566 send(io->socket, (char *)data, 24, MSG_NOSIGNAL);
567 }
568}
569
static const bool blocking[]
double psi
in radians
double p
in rad/s^2
double theta
in radians
double q
in rad/s^2
double phi
in radians
double r
in rad/s^2
void double_quat_of_eulers(struct DoubleQuat *q, struct DoubleEulers *e)
static double double_vect3_norm(struct DoubleVect3 *v)
#define VECT3_COPY(_a, _b)
double y
in meters
struct LlaCoor_d lla
origin of local frame in LLA
double z
in meters
double lat
in radians
double alt
in meters above WGS84 reference ellipsoid
double lon
in radians
double x
in meters
void ltp_def_from_ecef_d(struct LtpDef_d *def, struct EcefCoor_d *ecef)
void ecef_of_ned_vect_d(struct EcefCoor_d *ecef, struct LtpDef_d *def, struct NedCoor_d *ned)
void ned_of_ecef_vect_d(struct NedCoor_d *ned, struct LtpDef_d *def, struct EcefCoor_d *ecef)
void ned_of_ecef_point_d(struct NedCoor_d *ned, struct LtpDef_d *def, struct EcefCoor_d *ecef)
void ecef_of_lla_d(struct EcefCoor_d *ecef, struct LlaCoor_d *lla)
vector in EarthCenteredEarthFixed coordinates
vector in Latitude, Longitude and Altitude
definition of the local (flat earth) coordinate system
vector in North East Down coordinates Units: meters
static float pprz_isa_pressure_of_altitude(float altitude)
Get pressure in Pa from absolute altitude (using simplified equation).
Definition pprz_isa.h:117
#define PPRZ_ISA_SEA_LEVEL_PRESSURE
ISA sea level standard atmospheric pressure in Pascal.
Definition pprz_isa.h:50
uint16_t foo
Definition main_demo5.c:58
double time
Definition nps_fdm.h:46
struct NedCoor_d ltpprz_ecef_vel
velocity in ltppprz frame, wrt ECEF frame
Definition nps_fdm.h:79
struct DoubleVect3 ltp_g
Definition nps_fdm.h:104
double pressure_sl
pressure at sea level in Pascal
Definition nps_fdm.h:114
double init_dt
Definition nps_fdm.h:47
double total_pressure
total atmospheric pressure in Pascal
Definition nps_fdm.h:111
double hmsl
Definition nps_fdm.h:56
struct EcefCoor_d ecef_pos
Definition nps_fdm.h:53
struct NedCoor_d ltpprz_pos
Definition nps_fdm.h:54
struct LlaCoor_d lla_pos_pprz
Definition nps_fdm.h:58
struct DoubleRates body_inertial_rotvel
Definition nps_fdm.h:101
double airspeed
equivalent airspeed in m/s
Definition nps_fdm.h:109
struct NedCoor_d ltp_ecef_vel
velocity in LTP frame, wrt ECEF frame
Definition nps_fdm.h:74
struct DoubleVect3 ltp_h
Definition nps_fdm.h:105
double dynamic_pressure
dynamic pressure in Pascal
Definition nps_fdm.h:112
struct DoubleEulers ltp_to_body_eulers
Definition nps_fdm.h:92
double pressure
current (static) atmospheric pressure in Pascal
Definition nps_fdm.h:110
double curr_dt
Definition nps_fdm.h:48
struct DoubleQuat ltp_to_body_quat
Definition nps_fdm.h:91
struct DoubleRates body_ecef_rotvel
Definition nps_fdm.h:97
struct EcefCoor_d ecef_ecef_vel
velocity in ECEF frame, wrt ECEF frame
Definition nps_fdm.h:64
struct DoubleVect3 body_ecef_accel
acceleration in body frame, wrt ECEF frame
Definition nps_fdm.h:71
double temperature
current temperature in degrees Celcius
Definition nps_fdm.h:113
struct LlaCoor_d lla_pos
Definition nps_fdm.h:55
struct DoubleVect3 body_accel
acceleration in body frame as measured by an accelerometer (incl.
Definition nps_fdm.h:87
int nan_count
Definition nps_fdm.h:50
static void open_udp(char *host, int port, int blocking)
void nps_fdm_set_wind_ned(double wind_north, double wind_east, double wind_down)
byte data_buffer[FULL_PACKET_SIZE]
#define GPS_PACKET_LENGTH
void nps_fdm_init(double dt)
#define ShortOfBuf(_buf, _idx)
static void init_ltp(void)
static struct _crrcsim crrcsim
static void read_into_buffer(struct _crrcsim *io)
#define UShortOfBuf(_buf, _idx)
struct sockaddr_in addr
#define AHRS_PACKET_LENGTH
#define NPS_CRRCSIM_HOST_PORT
void nps_fdm_run_step(bool launch, double *commands, int commands_nb)
#define NPS_CRRCSIM_ROLL_NEUTRAL
struct inputbuf buf
static int get_msg(struct _crrcsim *io, byte *data_buffer)
#define NPS_CRRCSIM_PITCH_NEUTRAL
static void inputbuf_init(struct inputbuf *c)
#define byte
static void send_servo_cmd(struct _crrcsim *io, double *commands)
#define UDP_BLOCKING
static void decode_ahrspacket(struct NpsFdm *fdm, byte *buffer)
#define word
#define UDP_NONBLOCKING
#define IMU_PACKET_LENGTH
#define INPUT_BUFFER_SIZE
#define NPS_CRRCSIM_HOST_IP
#define FULL_PACKET_SIZE
void nps_fdm_set_turbulence(double wind_speed, int turbulence_severity)
static void decode_imupacket(struct NpsFdm *fdm, byte *buffer)
#define LongOfBuf(_buf, _idx)
void nps_fdm_set_wind(double speed, double dir)
void nps_fdm_run_init_step(void)
struct NpsFdm fdm
static void decode_gpspacket(struct NpsFdm *fdm, byte *buffer)
static struct LtpDef_d ltpdef
byte buf[INPUT_BUFFER_SIZE]
Paparazzi generic algebra macros.
Paparazzi floating point algebra.
Paparazzi generic macros for geodetic calculations.
Paparazzi double-precision floating point math for geodetic calculations.
Paparazzi floating point math for geodetic calculations.
Paparazzi atmospheric pressure conversion utilities.
static const ShellCommand commands[]
Definition shell_arch.c:77
static const float dir[]