Paparazzi UAS v7.1_unstable
Paparazzi is a free software Unmanned Aircraft System.
Loading...
Searching...
No Matches
actuators_uavcan.c
Go to the documentation of this file.
1/*
2 * Copyright (C) 2021 Freek van Tienen <freek.v.tienen@gmail.com>
3 *
4 * This file is part of paparazzi.
5 *
6 * paparazzi is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * paparazzi is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with paparazzi; see the file COPYING. If not, write to
18 * the Free Software Foundation, 59 Temple Place - Suite 330,
19 * Boston, MA 02111-1307, USA.
20 */
27#include "actuators_uavcan.h"
29#include "math/pprz_random.h"
30#include "modules/core/abi.h"
32
33
34#include "uavcan.equipment.esc.Status.h"
35#include "uavcan.equipment.esc.RawCommand.h"
36#include "uavcan.equipment.actuator.Status.h"
37#include "uavcan.equipment.actuator.ArrayCommand.h"
38#include "uavcan.equipment.device.Temperature.h"
39
40/* By default enable the usage of the current sensing in the ESC telemetry */
41#ifndef UAVCAN_ACTUATORS_USE_CURRENT
42#define UAVCAN_ACTUATORS_USE_CURRENT TRUE
43#endif
44
45/* uavcan ESC status telemetry structure */
58
59/* The transmitted actuator values */
60#ifdef SERVOS_UAVCAN1_NB
62
64{
66}
67#endif
68#ifdef SERVOS_UAVCAN2_NB
70
72{
74}
75#endif
76#ifdef SERVOS_UAVCAN1CMD_NB
78
80{
82}
83#endif
84#ifdef SERVOS_UAVCAN2CMD_NB
86
88{
90}
91#endif
92
93/* Set the actual telemetry length (ID's from actuators can't collide with the command version) */
94#if SERVOS_UAVCAN1CMD_NB > SERVOS_UAVCAN1_NB
95#define UAVCAN1_TELEM_NB SERVOS_UAVCAN1CMD_NB
97#elif defined(SERVOS_UAVCAN1_NB)
98#define UAVCAN1_TELEM_NB SERVOS_UAVCAN1_NB
100#endif
101
102#if SERVOS_UAVCAN2CMD_NB > SERVOS_UAVCAN2_NB
103#define UAVCAN2_TELEM_NB SERVOS_UAVCAN2CMD_NB
105#elif defined(SERVOS_UAVCAN2_NB)
106#define UAVCAN2_TELEM_NB SERVOS_UAVCAN2_NB
108#endif
109
110/* UNUSED value for CMD */
111#define UAVCAN_CMD_UNUSED (MIN_PPRZ-1)
112
113/* private variables */
118
119#if PERIODIC_TELEMETRY
121
122static uint8_t old_idx = 0;
123static uint8_t esc_idx = 0;
125#ifdef UAVCAN_ACTUATORS_TELEM_IDX
126 // Only report the ESCs listed in UAVCAN_ACTUATORS_TELEM_IDX (index counted over UAVCAN1, then UAVCAN2)
128 static uint8_t idx_cur = 0;
129
130 // Randomness added for multiple transport devices
131 if (rand_uniform() > 0.02f) {
132 idx_cur++;
133 }
134 if (idx_cur >= (sizeof(telem_idx) / sizeof(telem_idx[0]))) {
135 idx_cur = 0;
136 }
137
139 uint8_t offset = 0;
140 old_idx = idx;
141 esc_idx = idx;
142
143 // Skip the ESC if no telemetry was received from it (same as the default mode)
144#ifdef UAVCAN1_TELEM_NB
145 if (idx < UAVCAN1_TELEM_NB) {
147 }
149#endif
150#ifdef UAVCAN2_TELEM_NB
151 if (idx < offset + UAVCAN2_TELEM_NB) {
152 return uavcan2_telem[idx - offset].set ? &uavcan2_telem[idx - offset] : NULL;
153 }
154#endif
155 esc_idx = 0;
156 return NULL;
157
158#else
159 // Randomness added for multiple transport devices
160 uint8_t add_idx = 0;
161 if (rand_uniform() > 0.02) {
162 add_idx = 1;
163 }
164
165 // Find the next set telemetry
166 uint8_t offset = 0;
167#ifdef UAVCAN1_TELEM_NB
168 for(uint8_t i = esc_idx - offset; i < UAVCAN1_TELEM_NB; i++) {
169 if(uavcan1_telem[i].set) {
170 old_idx = i + offset;
171 esc_idx = i + offset + add_idx;
172 return &uavcan1_telem[i];
173 } else {
174 esc_idx = i + offset + 1;
175 }
176 }
178#endif
179#ifdef UAVCAN2_TELEM_NB
180 for(uint8_t i = esc_idx - offset; i < UAVCAN2_TELEM_NB; i++) {
181 if(uavcan2_telem[i].set) {
182 old_idx = i + offset;
183 esc_idx = i + offset + add_idx;
184 return &uavcan2_telem[i];
185 } else {
186 esc_idx = i + offset + 1;
187 }
188 }
190#endif
191
192 // Going round or no telemetry found
193 esc_idx = 0;
194 return NULL;
195#endif
196}
197
198static void actuators_uavcan_send_esc(struct transport_tx *trans, struct link_device *dev)
199{
200 // Find the correct telemetry (Try twice if going round)
202 if(telem == NULL) {
204 }
205
206 // Safety check (no telemetry received 2 times)
207 if (telem == NULL) {
208 return;
209 }
210
211 float power = telem->current * telem->voltage;
212 float rpm = telem->rpm;
213 float energy = telem->energy;
214 pprz_msg_send_ESC(trans, dev, AC_ID, &telem->current, &electrical.vsupply, &power,
215 &rpm, &telem->voltage, &energy, &telem->temperature, &telem->temperature_dev, &telem->node_id, &old_idx);
216}
217#endif
218
221
222#ifdef UAVCAN1_TELEM_NB
223 if (iface == &uavcan1 && idx < UAVCAN1_TELEM_NB) {
225 }
226#endif
227#ifdef UAVCAN2_TELEM_NB
228 if (iface == &uavcan2 && idx < UAVCAN2_TELEM_NB) {
230 }
231#endif
232
233 return telem;
234}
235
237 uint8_t actuator_idx = 255;
238
239#ifdef UAVCAN1_TELEM_NB
240 if(iface == &uavcan1) {
241#ifdef SERVOS_UAVCAN1_NB
242 // First try as RAW COMMAND
244#endif
245#ifdef SERVOS_UAVCAN1CMD_NB
246 // Then try as ACTUATOR COMMAND
249 }
250#endif
251 }
252#endif
253#ifdef UAVCAN2_TELEM_NB
254 if(iface == &uavcan2) {
255#ifdef SERVOS_UAVCAN2_NB
256 // First try as RAW COMMAND
258#endif
259#ifdef SERVOS_UAVCAN2CMD_NB
260 // Then try as ACTUATOR COMMAND
263 }
264#endif
265 }
266#endif
267
268 return actuator_idx;
269}
270
275{
276 // Decode the message
279 return; // Decoding error
280 }
281
282 // Get the correct telemetry
283 struct actuators_uavcan_telem_t *telem = get_actuator_telem(iface, msg.esc_index);
284 if(telem == NULL) {
285 return;
286 }
287
288 // Set the telemetry (FIXME: copy over fully)
289 telem->set = true;
290 telem->node_id = transfer->source_node_id;
291 telem->timestamp = get_sys_time_float();
292 telem->energy = msg.error_count;
293 telem->voltage = msg.voltage;
294 telem->current = msg.current;
295 telem->temperature = msg.temperature;
296 telem->rpm = msg.rpm;
297
298 /* Specification says Kelvin, but some are transmitting in Celsius */
299 if (telem->temperature > 230.f) {
300 telem->temperature -= 273.15;
301 }
302
303 // Feedback ABI RPM messages
304 struct act_feedback_t feedback = {0};
305 feedback.idx = get_actuator_idx(iface, msg.esc_index);
306 feedback.rpm = telem->rpm;
307 feedback.set.rpm = true;
308
309 // Send ABI message
311
312#if UAVCAN_ACTUATORS_USE_CURRENT
313 // Update total current based on ESC telemetry
315#ifdef UAVCAN1_TELEM_NB
316 for (uint8_t i = 0; i < UAVCAN1_TELEM_NB; ++i) {
317 electrical.current += uavcan1_telem[i].current;
318 }
319#endif
320#ifdef UAVCAN2_TELEM_NB
321 for (uint8_t i = 0; i < UAVCAN2_TELEM_NB; ++i) {
322 electrical.current += uavcan2_telem[i].current;
323 }
324#endif
325#endif
326}
327
332{
333 // Decode the message
336 return; // Decoding error
337 }
338
339 // Get the correct telemetry
340 struct actuators_uavcan_telem_t *telem = get_actuator_telem(iface, msg.actuator_id);
341 if(telem == NULL) {
342 return;
343 }
344
345 //telem[msg.actuator_id].set = true;
346 telem->position = msg.position;
347
348 // Feedback ABI position messages
349 struct act_feedback_t feedback = {0};
350 feedback.idx = get_actuator_idx(iface, msg.actuator_id);
351 feedback.position = telem->position;
352 feedback.set.position = true;
353
354 // Send ABI message
356}
357
362{
363 // Decode the message
366 return; // Decoding error
367 }
368
369 // Get the correct telemetry
370 struct actuators_uavcan_telem_t *telem = get_actuator_telem(iface, msg.device_id);
371 if(telem == NULL) {
372 return;
373 }
374
375 telem->set = true;
376 telem->temperature_dev = msg.temperature - 273.15;
377}
378
379
384{
385 // Check if not already initialized (for multiple interfaces, needs only 1)
386 if (actuators_uavcan_initialized) { return; }
387
388 // Bind uavcan ESC_STATUS message from EQUIPMENT
391 // Bind uavcan ACTUATOR_STATUS message from EQUIPMENT
394 // Bind uavcan DEVICE_TEMPERATURE message from EQUIPMENT
397
398 // Configure telemetry
399#if PERIODIC_TELEMETRY
401#endif
402
403 // Set default to not used
404#ifdef SERVOS_UAVCAN1CMD_NB
405 for(uint8_t i = 0; i < SERVOS_UAVCAN1CMD_NB; i++)
407#endif
408#ifdef SERVOS_UAVCAN2CMD_NB
409 for(uint8_t i = 0; i < SERVOS_UAVCAN2CMD_NB; i++)
411#endif
412
413 // Set initialization
415
416 // Initialize Random (for telemetry)
417 init_random();
418}
419
424{
425 // Generate the message
427 msg.cmd.len = nb;
428 for (uint8_t i = 0; i < nb; i++) {
429 msg.cmd.data[i] = values[i];
430 }
431
432 // Encode the mssage
435
436 // Broadcast the raw command message on the interface
439}
440
445{
447 msg.commands.len = 0;
448
449 // Encode the values for each command
450 for (uint8_t i = 0; i < nb; i++) {
451 // Skip unused commands
452 if(values[i] == UAVCAN_CMD_UNUSED || values[i] < MIN_PPRZ || values[i] > MAX_PPRZ)
453 continue;
454
455 msg.commands.data[msg.commands.len].actuator_id = i;
456 msg.commands.data[msg.commands.len].command_type = UAVCAN_EQUIPMENT_ACTUATOR_COMMAND_COMMAND_TYPE_UNITLESS;
457 msg.commands.data[msg.commands.len].command_value = (float)values[i] / (float)MAX_PPRZ;
458 msg.commands.len++;
459 }
460
461 // Encode the message
464
465 // Broadcast the raw command message on the interface
468}
Main include for ABI (AirBorneInterface).
#define ACT_FEEDBACK_UAVCAN_ID
void actuators_uavcan1_set(uint8_t idx, int16_t value)
int16_t actuators_uavcan1_values[SERVOS_UAVCAN1_NB]
Stub file needed per uavcan interface because of generator.
int16_t actuators_uavcan1cmd_values[SERVOS_UAVCAN1CMD_NB]
Stub file needed per uavcan interface because of generator.
void actuators_uavcan1cmd_set(uint8_t idx, int16_t value)
void actuators_uavcan2_set(uint8_t idx, int16_t value)
int16_t actuators_uavcan2_values[SERVOS_UAVCAN2_NB]
Stub file needed per interface because of generator.
void actuators_uavcan2cmd_set(uint8_t idx, int16_t value)
int16_t actuators_uavcan2cmd_values[SERVOS_UAVCAN2CMD_NB]
Stub file needed per uavcan interface because of generator.
static void actuators_uavcan_send_esc(struct transport_tx *trans, struct link_device *dev)
void actuators_uavcan_init(struct uavcan_iface_t *iface)
Initialize an uavcan interface.
static void actuators_uavcan_device_temperature_cb(struct uavcan_iface_t *iface, CanardRxTransfer *transfer)
Whevener an DEVICE_TEMPERATURE message from the EQUIPMENT group is received.
static uavcan_event actuator_status_ev
static struct actuators_uavcan_telem_t * actuators_uavcan_next_telem(void)
void actuators_uavcan_commit(struct uavcan_iface_t *iface, int16_t *values, uint8_t nb)
Commit actuator values to the uavcan interface (EQUIPMENT_ESC_RAWCOMMAND)
static void actuators_uavcan_esc_status_cb(struct uavcan_iface_t *iface, CanardRxTransfer *transfer)
Whevener an ESC_STATUS message from the EQUIPMENT group is received.
static uavcan_event device_temperature_ev
static void actuators_uavcan_actuator_status_cb(struct uavcan_iface_t *iface, CanardRxTransfer *transfer)
Whevener an ACTUATOR_STATUS message from the EQUIPMENT group is received.
static bool actuators_uavcan_initialized
static uint8_t old_idx
static uint8_t esc_idx
void actuators_uavcan_cmd_commit(struct uavcan_iface_t *iface, int16_t *values, uint8_t nb)
Commit actuator values to the uavcan interface (EQUIPMENT_ACTUATOR_ARRAYCOMMAND)
static struct actuators_uavcan_telem_t * get_actuator_telem(struct uavcan_iface_t *iface, uint8_t idx)
#define UAVCAN_CMD_UNUSED
static uint8_t get_actuator_idx(struct uavcan_iface_t *iface, uint8_t idx)
static uavcan_event esc_status_ev
static struct uart_periph * dev
struct Electrical electrical
Definition electrical.c:92
Interface for electrical status: supply voltage, current, battery status, etc.
float current
current in A
Definition electrical.h:47
float vsupply
supply voltage in V
Definition electrical.h:45
uint8_t msg[10]
Buffer used for general comunication over SPI (out buffer)
uint16_t foo
Definition main_demo5.c:58
Hardware independent API for actuators (servos, motor controllers).
uint8_t idx
General index of the actuators (generated in airframe.h)
Definition actuators.h:45
static uint32_t idx
#define MAX_PPRZ
Definition paparazzi.h:8
#define MIN_PPRZ
Definition paparazzi.h:9
void init_random(void)
Definition pprz_random.c:35
double rand_uniform(void)
Definition pprz_random.c:45
uint16_t rpm
Definition rpm_sensor.c:33
static float get_sys_time_float(void)
Get the time in seconds since startup.
Definition sys_time.h:174
int16_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint16_t _id, telemetry_cb _cb)
Register a telemetry callback function.
Definition telemetry.c:51
Periodic telemetry system header (includes downlink utility and generated code).
#define DefaultPeriodic
Set default periodic telemetry.
Definition telemetry.h:66
void uavcan_broadcast(struct uavcan_iface_t *iface, uint64_t data_type_signature, uint16_t data_type_id, uint8_t priority, const void *payload, uint16_t payload_len)
Legacy function Broadcast an uavcan message to a specific interface.
Definition uavcan.c:313
void uavcan_bind(uint16_t data_type_id, uint64_t data_type_signature, uavcan_event *ev, uavcan_callback cb)
Bind to a receiving message from uavcan.
Definition uavcan.c:240
Main uavcan event structure for registering/calling callbacks.
Definition uavcan.h:74
uavcan interface structure
Definition uavcan.h:44
static const float offset[]
int int32_t
Typedef defining 32 bit int type.
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
short int16_t
Typedef defining 16 bit short type.
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
int transfer(const Mat *from, const image_t *to)