Paparazzi UAS v7.0_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 // Randomness added for multiple transport devices
126 uint8_t add_idx = 0;
127 if (rand_uniform() > 0.02) {
128 add_idx = 1;
129 }
130
131 // Find the next set telemetry
132 uint8_t offset = 0;
133#ifdef UAVCAN1_TELEM_NB
134 for(uint8_t i = esc_idx - offset; i < UAVCAN1_TELEM_NB; i++) {
135 if(uavcan1_telem[i].set) {
136 old_idx = i + offset;
137 esc_idx = i + offset + add_idx;
138 return &uavcan1_telem[i];
139 } else {
140 esc_idx = i + offset + 1;
141 }
142 }
144#endif
145#ifdef UAVCAN2_TELEM_NB
146 for(uint8_t i = esc_idx - offset; i < UAVCAN2_TELEM_NB; i++) {
147 if(uavcan2_telem[i].set) {
148 old_idx = i + offset;
149 esc_idx = i + offset + add_idx;
150 return &uavcan2_telem[i];
151 } else {
152 esc_idx = i + offset + 1;
153 }
154 }
156#endif
157
158 // Going round or no telemetry found
159 esc_idx = 0;
160 return NULL;
161}
162
163static void actuators_uavcan_send_esc(struct transport_tx *trans, struct link_device *dev)
164{
165 // Find the correct telemetry (Try twice if going round)
167 if(telem == NULL) {
169 }
170
171 // Safety check (no telemetry received 2 times)
172 if (telem == NULL) {
173 return;
174 }
175
176 float power = telem->current * telem->voltage;
177 float rpm = telem->rpm;
178 float energy = telem->energy;
179 pprz_msg_send_ESC(trans, dev, AC_ID, &telem->current, &electrical.vsupply, &power,
180 &rpm, &telem->voltage, &energy, &telem->temperature, &telem->temperature_dev, &telem->node_id, &old_idx);
181}
182#endif
183
186
187#ifdef UAVCAN1_TELEM_NB
188 if (iface == &uavcan1 && idx < UAVCAN1_TELEM_NB) {
190 }
191#endif
192#ifdef UAVCAN2_TELEM_NB
193 if (iface == &uavcan2 && idx < UAVCAN2_TELEM_NB) {
195 }
196#endif
197
198 return telem;
199}
200
202 uint8_t actuator_idx = 255;
203
204#ifdef UAVCAN1_TELEM_NB
205 if(iface == &uavcan1) {
206#ifdef SERVOS_UAVCAN1_NB
207 // First try as RAW COMMAND
209#endif
210#ifdef SERVOS_UAVCAN1CMD_NB
211 // Then try as ACTUATOR COMMAND
214 }
215#endif
216 }
217#endif
218#ifdef UAVCAN2_TELEM_NB
219 if(iface == &uavcan2) {
220#ifdef SERVOS_UAVCAN2_NB
221 // First try as RAW COMMAND
223#endif
224#ifdef SERVOS_UAVCAN2CMD_NB
225 // Then try as ACTUATOR COMMAND
228 }
229#endif
230 }
231#endif
232
233 return actuator_idx;
234}
235
240{
241 // Decode the message
244 return; // Decoding error
245 }
246
247 // Get the correct telemetry
249 if(telem == NULL) {
250 return;
251 }
252
253 // Set the telemetry (FIXME: copy over fully)
254 telem->set = true;
255 telem->node_id = transfer->source_node_id;
256 telem->timestamp = get_sys_time_float();
257 telem->energy = msg.error_count;
258 telem->voltage = msg.voltage;
259 telem->current = msg.current;
260 telem->temperature = msg.temperature;
261 telem->rpm = msg.rpm;
262
263 /* Specification says Kelvin, but some are transmitting in Celsius */
264 if (telem->temperature > 230.f) {
265 telem->temperature -= 273.15;
266 }
267
268 // Feedback ABI RPM messages
269 struct act_feedback_t feedback = {0};
270 feedback.idx = get_actuator_idx(iface, msg.esc_index);
271 feedback.rpm = telem->rpm;
272 feedback.set.rpm = true;
273
274 // Send ABI message
276
277#if UAVCAN_ACTUATORS_USE_CURRENT
278 // Update total current based on ESC telemetry
280#ifdef UAVCAN1_TELEM_NB
281 for (uint8_t i = 0; i < UAVCAN1_TELEM_NB; ++i) {
282 electrical.current += uavcan1_telem[i].current;
283 }
284#endif
285#ifdef UAVCAN2_TELEM_NB
286 for (uint8_t i = 0; i < UAVCAN2_TELEM_NB; ++i) {
287 electrical.current += uavcan2_telem[i].current;
288 }
289#endif
290#endif
291}
292
297{
298 // Decode the message
301 return; // Decoding error
302 }
303
304 // Get the correct telemetry
306 if(telem == NULL) {
307 return;
308 }
309
310 //telem[msg.actuator_id].set = true;
311 telem->position = msg.position;
312
313 // Feedback ABI position messages
314 struct act_feedback_t feedback = {0};
315 feedback.idx = get_actuator_idx(iface, msg.actuator_id);
316 feedback.position = telem->position;
317 feedback.set.position = true;
318
319 // Send ABI message
321}
322
327{
328 // Decode the message
331 return; // Decoding error
332 }
333
334 // Get the correct telemetry
336 if(telem == NULL) {
337 return;
338 }
339
340 telem->set = true;
341 telem->temperature_dev = msg.temperature - 273.15;
342}
343
344
349{
350 // Check if not already initialized (for multiple interfaces, needs only 1)
351 if (actuators_uavcan_initialized) { return; }
352
353 // Bind uavcan ESC_STATUS message from EQUIPMENT
356 // Bind uavcan ACTUATOR_STATUS message from EQUIPMENT
359 // Bind uavcan DEVICE_TEMPERATURE message from EQUIPMENT
362
363 // Configure telemetry
364#if PERIODIC_TELEMETRY
366#endif
367
368 // Set default to not used
369#ifdef SERVOS_UAVCAN1CMD_NB
370 for(uint8_t i = 0; i < SERVOS_UAVCAN1CMD_NB; i++)
372#endif
373#ifdef SERVOS_UAVCAN2CMD_NB
374 for(uint8_t i = 0; i < SERVOS_UAVCAN2CMD_NB; i++)
376#endif
377
378 // Set initialization
380
381 // Initialize Random (for telemetry)
382 init_random();
383}
384
389{
390 // Generate the message
392 msg.cmd.len = nb;
393 for (uint8_t i = 0; i < nb; i++) {
394 msg.cmd.data[i] = values[i];
395 }
396
397 // Encode the mssage
400
401 // Broadcast the raw command message on the interface
403 CANARD_TRANSFER_PRIORITY_HIGH, buffer, total_size);
404}
405
410{
412 msg.commands.len = 0;
413
414 // Encode the values for each command
415 for (uint8_t i = 0; i < nb; i++) {
416 // Skip unused commands
417 if(values[i] == UAVCAN_CMD_UNUSED || values[i] < MIN_PPRZ || values[i] > MAX_PPRZ)
418 continue;
419
420 msg.commands.data[msg.commands.len].actuator_id = i;
421 msg.commands.data[msg.commands.len].command_type = UAVCAN_EQUIPMENT_ACTUATOR_COMMAND_COMMAND_TYPE_UNITLESS;
422 msg.commands.data[msg.commands.len].command_value = (float)values[i] / (float)MAX_PPRZ;
423 msg.commands.len++;
424 }
425
426 // Encode the message
429
430 // Broadcast the raw command message on the interface
432 CANARD_TRANSFER_PRIORITY_HIGH, buffer, total_size);
433}
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
Main uavcan event structure for registering/calling callbacks.
Definition uavcan.h:76
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:46
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
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)
Broadcast an uavcan message to a specific interface.
Definition uavcan.c:265
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:250
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)