Paparazzi UAS v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Modules Pages
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#endif
63#ifdef SERVOS_UAVCAN2_NB
65#endif
66#ifdef SERVOS_UAVCAN1CMD_NB
68#endif
69#ifdef SERVOS_UAVCAN2CMD_NB
71#endif
72
73/* Set the actual telemetry length (ID's from actuators can't collide with the command version) */
74#if SERVOS_UAVCAN1CMD_NB > SERVOS_UAVCAN1_NB
75#define UAVCAN1_TELEM_NB SERVOS_UAVCAN1CMD_NB
77#elif defined(SERVOS_UAVCAN1_NB)
78#define UAVCAN1_TELEM_NB SERVOS_UAVCAN1_NB
80#endif
81
82#if SERVOS_UAVCAN2CMD_NB > SERVOS_UAVCAN2_NB
83#define UAVCAN2_TELEM_NB SERVOS_UAVCAN2CMD_NB
85#elif defined(SERVOS_UAVCAN2_NB)
86#define UAVCAN2_TELEM_NB SERVOS_UAVCAN2_NB
88#endif
89
90/* UNUSED value for CMD */
91#define UAVCAN_CMD_UNUSED (MIN_PPRZ-1)
92
93/* private variables */
94static bool actuators_uavcan_initialized = false;
98
99#if PERIODIC_TELEMETRY
101
102static uint8_t old_idx = 0;
103static uint8_t esc_idx = 0;
105 // Randomness added for multiple transport devices
106 uint8_t add_idx = 0;
107 if (rand_uniform() > 0.02) {
108 add_idx = 1;
109 }
110
111 // Find the next set telemetry
112 uint8_t offset = 0;
113#ifdef UAVCAN1_TELEM_NB
114 for(uint8_t i = esc_idx - offset; i < UAVCAN1_TELEM_NB; i++) {
115 if(uavcan1_telem[i].set) {
116 old_idx = i + offset;
117 esc_idx = i + offset + add_idx;
118 return &uavcan1_telem[i];
119 } else {
120 esc_idx = i + offset + 1;
121 }
122 }
124#endif
125#ifdef UAVCAN2_TELEM_NB
126 for(uint8_t i = esc_idx - offset; i < UAVCAN2_TELEM_NB; i++) {
127 if(uavcan2_telem[i].set) {
128 old_idx = i + offset;
129 esc_idx = i + offset + add_idx;
130 return &uavcan2_telem[i];
131 } else {
132 esc_idx = i + offset + 1;
133 }
134 }
136#endif
137
138 // Going round or no telemetry found
139 esc_idx = 0;
140 return NULL;
141}
142
143static void actuators_uavcan_send_esc(struct transport_tx *trans, struct link_device *dev)
144{
145 // Find the correct telemetry (Try twice if going round)
147 if(telem == NULL) {
149 }
150
151 // Safety check (no telemetry received 2 times)
152 if (telem == NULL) {
153 return;
154 }
155
156 float power = telem->current * telem->voltage;
157 float rpm = telem->rpm;
158 float energy = telem->energy;
159 pprz_msg_send_ESC(trans, dev, AC_ID, &telem->current, &electrical.vsupply, &power,
160 &rpm, &telem->voltage, &energy, &telem->temperature, &telem->temperature_dev, &telem->node_id, &old_idx);
161}
162#endif
163
166
167#ifdef UAVCAN1_TELEM_NB
168 if (iface == &uavcan1 && idx < UAVCAN1_TELEM_NB) {
170 }
171#endif
172#ifdef UAVCAN2_TELEM_NB
173 if (iface == &uavcan2 && idx < UAVCAN2_TELEM_NB) {
175 }
176#endif
177
178 return telem;
179}
180
182 uint8_t actuator_idx = 255;
183
184#ifdef UAVCAN1_TELEM_NB
185 if(iface == &uavcan1) {
186#ifdef SERVOS_UAVCAN1_NB
187 // First try as RAW COMMAND
189#endif
190#ifdef SERVOS_UAVCAN1CMD_NB
191 // Then try as ACTUATOR COMMAND
194 }
195#endif
196 }
197#endif
198#ifdef UAVCAN2_TELEM_NB
199 if(iface == &uavcan2) {
200#ifdef SERVOS_UAVCAN2_NB
201 // First try as RAW COMMAND
203#endif
204#ifdef SERVOS_UAVCAN2CMD_NB
205 // Then try as ACTUATOR COMMAND
208 }
209#endif
210 }
211#endif
212
213 return actuator_idx;
214}
215
220{
221 // Decode the message
224 return; // Decoding error
225 }
226
227 // Get the correct telemetry
229 if(telem == NULL) {
230 return;
231 }
232
233 // Set the telemetry (FIXME: copy over fully)
234 telem->set = true;
235 telem->node_id = transfer->source_node_id;
236 telem->timestamp = get_sys_time_float();
237 telem->energy = msg.error_count;
238 telem->voltage = msg.voltage;
239 telem->current = msg.current;
240 telem->temperature = msg.temperature;
241 telem->rpm = msg.rpm;
242
243 /* Specification says Kelvin, but some are transmitting in Celsius */
244 if (telem->temperature > 230.f) {
245 telem->temperature -= 273.15;
246 }
247
248 // Feedback ABI RPM messages
249 struct act_feedback_t feedback = {0};
250 feedback.idx = get_actuator_idx(iface, msg.esc_index);
251 feedback.rpm = telem->rpm;
252 feedback.set.rpm = true;
253
254 // Send ABI message
256
257#if UAVCAN_ACTUATORS_USE_CURRENT
258 // Update total current based on ESC telemetry
260#ifdef UAVCAN1_TELEM_NB
261 for (uint8_t i = 0; i < UAVCAN1_TELEM_NB; ++i) {
262 electrical.current += uavcan1_telem[i].current;
263 }
264#endif
265#ifdef UAVCAN2_TELEM_NB
266 for (uint8_t i = 0; i < UAVCAN2_TELEM_NB; ++i) {
267 electrical.current += uavcan2_telem[i].current;
268 }
269#endif
270#endif
271}
272
277{
278 // Decode the message
281 return; // Decoding error
282 }
283
284 // Get the correct telemetry
286 if(telem == NULL) {
287 return;
288 }
289
290 //telem[msg.actuator_id].set = true;
291 telem->position = msg.position;
292
293 // Feedback ABI position messages
294 struct act_feedback_t feedback = {0};
295 feedback.idx = get_actuator_idx(iface, msg.actuator_id);
296 feedback.position = telem->position;
297 feedback.set.position = true;
298
299 // Send ABI message
301}
302
307{
308 // Decode the message
311 return; // Decoding error
312 }
313
314 // Get the correct telemetry
316 if(telem == NULL) {
317 return;
318 }
319
320 telem->set = true;
321 telem->temperature_dev = msg.temperature - 273.15;
322}
323
324
329{
330 // Check if not already initialized (for multiple interfaces, needs only 1)
331 if (actuators_uavcan_initialized) { return; }
332
333 // Bind uavcan ESC_STATUS message from EQUIPMENT
336 // Bind uavcan ACTUATOR_STATUS message from EQUIPMENT
339 // Bind uavcan DEVICE_TEMPERATURE message from EQUIPMENT
342
343 // Configure telemetry
344#if PERIODIC_TELEMETRY
346#endif
347
348 // Set default to not used
349#ifdef SERVOS_UAVCAN1CMD_NB
350 for(uint8_t i = 0; i < SERVOS_UAVCAN1CMD_NB; i++)
352#endif
353#ifdef SERVOS_UAVCAN2CMD_NB
354 for(uint8_t i = 0; i < SERVOS_UAVCAN2CMD_NB; i++)
356#endif
357
358 // Set initialization
360
361 // Initialize Random (for telemetry)
362 init_random();
363}
364
369{
370 // Generate the message
372 msg.cmd.len = nb;
373 for (uint8_t i = 0; i < nb; i++) {
374 msg.cmd.data[i] = values[i];
375 }
376
377 // Encode the mssage
380
381 // Broadcast the raw command message on the interface
383 CANARD_TRANSFER_PRIORITY_HIGH, buffer, total_size);
384}
385
390{
392 msg.commands.len = 0;
393
394 // Encode the values for each command
395 for (uint8_t i = 0; i < nb; i++) {
396 // Skip unused commands
397 if(values[i] == UAVCAN_CMD_UNUSED || values[i] < MIN_PPRZ || values[i] > MAX_PPRZ)
398 continue;
399
400 msg.commands.data[msg.commands.len].actuator_id = i;
401 msg.commands.data[msg.commands.len].command_type = UAVCAN_EQUIPMENT_ACTUATOR_COMMAND_COMMAND_TYPE_UNITLESS;
402 msg.commands.data[msg.commands.len].command_value = (float)values[i] / (float)MAX_PPRZ;
403 msg.commands.len++;
404 }
405
406 // Encode the message
409
410 // Broadcast the raw command message on the interface
412 CANARD_TRANSFER_PRIORITY_HIGH, buffer, total_size);
413}
Main include for ABI (AirBorneInterface).
#define ACT_FEEDBACK_UAVCAN_ID
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.
int16_t actuators_uavcan2_values[SERVOS_UAVCAN2_NB]
Stub file needed per interface because of generator.
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
Main uavcan event structure for registering/calling callbacks.
Definition uavcan.h:60
static const float offset[]
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).
int32_t rpm
RPM.
Definition actuators.h:51
bool position
Position is set.
Definition actuators.h:48
struct act_feedback_t::act_feedback_set_t set
Bitset registering what is set as feedback.
uint8_t idx
General index of the actuators (generated in airframe.h)
Definition actuators.h:45
float position
In radians.
Definition actuators.h:52
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
uavcan interface structure
Definition uavcan.h:34
static const struct usb_device_descriptor dev
Definition usb_ser_hw.c:74
static float get_sys_time_float(void)
Get the time in seconds since startup.
Definition sys_time.h:138
int8_t register_periodic_telemetry(struct periodic_telemetry *_pt, uint8_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)
Broadcast an uavcan message to a specific interface.
Definition uavcan.c:432
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:417
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)