dRonin  adbada4
dRonin firmware
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pios_px4flow.c
Go to the documentation of this file.
1 
14 /*
15  * This program is free software; you can redistribute it and/or modify
16  * it under the terms of the GNU General Public License as published by
17  * the Free Software Foundation; either version 3 of the License, or
18  * (at your option) any later version.
19  *
20  * This program is distributed in the hope that it will be useful, but
21  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
22  * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23  * for more details.
24  *
25  * You should have received a copy of the GNU General Public License along
26  * with this program; if not, see <http://www.gnu.org/licenses/>
27  */
28 
29 
30 /* Project Includes */
31 #include "pios.h"
32 #include "coordinate_conversions.h"
33 #include "physical_constants.h"
34 
35 #if defined(PIOS_INCLUDE_PX4FLOW)
36 #include "pios_px4flow_priv.h"
37 
38 #include "pios_semaphore.h"
39 #include "pios_thread.h"
40 #include "pios_queue.h"
41 
42 /* Private constants */
43 #define PX4FLOW_TASK_PRIORITY PIOS_THREAD_PRIO_HIGH
44 #define PX4FLOW_TASK_STACK_BYTES 512
45 #define PX4FLOW_SAMPLE_PERIOD_MS 5
46 #define PIOS_PX4FLOW_MAX_DOWNSAMPLE 1
47 
48 /* Global Variables */
49 
50 /* Local Types */
51 enum pios_px4flow_dev_magic {
52  PIOS_PX4FLOW_DEV_MAGIC = 0x1dbef871, // md5 hash of the string "PIOS_PX4FLOW_DEV_MAGIC"
53 };
54 
55 struct px4flow_dev {
56  pios_i2c_t i2c_id;
57  const struct pios_px4flow_cfg *cfg;
58  struct pios_queue *optical_flow_queue;
59  struct pios_queue *rangefinder_queue;
60  struct pios_thread *task;
61  struct pios_semaphore *data_ready_sema;
62  enum pios_px4flow_dev_magic magic;
63  float Rsb[3][3];
64 };
65 
66 /* Local Variables */
67 static int32_t PIOS_PX4Flow_Config(const struct pios_px4flow_cfg * cfg);
68 static void PIOS_PX4Flow_Task(void *parameters);
69 
70 static struct px4flow_dev *dev;
71 
75 static struct px4flow_dev * PIOS_PX4Flow_alloc(void)
76 {
77  struct px4flow_dev *px4flow_dev;
78 
79  px4flow_dev = (struct px4flow_dev *)PIOS_malloc(sizeof(*px4flow_dev));
80  if (!px4flow_dev) return (NULL);
81 
82  px4flow_dev->magic = PIOS_PX4FLOW_DEV_MAGIC;
83 
84  px4flow_dev->optical_flow_queue = PIOS_Queue_Create(PIOS_PX4FLOW_MAX_DOWNSAMPLE, sizeof(struct pios_sensor_optical_flow_data));
85  px4flow_dev->rangefinder_queue = PIOS_Queue_Create(PIOS_PX4FLOW_MAX_DOWNSAMPLE, sizeof(struct pios_sensor_rangefinder_data));
86  if (px4flow_dev->optical_flow_queue == NULL || px4flow_dev->rangefinder_queue == NULL) {
87  PIOS_free(px4flow_dev);
88  return NULL;
89  }
90 
91  return px4flow_dev;
92 }
93 
98 static int32_t PIOS_PX4Flow_Validate(struct px4flow_dev *dev)
99 {
100  if (dev == NULL)
101  return -1;
102  if (dev->magic != PIOS_PX4FLOW_DEV_MAGIC)
103  return -2;
104  if (dev->i2c_id == 0)
105  return -3;
106  return 0;
107 }
108 
113 int32_t PIOS_PX4Flow_Init(const struct pios_px4flow_cfg *cfg, pios_i2c_t i2c_id)
114 {
115  dev = (struct px4flow_dev *) PIOS_PX4Flow_alloc();
116  if (dev == NULL)
117  return -1;
118 
119  dev->cfg = cfg;
120  dev->i2c_id = i2c_id;
122 
123  if (PIOS_PX4Flow_Config(cfg) != 0)
124  return -2;
125 
126  PIOS_SENSORS_Register(PIOS_SENSOR_OPTICAL_FLOW, dev->optical_flow_queue);
127  PIOS_SENSORS_Register(PIOS_SENSOR_RANGEFINDER, dev->rangefinder_queue);
128 
129  dev->task = PIOS_Thread_Create(PIOS_PX4Flow_Task, "pios_px4flow", PX4FLOW_TASK_STACK_BYTES, NULL, PX4FLOW_TASK_PRIORITY);
130 
131  PIOS_Assert(dev->task != NULL);
132 
133  return 0;
134 }
135 
140 int32_t PIOS_PX4Flow_SetRotation(const struct Rotation rotation)
141 {
142  if (PIOS_PX4Flow_Validate(dev) != 0)
143  return -1;
144 
145  float rpy_R[3] = {rotation.roll_D100/100.0f * DEG2RAD, rotation.pitch_D100/100.0f * DEG2RAD, rotation.yaw_D100/100.0f * DEG2RAD};
146 
147  Euler2R(rpy_R, dev->Rsb);
148 
149 
150  return 0;
151 }
152 
159 static int32_t PIOS_PX4Flow_Config(const struct pios_px4flow_cfg * cfg)
160 {
161  // This function intentionally left blank.
162 
163  return 0;
164 }
165 
170 static int32_t PIOS_PX4Flow_ReadData()
171 {
172  if (PIOS_PX4Flow_Validate(dev) != 0) {
173  return -1;
174  }
175 
176  /* don't use PIOS_PX4Flow_Read and PIOS_PX4Flow_Write here because the task could be
177  * switched out of context in between which would give the sensor less time to capture
178  * the next sample.
179  */
180  uint8_t addr_read[] = {
182  };
183 
184  /* Optical flow structs */
185  struct I2C_Frame
186  {
187  uint16_t frame_count; // counts created I2C frames [#frames]
188  int16_t pixel_flow_x_sum_px10; // latest x flow measurement in pixels*10 [pixels]
189  int16_t pixel_flow_y_sum_px10; // latest y flow measurement in pixels*10 [pixels]
190  int16_t flow_comp_x_m1000; // x velocity*1000 [meters/sec]
191  int16_t flow_comp_y_m1000; // y velocity*1000 [meters/sec]
192  uint16_t qual; // Optical flow solution quality [0: bad, 255: maximum quality]
193  int16_t gyro_x_R; // latest gyro x rate [rad/sec]
194  int16_t gyro_y_R; // latest gyro y rate [rad/sec]
195  int16_t gyro_z_R; // latest gyro z rate [rad/sec]
196  uint8_t gyro_range; // gyro range [0 .. 7] equals [50 deg/sec .. 2000 deg/sec]
197  uint8_t sonar_timestamp; // time since last sonar update [milliseconds]
198  int16_t ground_distance_m1000; // Ground distance in meters*1000 [meters]. Positive value: distance known. Negative value: Unknown distance
199  } __attribute__((packed)) i2c_frame;
200 
201  const struct pios_i2c_txn txn_list[] = {
202  {
203  .info = __func__,
205  .rw = PIOS_I2C_TXN_WRITE,
206  .len = 1,
207  .buf = addr_read,
208  },
209  {
210  .info = __func__,
212  .rw = PIOS_I2C_TXN_READ,
213  .len = sizeof(i2c_frame),
214  .buf = (uint8_t *)&i2c_frame,
215  }
216  };
217 
218  // Perform transfer, and return error if TX fails
219  if (PIOS_I2C_Transfer(dev->i2c_id, txn_list, NELEMENTS(txn_list)) != 0)
220  return -1;
221 
222 
223  // PX4Flow docs state that `quality` is an int16, but that it only takes values
224  // from 0..255. This provides a useful check for corruption.
225  if (i2c_frame.qual > 255) {
226  return -1;
227  }
228 
229  struct pios_sensor_optical_flow_data optical_flow_data = { 0 };
230  struct pios_sensor_rangefinder_data rangefinder_data = { 0 };
231 
232  // Only update rangefinder queue if data is fresh XXX this conditional looks
233  // wrong
234  if (i2c_frame.sonar_timestamp > 0) {
235  rangefinder_data.range = i2c_frame.ground_distance_m1000 / 1000.0f;
236 
237  if (rangefinder_data.range >= 0) {
238  rangefinder_data.range_status = true;
239  }
240 
241  PIOS_Queue_Send(dev->rangefinder_queue, &rangefinder_data, 0);
242  }
243 
244  /* Rotate the flow from the sensor frame into the body frame. It's not
245  * good to set the z-axis velocity to 0, but the optical flow doesn't return
246  * any data along that direction, and moreover if the sensor is always
247  * mounted vertically then the sensor board mounting yaw angle will not
248  * affect the vertical results.
249  */
250  float flow_sensor_frame[3] = {i2c_frame.flow_comp_x_m1000 / 1000.0f, i2c_frame.flow_comp_y_m1000 / 1000.0f, 0 / 1000.0f};
251  float flow_rotated[3];
252  rot_mult(dev->Rsb, flow_sensor_frame, flow_rotated, true);
253  optical_flow_data.x_dot = flow_rotated[0];
254  optical_flow_data.y_dot = flow_rotated[1];
255  optical_flow_data.z_dot = flow_rotated[2];
256 
257  optical_flow_data.quality = i2c_frame.qual;
258 
259  PIOS_Queue_Send(dev->optical_flow_queue, &optical_flow_data, 0);
260 
261  return 0;
262 }
263 
264 
268 static void PIOS_PX4Flow_Task(void *parameters)
269 {
270  while (PIOS_PX4Flow_Validate(dev) != 0) {
271  PIOS_Thread_Sleep(100);
272  }
273 
274  uint32_t now = PIOS_Thread_Systime();
275 
276  while (1) {
277  PIOS_Thread_Sleep_Until(&now, PX4FLOW_SAMPLE_PERIOD_MS);
278 
279  PIOS_PX4Flow_ReadData();
280  }
281 }
282 
283 #endif /* PIOS_INCLUDE_PX4FLOW */
284 
void rot_mult(float R[3][3], const float vec[3], float vec_out[3], bool transpose)
Rotate a vector by a rotation matrix.
uint32_t PIOS_Thread_Systime(void)
Definition: pios_thread.c:212
#define PIOS_PX4FLOW_FRAMECOUNTER_LSB
struct pios_queue * PIOS_Queue_Create(size_t queue_length, size_t item_size)
Definition: pios_queue.c:47
Main PiOS header to include all the compiled in PiOS options.
#define NELEMENTS(x)
Definition: pios.h:192
Pios sensor structure for generic mag data.
Definition: pios_sensors.h:61
void * PIOS_malloc(size_t size)
Definition: pios_heap.c:125
bool PIOS_Queue_Send(struct pios_queue *queuep, const void *itemp, uint32_t timeout_ms)
Definition: pios_queue.c:141
static struct flyingpicmd_cfg_fa cfg
Definition: main.c:49
int16_t pitch_D100
Pios sensor structure for generic rangefinder data.
Definition: pios_sensors.h:70
int16_t roll_D100
int32_t PIOS_PX4Flow_SetRotation(const struct Rotation rotation)
struct pios_i2c_adapter * pios_i2c_t
Definition: pios_i2c.h:48
struct pios_thread * PIOS_Thread_Create(void(*fp)(void *), const char *namep, size_t stack_bytes, void *argp, enum pios_thread_prio_e prio)
Definition: pios_thread.c:89
int32_t PIOS_SENSORS_Register(enum pios_sensor_type type, struct pios_queue *queue)
Register a queue-based sensor with the PIOS_SENSORS interface.
Definition: pios_sensors.c:82
static TaskInfoRunningElem task
int16_t yaw_D100
int32_t PIOS_I2C_Transfer(pios_i2c_t i2c_id, const struct pios_i2c_txn txn_list[], uint32_t num_txns)
struct Rotation rotation
void PIOS_Thread_Sleep_Until(uint32_t *previous_ms, uint32_t increment_ms)
Definition: pios_thread.c:255
uint32_t magic
void Euler2R(float rpy[3], float Rbe[3][3])
void PIOS_free(void *buf)
Definition: pios_heap.c:174
void PIOS_Thread_Sleep(uint32_t time_ms)
Definition: pios_thread.c:229
Header for Coordinate conversions library in coordinate_conversions.c.
int32_t PIOS_PX4Flow_Init(const struct pios_px4flow_cfg *cfg, pios_i2c_t i2c_id)
#define PIOS_PX4FLOW_I2C_7_BIT_ADDR
const char * info
Definition: pios_i2c.h:41
#define PIOS_Assert(test)
Definition: pios_debug.h:52
typedef __attribute__
Definition: serial_4way.h:43
static float Rsb[3][3]
Definition: sensors.c:122