diff --git a/conf/airframes/AGGIEAIR/aggieair_control_panel.xml b/conf/airframes/AGGIEAIR/aggieair_control_panel.xml index ca18ad87ac0..b49348da1fa 100644 --- a/conf/airframes/AGGIEAIR/aggieair_control_panel.xml +++ b/conf/airframes/AGGIEAIR/aggieair_control_panel.xml @@ -82,7 +82,9 @@ - + + + @@ -135,6 +137,23 @@ + + + + + + + + + + + + + + + + + diff --git a/conf/airframes/AGGIEAIR/aggieair_rp3_lia.xml b/conf/airframes/AGGIEAIR/aggieair_rp3_lia.xml index 30cdee4bd01..5316b543f58 100644 --- a/conf/airframes/AGGIEAIR/aggieair_rp3_lia.xml +++ b/conf/airframes/AGGIEAIR/aggieair_rp3_lia.xml @@ -57,6 +57,7 @@ RP3 Lisa MX + diff --git a/conf/flight_plans/AGGIEAIR/BasicTuning_Launcher.xml b/conf/flight_plans/AGGIEAIR/BasicTuning_Launcher.xml index c58deddf059..9d413887902 100644 --- a/conf/flight_plans/AGGIEAIR/BasicTuning_Launcher.xml +++ b/conf/flight_plans/AGGIEAIR/BasicTuning_Launcher.xml @@ -22,6 +22,7 @@ + diff --git a/conf/gcs/AGGIEAIR/vertical.xml b/conf/gcs/AGGIEAIR/vertical.xml new file mode 100755 index 00000000000..f4d4ed6e445 --- /dev/null +++ b/conf/gcs/AGGIEAIR/vertical.xml @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/modules/copilot.xml b/conf/modules/copilot.xml new file mode 100644 index 00000000000..4fe64de2c5a --- /dev/null +++ b/conf/modules/copilot.xml @@ -0,0 +1,41 @@ + + + + + + Mission Computer module, interfacing the mission computer (also known as Copilot), + based losely on + ISaAC: The Intelligent Safety and Airworthiness Co-Pilot module + Based on paper "A Payload Verification and Management Framework + for Small UAV-based Personal Remote Sensing Systems" by Cal Coopmans + and Chris Coffin. Link: http://ieeexplore.ieee.org/abstract/document/6309316/ + + More info can be found on http://wiki.paparazziuav.org/wiki/Mission_computer + + Copilot is intended mainly for mapping applications. + + This module processes messages from Copilot, and either forwards them to the GCS + (such as CAMERA_SNAPSHOT or CAMERA_PAYLOAD messages), or responds to them as necessary + (such as MOVE_WP). + + The module assumes the source of the messages is trusted (i.e. not authentication besides + AC_ID check is performed). + + + + + extra_dl +
+ +
+ + + + + + + + + +
+ diff --git a/conf/telemetry/AGGIEAIR/aggieair_fixedwing.xml b/conf/telemetry/AGGIEAIR/aggieair_fixedwing.xml index 22c0479fe27..e5131a222b1 100644 --- a/conf/telemetry/AGGIEAIR/aggieair_fixedwing.xml +++ b/conf/telemetry/AGGIEAIR/aggieair_fixedwing.xml @@ -5,7 +5,7 @@ - + @@ -21,6 +21,7 @@ + @@ -106,7 +107,10 @@ - + + + + diff --git a/sw/airborne/modules/cartography/cartography.c b/sw/airborne/modules/cartography/cartography.c index 9ec8555d074..401d5c1567f 100644 --- a/sw/airborne/modules/cartography/cartography.c +++ b/sw/airborne/modules/cartography/cartography.c @@ -151,7 +151,16 @@ void init_carto(void) void periodic_downlink_carto(void) { - DOWNLINK_SEND_CAMERA_SNAPSHOT(DefaultChannel, DefaultDevice, &camera_snapshot_image_number); + static uint16_t dummy_id = 0; + static uint8_t dummy_state = 0; + static uint8_t snapshot_valid = 1; + static float dummy_temp = NAN; + DOWNLINK_SEND_CAMERA_SNAPSHOT(DefaultChannel, DefaultDevice, + &dummy_d, + &dummy_state, + &camera_snapshot_image_number, + &snapshot_valid, + &dummy_temp); } void start_carto(void) diff --git a/sw/airborne/modules/datalink/extra_pprz_dl.h b/sw/airborne/modules/datalink/extra_pprz_dl.h index 76b085fd970..8e4fea2bece 100644 --- a/sw/airborne/modules/datalink/extra_pprz_dl.h +++ b/sw/airborne/modules/datalink/extra_pprz_dl.h @@ -41,6 +41,8 @@ /* PPRZ transport structure */ extern struct pprz_transport extra_pprz_tp; +extern uint8_t extra_dl_buffer[MSG_SIZE] __attribute__((aligned)); + /** Datalink Event */ void extra_pprz_dl_event(void); diff --git a/sw/airborne/modules/mission/copilot.c b/sw/airborne/modules/mission/copilot.c new file mode 100644 index 00000000000..d3b90b5eb20 --- /dev/null +++ b/sw/airborne/modules/mission/copilot.c @@ -0,0 +1,247 @@ +/* + * Copyright (C) 2016 2017 Michal Podhradsky + * + * This file is part of paparazzi. + * + * paparazzi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * paparazzi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +/** + * @file "modules/mission/copilot.c" + * + * Mission Computer module, interfacing the mission computer (also known as Copilot), + * based losely on + * ISaAC: The Intelligent Safety and Airworthiness Co-Pilot module + * Based on paper "A Payload Verification and Management Framework + * for Small UAV-based Personal Remote Sensing Systems" by Cal Coopmans + * and Chris Coffin. Link: http://ieeexplore.ieee.org/abstract/document/6309316/ + * + * More info can be found on http://wiki.paparazziuav.org/wiki/Mission_computer + * + * Copilot is intended mainly for mapping applications. + * + * This module processes messages from Copilot, and either forwards them to the GCS + * (such as CAMERA_SNAPSHOT or CAMERA_PAYLOAD messages), or responds to them as necessary + * (such as MOVE_WP). + * + * The module assumes the source of the messages is trusted (i.e. not authentication besides + * AC_ID check is performed). + */ + +#include "modules/mission/copilot.h" +#include "subsystems/datalink/telemetry.h" +#include + +#include "pprz_mutex.h" + +// needed for WP_MOVED confirmation +#include "firmwares/fixedwing/nav.h" +#include "subsystems/navigation/common_nav.h" +#include "math/pprz_geodetic_float.h" + +bool send_cam_snapshot; +bool send_cam_payload; +bool send_copilot_status; + +struct CameraPayload cam_payload; +struct CameraSnapshot cam_snapshot; +struct CopilotStatus copilot_status; + +PPRZ_MUTEX(copilot_cam_snapshot_mtx); +PPRZ_MUTEX(copilot_cam_payload_mtx); +PPRZ_MUTEX(copilot_status_mtx); + +/** Init function */ +void copilot_init(void) +{ + send_cam_snapshot = false; + send_cam_payload = false; + send_copilot_status = false; + + memset(&cam_payload, 0, sizeof(cam_payload)); + memset(&cam_snapshot, 0, sizeof(cam_snapshot)); + memset(&copilot_status, 0, sizeof(copilot_status)); + + PPRZ_MUTEX_INIT(copilot_cam_snapshot_mtx); + PPRZ_MUTEX_INIT(copilot_cam_payload_mtx); + PPRZ_MUTEX_INIT(copilot_status_mtx); +} + +/** Periodic function */ +void copilot_periodic(void) +{ + PPRZ_MUTEX_LOCK(copilot_cam_snapshot_mtx); + if (send_cam_snapshot) + { + // send down to GCS + DOWNLINK_SEND_CAMERA_SNAPSHOT(DefaultChannel, DefaultDevice, + &cam_snapshot.cam_id, + &cam_snapshot.cam_state, + &cam_snapshot.snapshot_num, + &cam_snapshot.snapshot_valid, + &cam_snapshot.lens_temp, + &cam_snapshot.array_temp); + + send_cam_snapshot = false; + } + PPRZ_MUTEX_UNLOCK(copilot_cam_snapshot_mtx); + + + PPRZ_MUTEX_LOCK(copilot_cam_payload_mtx); + if (send_cam_payload) + { + // NOTE: to send the message over the EXTRA_DL port + // use "DOWNLINK_SEND_CAMERA_PAYLOAD(extra_pprz_tp, EXTRA_DOWNLINK_DEVICE," + + // send down to GCS + DOWNLINK_SEND_CAMERA_PAYLOAD(DefaultChannel, DefaultDevice, + &cam_payload.timestamp, + &cam_payload.used_mem, + &cam_payload.used_disk, + &cam_payload.door_status, + &cam_payload.error_code); + + send_cam_payload = false; + } + PPRZ_MUTEX_UNLOCK(copilot_cam_payload_mtx); + + PPRZ_MUTEX_LOCK(copilot_status_mtx); + // send down to GCS + if (send_copilot_status) + { + DOWNLINK_SEND_COPILOT_STATUS(DefaultChannel, DefaultDevice, + &copilot_status.timestamp, + &copilot_status.used_mem, + &copilot_status.used_disk, + &copilot_status.status, + &copilot_status.error_code); + + send_copilot_status = false; + } + PPRZ_MUTEX_UNLOCK(copilot_status_mtx); + +} + +/** + * + * copy CAMERA_SNAPSHOT message and mark it to be sent + * + * In case of multiple cameras, it is up to the payload computer to send + * CAMERA_SNAPSHOT messages for each camera at proper interval, so the values + * don't get overwritten. + * + */ +void copilot_parse_cam_snapshot_dl(uint8_t *buf) +{ + PPRZ_MUTEX_LOCK(copilot_cam_snapshot_mtx); + + // copy CAMERA_SNAPSHOT message and mark it to be sent + cam_snapshot.cam_id = DL_CAMERA_SNAPSHOT_DL_camera_id(buf); + cam_snapshot.cam_state = DL_CAMERA_SNAPSHOT_DL_camera_state(buf); + cam_snapshot.snapshot_num = DL_CAMERA_SNAPSHOT_DL_snapshot_image_number(buf); + cam_snapshot.snapshot_valid = DL_CAMERA_SNAPSHOT_DL_snapshot_valid(buf); + cam_snapshot.lens_temp = DL_CAMERA_SNAPSHOT_DL_lens_temp(buf); + cam_snapshot.array_temp = DL_CAMERA_SNAPSHOT_DL_array_temp(buf); + + send_cam_snapshot = true; + + PPRZ_MUTEX_UNLOCK(copilot_cam_snapshot_mtx); +} + +/** + * copy CAMERA_PAYLOAD message and mark it to be sent + */ +void copilot_parse_cam_payload_dl(uint8_t *buf) +{ + PPRZ_MUTEX_LOCK(copilot_cam_payload_mtx); + + cam_payload.timestamp = DL_CAMERA_PAYLOAD_DL_timestamp(buf); + cam_payload.used_mem = DL_CAMERA_PAYLOAD_DL_used_memory(buf); + cam_payload.used_disk = DL_CAMERA_PAYLOAD_DL_used_disk(buf); + cam_payload.door_status = DL_CAMERA_PAYLOAD_DL_door_status(buf); + cam_payload.error_code = DL_CAMERA_PAYLOAD_DL_error_code(buf); + + send_cam_payload = true; + + PPRZ_MUTEX_UNLOCK(copilot_cam_payload_mtx); +} + +/** + * copy COPILOT_STATUS message and mark it to be sent + */ +void copilot_parse_copilot_status_dl(uint8_t *buf) +{ + PPRZ_MUTEX_LOCK(copilot_status_mtx); + + copilot_status.timestamp = DL_COPILOT_STATUS_DL_timestamp(buf); + copilot_status.used_mem = DL_COPILOT_STATUS_DL_used_memory(buf); + copilot_status.used_disk = DL_COPILOT_STATUS_DL_used_disk(buf); + copilot_status.status = DL_COPILOT_STATUS_DL_status(buf); + copilot_status.error_code = DL_COPILOT_STATUS_DL_error_code(buf); + + send_copilot_status = true; + + PPRZ_MUTEX_UNLOCK(copilot_status_mtx); +} + +/** + * If MOVE_WP from GCS + * - processed in firmware_parse_msg(dev, trans, buf); with regular buffer + * - reponse over telemetry (regular buffer) + * - here send WP_MOVED over extra_dl + * + * If MOVE_WP from extra_dl + * - processed in firmware_parse_msg(dev, trans, buf); with extra buffer + * - response over extra_dl + * - send an update to GCS + * + * In both cases, the MOVE_WP message was already processed in firmware_parse + * here we are taking care only about propagating the change + * + */ +void copilot_parse_move_wp_dl(uint8_t *buf) +{ + if (DL_MOVE_WP_ac_id(buf) == AC_ID) { + uint8_t wp_id = DL_MOVE_WP_wp_id(buf); + + /* Computes from (lat, long) in the referenced UTM zone */ + struct LlaCoor_f lla; + lla.lat = RadOfDeg((float)(DL_MOVE_WP_lat(buf) / 1e7)); + lla.lon = RadOfDeg((float)(DL_MOVE_WP_lon(buf) / 1e7)); + lla.alt = ((float)(DL_MOVE_WP_alt(buf)))/1000.; + struct UtmCoor_f utm; + utm.zone = nav_utm_zone0; + utm_of_lla_f(&utm, &lla); + + // Waypoint range is limited. Computes the UTM pos back from the relative + // coordinates */ + utm.east = waypoints[wp_id].x + nav_utm_east0; + utm.north = waypoints[wp_id].y + nav_utm_north0; + + if (buf == extra_dl_buffer) { + // MOVE_WP came from extra_dl, respond over telemetry + DOWNLINK_SEND_WP_MOVED(DefaultChannel, DefaultDevice, + &wp_id, &utm.east, &utm.north, &utm.alt, &nav_utm_zone0); + } + + if (buf == dl_buffer) { + // MOVE_WP came over telemetry, respond over extra_dl + DOWNLINK_SEND_WP_MOVED(extra_pprz_tp, EXTRA_DOWNLINK_DEVICE, + &wp_id, &utm.east, &utm.north, &utm.alt, &nav_utm_zone0); + } + + } +} diff --git a/sw/airborne/modules/mission/copilot.h b/sw/airborne/modules/mission/copilot.h new file mode 100644 index 00000000000..d13873aaa01 --- /dev/null +++ b/sw/airborne/modules/mission/copilot.h @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2016 2017 Michal Podhradsky + * + * This file is part of paparazzi. + * + * paparazzi is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * paparazzi is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with paparazzi; see the file COPYING. If not, write to + * the Free Software Foundation, 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + */ +/** + * @file "modules/mission/copilot.h" + * + * Mission Computer module, interfacing the mission computer (also known as Copilot), + * based losely on + * ISaAC: The Intelligent Safety and Airworthiness Co-Pilot module + * Based on paper "A Payload Verification and Management Framework + * for Small UAV-based Personal Remote Sensing Systems" by Cal Coopmans + * and Chris Coffin. Link: http://ieeexplore.ieee.org/abstract/document/6309316/ + * + * More info can be found on http://wiki.paparazziuav.org/wiki/Mission_computer + * + * Copilot is intended mainly for mapping applications. + * + * This module processes messages from Copilot, and either forwards them to the GCS + * (such as CAMERA_SNAPSHOT or CAMERA_PAYLOAD messages), or responds to them as necessary + * (such as MOVE_WP). + * + * The module assumes the source of the messages is trusted (i.e. not authentication besides + * AC_ID check is performed). + */ + +#ifndef COPILOT_H +#define COPILOT_H + +#include "subsystems/datalink/datalink.h" +#include "modules/datalink/extra_pprz_dl.h" + +struct CameraPayload { + float timestamp; + uint8_t used_mem; + uint8_t used_disk; + uint8_t door_status; + uint8_t error_code; +}; + +struct CameraSnapshot { + uint16_t cam_id; + uint8_t cam_state; + uint16_t snapshot_num; + uint8_t snapshot_valid; + float lens_temp; + float array_temp; +}; + +struct CopilotStatus { + float timestamp; + uint8_t used_mem; + uint8_t used_disk; + uint8_t status; + uint8_t error_code; +}; + +extern bool send_cam_snapshot; +extern bool send_cam_payload; +extern bool send_copilot_status; + +/** Init function */ +void copilot_init(void); + +/** Periodic function */ +void copilot_periodic(void); + +/** Message processing functions */ +void copilot_parse_cam_snapshot_dl(uint8_t *buf); +void copilot_parse_cam_payload_dl(uint8_t *buf); +void copilot_parse_copilot_status_dl(uint8_t *buf); +void copilot_parse_move_wp_dl(uint8_t *buf); + +#endif /* COPILOT_H */ + diff --git a/sw/airborne/subsystems/datalink/datalink.c b/sw/airborne/subsystems/datalink/datalink.c index 1d5819b3e0f..3efde33e040 100644 --- a/sw/airborne/subsystems/datalink/datalink.c +++ b/sw/airborne/subsystems/datalink/datalink.c @@ -146,7 +146,7 @@ void dl_parse_msg(struct link_device *dev, struct transport_tx *trans, uint8_t * firmware_parse_msg(dev, trans, buf); /* Parse modules datalink */ - modules_parse_datalink(msg_id); + modules_parse_datalink(msg_id, dev, trans, buf); } /* default empty WEAK implementation for firmwares without an extra firmware_parse_msg */ diff --git a/sw/ext/pprzlink b/sw/ext/pprzlink index d2d49893ca3..f875eabafdf 160000 --- a/sw/ext/pprzlink +++ b/sw/ext/pprzlink @@ -1 +1 @@ -Subproject commit d2d49893ca3038108a4e64fb5dec5ca8af527c7a +Subproject commit f875eabafdf15499a9e277865879503e76fb2846 diff --git a/sw/tools/generators/gen_modules.ml b/sw/tools/generators/gen_modules.ml index b9effb33984..3426b1a9789 100644 --- a/sw/tools/generators/gen_modules.ml +++ b/sw/tools/generators/gen_modules.ml @@ -304,7 +304,10 @@ let print_event_functions = fun modules -> let print_datalink_functions = fun modules -> lprintf out_h "\n#include \"pprzlink/messages.h\"\n"; lprintf out_h "#include \"generated/airframe.h\"\n"; - lprintf out_h "static inline void modules_parse_datalink(uint8_t msg_id __attribute__ ((unused))) {\n"; + lprintf out_h "static inline void modules_parse_datalink(uint8_t msg_id __attribute__ ((unused)), + struct link_device *dev __attribute__((unused)), + struct transport_tx *trans __attribute__((unused)), + uint8_t *buf __attribute__((unused))) {\n"; right (); let else_ = ref "" in List.iter (fun m ->