diff --git a/conf/abi.xml b/conf/abi.xml index f358de58f4..269d937287 100644 --- a/conf/abi.xml +++ b/conf/abi.xml @@ -124,6 +124,33 @@ + + + Standardized message type JEVOIS_MSG_[T1|N1|D1|T2|N2|D2|F2|T3|N3|D3|F3] + Text string describing the reported object + Number of elements in the coordinates array + List of coordinates corresponding to 1D, 2D or 3D messages + 1, 2 or 3D dimension + Quaternion that relates the object's frame to the camera's frame, if appropriate + Additional text information + + + + Object ID to track + + bitmask to select relative coordinates (0) or global coordinates (1) + bit 0: bearing + bit 1: height + bit 2: distance + + Direction of object to track + Height of object to track + Distance of object to track + + diff --git a/conf/modules/jevois.xml b/conf/modules/jevois.xml new file mode 100644 index 0000000000..0b5fc7548f --- /dev/null +++ b/conf/modules/jevois.xml @@ -0,0 +1,35 @@ + + + + + + Decoder for standardized messages from the JEVOIS smart camera (http://jevois.org) + + Data are extracted from a serial link and produce a JEVOIS_MSG ABI message + + + + + + + + + + + + +
+ +
+ + + + + + + + + + +
+ diff --git a/sw/airborne/modules/sensors/cameras/jevois.c b/sw/airborne/modules/sensors/cameras/jevois.c new file mode 100644 index 0000000000..16c9dc8b99 --- /dev/null +++ b/sw/airborne/modules/sensors/cameras/jevois.c @@ -0,0 +1,362 @@ +/* + * Copyright (C) 2017 Gautier Hattenberger + * + * 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, see + * . + */ +/** + * @file "modules/sensors/cameras/jevois.c" + * @author Gautier Hattenberger + * Decoder for standardized messages from the JEVOIS smart camera (http://jevois.org) + */ + +#include "modules/sensors/cameras/jevois.h" + +#include "std.h" +#include "mcu_periph/uart.h" +#include "subsystems/abi.h" +#include "math/pprz_algebra_float.h" +#include + +int jevois_mapping_setting; +bool jevois_stream_setting; + +// max string length +#define JEVOIS_MAX_LEN 32 +// max number of coordinates +#define JEVOIS_MAX_COORD 18 +// check delimiter +#define JEVOIS_CHECK_DELIM(_c) (_c == ' ' || _c == '\n' || _c == '\r' || _c == '\0') + +// generic JEVOIS message structure +struct jevois_msg_t { + uint8_t type; + char id[JEVOIS_MAX_LEN]; + uint8_t nb; + int16_t coord[JEVOIS_MAX_COORD]; + uint16_t dim[3]; + struct FloatQuat quat; + char extra[JEVOIS_MAX_LEN]; +}; + +// decoder state +enum jevois_state { + JV_SYNC = 0, + JV_TYPE, + JV_ID, + JV_SIZE, + JV_COORD, + JV_DIM, + JV_QUAT, + JV_EXTRA, + JV_SEND_MSG +}; + +// jevois struct +struct jevois_t { + enum jevois_state state; // decoder state + char buf[JEVOIS_MAX_LEN]; // temp buffer + uint8_t idx; // temp buffer index + uint8_t n; // temp coordinates/dimension index + struct jevois_msg_t msg; // last decoded message +}; + +struct jevois_t jevois; + +// initialization +void jevois_init(void) +{ + // dummy settings + jevois_mapping_setting = 0; + jevois_stream_setting = false; + + jevois.state = JV_SYNC; + jevois.idx = 0; + jevois.n = 0; + memset(jevois.buf, 0, JEVOIS_MAX_LEN); +} + +// send specific message if requested +static void jevois_send_message(void) +{ +#if JEVOIS_SEND_FOLLOW_TARGET + float cam_heading = (JEVOIS_HFOV / (2.f * JEVOIS_NORM)) * (float)(jevois.msg.coord[0]); + float cam_height = (JEVOIS_VFOV / (2.f * JEVOIS_NORM)) * (float)(jevois.msg.coord[1]); + // send a FOLLOW_TARGET message in camera frame + AbiSendMsgFOLLOW_TARGET(CAM_JEVOIS_ID, 0, 0, cam_heading, cam_height, 0.f); +#endif +} + +// raw message parsing function +static void jevois_parse(struct jevois_t *jv, char c) +{ + switch (jv->state) { + case JV_SYNC: + // wait for sync (newline character) + if (c == '\n') { + jv->state = JV_TYPE; + jv->idx = 0; + jv->n = 0; + } + break; + case JV_TYPE: + jv->buf[jv->idx++] = c; // fill buffer + // parse type + if (jv->idx > 2) { // msg type + white space + if (jv->buf[0] == 'T' && jv->buf[1] == '1') { + jv->state = JV_COORD; + jv->msg.type = JEVOIS_MSG_T1; + jv->msg.nb = 1; + } else if (jv->buf[0] == 'N' && jv->buf[1] == '1') { + jv->state = JV_ID; + jv->msg.type = JEVOIS_MSG_N1; + jv->msg.nb = 1; + } else if (jv->buf[0] == 'D' && jv->buf[1] == '1') { + jv->state = JV_ID; + jv->msg.type = JEVOIS_MSG_D1; + jv->msg.nb = 2; + } else if (jv->buf[0] == 'T' && jv->buf[1] == '2') { + jv->state = JV_COORD; + jv->msg.type = JEVOIS_MSG_T2; + jv->msg.nb = 2; + } else if (jv->buf[0] == 'N' && jv->buf[1] == '2') { + jv->state = JV_ID; + jv->msg.type = JEVOIS_MSG_N2; + jv->msg.nb = 2; + } else if (jv->buf[0] == 'D' && jv->buf[1] == '2') { + jv->state = JV_ID; + jv->msg.type = JEVOIS_MSG_D2; + jv->msg.nb = 8; + } else if (jv->buf[0] == 'F' && jv->buf[1] == '2') { + jv->state = JV_ID; + jv->msg.type = JEVOIS_MSG_F2; + jv->msg.nb = 0; + } else if (jv->buf[0] == 'T' && jv->buf[1] == '3') { + jv->state = JV_COORD; + jv->msg.type = JEVOIS_MSG_T3; + jv->msg.nb = 3; + } else if (jv->buf[0] == 'N' && jv->buf[1] == '3') { + jv->state = JV_ID; + jv->msg.type = JEVOIS_MSG_N3; + jv->msg.nb = 3; + } else if (jv->buf[0] == 'D' && jv->buf[1] == '3') { + jv->state = JV_ID; + jv->msg.type = JEVOIS_MSG_D3; + jv->msg.nb = 3; + } else if (jv->buf[0] == 'F' && jv->buf[1] == '3') { + jv->state = JV_ID; + jv->msg.type = JEVOIS_MSG_F3; + jv->msg.nb = 0; + } else { + jv->state = JV_SYNC; // error + } + jv->idx = 0; + } + break; + case JV_ID: + if (JEVOIS_CHECK_DELIM(c)) { + jv->buf[jv->idx] = '\0'; // end string + if (jv->msg.type == JEVOIS_MSG_F2 || + jv->msg.type == JEVOIS_MSG_F3) { + jv->state = JV_SIZE; // parse n before coordinates + } else { + jv->state = JV_COORD; // parse directly coordinates + } + break; + } + else { + jv->msg.id[jv->idx++] = c; + if (jv->idx > JEVOIS_MAX_LEN - 1) { + jv->state = JV_SYNC; // too long, return to sync + } + } + break; + case JV_SIZE: + if (JEVOIS_CHECK_DELIM(c)) { + jv->buf[jv->idx] = '\0'; // end string + jv->msg.nb = (uint8_t)atoi(jv->buf); // store size + jv->state = JV_COORD; + jv->idx = 0; + } + else { + jv->buf[jv->idx++] = c; // fill buffer + } + break; + case JV_COORD: + if (JEVOIS_CHECK_DELIM(c)) { + jv->buf[jv->idx] = '\0'; // end string + jv->msg.coord[jv->n++] = (int16_t)atoi(jv->buf); // store value + if (jv->n == jv->msg.nb) { + // got all coordinates, go to next state + jv->n = 0; // reset number of received elements + jv->idx = 0; // reset index + switch (jv->msg.type) { + case JEVOIS_MSG_T1: + case JEVOIS_MSG_T2: + case JEVOIS_MSG_T3: + jv->state = JV_SEND_MSG; + break; + case JEVOIS_MSG_N1: + case JEVOIS_MSG_N2: + case JEVOIS_MSG_N3: + case JEVOIS_MSG_D3: + jv->state = JV_DIM; + break; + case JEVOIS_MSG_D1: + case JEVOIS_MSG_D2: + case JEVOIS_MSG_F2: + case JEVOIS_MSG_F3: + jv->state = JV_EXTRA; + break; + default: + jv->state = JV_SYNC; // error + break; + } + } + jv->idx = 0; // reset index + } + else { + jv->buf[jv->idx++] = c; // fill buffer + } + break; + case JV_DIM: + if (JEVOIS_CHECK_DELIM(c)) { + jv->buf[jv->idx] = '\0'; // end string + jv->msg.dim[jv->n++] = (uint16_t)atoi(jv->buf); // store dimension + if (jv->n == jv->msg.nb) { + // got all dimensions, go to next state + jv->n = 0; // reset number of received elements + jv->idx = 0; // reset index + if (jv->msg.type == JEVOIS_MSG_D3) { + jv->state = JV_QUAT; + } else { + jv->state = JV_SEND_MSG; + } + break; + } + jv->idx = 0; // reset index + } + else { + jv->buf[jv->idx++] = c; // fill buffer + } + break; + case JV_QUAT: + if (JEVOIS_CHECK_DELIM(c)) { + jv->buf[jv->idx] = '\0'; + float q = 0.f;//(float) atof(jv->buf); + switch (jv->n) { + case 0: + jv->msg.quat.qi = q; // TODO check quaternion order + break; + case 1: + jv->msg.quat.qx = q; + break; + case 2: + jv->msg.quat.qy = q; + break; + case 3: + jv->msg.quat.qz = q; + break; + case 4: + jv->state = JV_EXTRA; + break; + default: + jv->state = JV_SYNC; // error + break; + } + jv->n++; + jv->idx = 0; // reset index + } + else { + jv->buf[jv->idx++] = c; // fill buffer + } + break; + case JV_EXTRA: + if (JEVOIS_CHECK_DELIM(c)) { + jv->buf[jv->idx] = '\0'; // end string + jv->state = JV_SEND_MSG; + } + else { + jv->msg.id[jv->idx++] = c; // store extra string + if (jv->idx > JEVOIS_MAX_LEN - 1) { + jv->state = JV_SYNC; // too long, return to sync + } + } + break; + case JV_SEND_MSG: + // send ABI message + AbiSendMsgJEVOIS_MSG(CAM_JEVOIS_ID, + jv->msg.type, + jv->msg.id, + jv->msg.nb, + jv->msg.coord, + jv->msg.dim, + jv->msg.quat, + jv->msg.extra); + // also send specific messages if needed + jevois_send_message(); + jv->state = JV_SYNC; + break; + default: + // error, back to SYNC + jv->state = JV_SYNC; + break; + } +} + + +// UART polling function +void jevois_event(void) +{ + // Look for data on serial link and send to parser + while (uart_char_available(&(JEVOIS_DEV))) { + uint8_t ch = uart_getch(&(JEVOIS_DEV)); + jevois_parse(&jevois, ch); + } +} + +// utility function to send a string +static void send_string(char *s) +{ + uint8_t i = 0; + while (s[i]) { + uart_put_byte(&(JEVOIS_DEV), 0, (uint8_t)(s[i])); + i++; + } +} + +void jevois_stream(bool activate) +{ + jevois_stream_setting = activate; + if (activate) { + send_string("streamon\r\n"); + } else { + send_string("streamoff\r\n"); + } +} + +void jevois_setmapping(int number) +{ + jevois_mapping_setting = number; + jevois_stream(false); + send_string("setmapping "); + char s[4]; + itoa(number, s, 10); + send_string(s); + send_string("\r\n"); + jevois_stream(true); +} + diff --git a/sw/airborne/modules/sensors/cameras/jevois.h b/sw/airborne/modules/sensors/cameras/jevois.h new file mode 100644 index 0000000000..18afe2acdb --- /dev/null +++ b/sw/airborne/modules/sensors/cameras/jevois.h @@ -0,0 +1,82 @@ +/* + * Copyright (C) 2017 Gautier Hattenberger + * + * 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, see + * . + */ +/** + * @file "modules/sensors/cameras/jevois.h" + * @author Gautier Hattenberger + * Decoder for standardized messages from the JEVOIS smart camera (http://jevois.org) + */ + +#ifndef JEVOIS_H +#define JEVOIS_H + +#include "std.h" + +/** JEVOIS messages types */ +#define JEVOIS_MSG_T1 10 +#define JEVOIS_MSG_N1 11 +#define JEVOIS_MSG_D1 12 +#define JEVOIS_MSG_T2 20 +#define JEVOIS_MSG_N2 21 +#define JEVOIS_MSG_D2 22 +#define JEVOIS_MSG_F2 23 +#define JEVOIS_MSG_T3 30 +#define JEVOIS_MSG_N3 31 +#define JEVOIS_MSG_D3 32 +#define JEVOIS_MSG_F3 33 + +/** Normalized data from JEVOIS are between -1000 and 1000 */ +#define JEVOIS_NORM 1000 + +/** Camera horizontal FOV + * From datasheet it should be 65deg, + * but it seems that better results are acheived with 45 + */ +#ifndef JEVOIS_HFOV +#define JEVOIS_HFOV RadOfDeg(45) +#endif + +/** Camera vertical FOV + * Camera has a 4/3 ratio + */ +#ifndef JEVOIS_VFOV +#define JEVOIS_VFOV (3*JEVOIS_HFOV/4) +#endif + +extern void jevois_init(void); +extern void jevois_event(void); + +/** Start and stop streaming + * @param[in] activate enable or disable streaming + */ +extern void jevois_stream(bool activate); + +// dummy variable to start/stop stream from setting +extern bool jevois_stream_setting; + +/** Set video mapping + * @param[in] number video mapping number + */ +extern void jevois_setmapping(int number); + +// dummy variable to change mapping from setting +extern int jevois_mapping_setting; + +#endif + diff --git a/sw/airborne/subsystems/abi_sender_ids.h b/sw/airborne/subsystems/abi_sender_ids.h index 0dc94f1b93..c578b67750 100644 --- a/sw/airborne/subsystems/abi_sender_ids.h +++ b/sw/airborne/subsystems/abi_sender_ids.h @@ -362,4 +362,13 @@ #define RANGE_FORCEFIELD_ID 1 #endif +/* + * ID's for camera type sensors + */ + +#ifndef CAM_JEVOIS_ID +#define CAM_JEVOIS_ID 1 +#endif + + #endif /* ABI_SENDER_IDS_H */