Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
power_uavcan.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2023 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  */
21 
26 #include "power_uavcan.h"
27 #include "uavcan/uavcan.h"
29 
30 /* uavcan EQUIPMENT_ESC_STATUS message definition */
31 #define UAVCAN_EQUIPMENT_POWER_BATTERYINFO_ID 1092
32 #define UAVCAN_EQUIPMENT_POWER_BATTERYINFO_SIGNATURE (0x249C26548A711966ULL)
33 #define UAVCAN_EQUIPMENT_POWER_BATTERYINFO_MAX_SIZE 55
34 
35 /* uavcan EQUIPMENT_POWER_CIRCUITSTATUS message definition */
36 #define UAVCAN_EQUIPMENT_POWER_CIRCUITSTATUS_ID 1091
37 #define UAVCAN_EQUIPMENT_POWER_CIRCUITSTATUS_SIGNATURE (0x8313D33D0DDDA115ULL)
38 #define UAVCAN_EQUIPMENT_POWER_CIRCUITSTATUS_MAX_SIZE 7
39 
40 /* Default maximum amount of batteries */
41 #ifndef POWER_UAVCAN_BATTERIES_MAX
42 #define POWER_UAVCAN_BATTERIES_MAX 3
43 #endif
44 
45 /* Default maximum amount of circuits */
46 #ifndef POWER_UAVCAN_CIRCUITS_MAX
47 #define POWER_UAVCAN_CIRCUITS_MAX 15
48 #endif
49 
50 /* Default Battery circuits */
51 #ifndef POWER_UAVCAN_BATTERY_CIRCUITS
52 #define POWER_UAVCAN_BATTERY_CIRCUITS {}
53 #endif
54 
55 /* Local variables */
58 
59 /* Batteries */
61  bool set;
63 
64  float temperature;
65  float voltage;
66  float current;
77 // struct { uint8_t len; uint8_t data[31]; }model_name;
78 };
80 
81 /* Circuits */
83  bool set;
85  bool is_battery;
86 
88  float voltage;
89  float current;
91 };
93 
94 /* Battery circuits */
98 };
100 
101 
102 static void power_uavcan_battery_cb(struct uavcan_iface_t *iface __attribute__((unused)), CanardRxTransfer *transfer)
103 {
104  uint16_t tmp_float = 0;
105 
106  /* Decode the message */
107  canardDecodeScalar(transfer, (uint32_t)0, 16, true, (void *)&tmp_float);
108  float temperature = canardConvertFloat16ToNativeFloat(tmp_float);
109  canardDecodeScalar(transfer, (uint32_t)16, 16, true, (void *)&tmp_float);
110  float voltage = canardConvertFloat16ToNativeFloat(tmp_float);
111  canardDecodeScalar(transfer, (uint32_t)32, 16, true, (void *)&tmp_float);
112  float current = canardConvertFloat16ToNativeFloat(tmp_float);
113  canardDecodeScalar(transfer, (uint32_t)48, 16, true, (void *)&tmp_float);
114  float average_power_10sec = canardConvertFloat16ToNativeFloat(tmp_float);
115  canardDecodeScalar(transfer, (uint32_t)64, 16, true, (void *)&tmp_float);
116  float remaining_capacity_wh = canardConvertFloat16ToNativeFloat(tmp_float);
117  canardDecodeScalar(transfer, (uint32_t)80, 16, true, (void *)&tmp_float);
118  float full_charge_capacity_wh = canardConvertFloat16ToNativeFloat(tmp_float);
119  canardDecodeScalar(transfer, (uint32_t)96, 16, true, (void *)&tmp_float);
120  float hours_to_full_charge = canardConvertFloat16ToNativeFloat(tmp_float);
121  uint16_t status_flags = 0;
122  canardDecodeScalar(transfer, (uint32_t)112, 11, false, (void *)&status_flags);
123  uint8_t state_of_health_pct = 0;
124  canardDecodeScalar(transfer, (uint32_t)123, 7, false, (void *)&state_of_health_pct);
125  uint8_t state_of_charge_pct = 0;
126  canardDecodeScalar(transfer, (uint32_t)130, 7, false, (void *)&state_of_charge_pct);
127  uint8_t state_of_charge_pct_stdev = 0;
128  canardDecodeScalar(transfer, (uint32_t)137, 7, false, (void *)&state_of_charge_pct_stdev);
129  uint8_t battery_id = 0;
130  canardDecodeScalar(transfer, (uint32_t)144, 8, false, (void *)&battery_id);
131  uint32_t model_instance_id = 0;
132  canardDecodeScalar(transfer, (uint32_t)152, 32, false, (void *)&model_instance_id);
133 
134  // Search for the battery or free spot
135  uint8_t battery_idx = POWER_UAVCAN_BATTERIES_MAX;
136  for (uint8_t i = 0; i < POWER_UAVCAN_BATTERIES_MAX; i++) {
137  if (batteries[i].set && batteries[i].node_id == transfer->source_node_id &&
138  batteries[i].battery_id == battery_id && batteries[i].model_instance_id == model_instance_id) {
139  battery_idx = i;
140  break;
141  }
142  else if(!batteries[i].set) {
143  battery_idx = i;
144  break;
145  }
146  }
147 
148  // No free spot found
149  if (battery_idx >= POWER_UAVCAN_BATTERIES_MAX) {
150  return;
151  }
152 
153  // Set the battery info
154  batteries[battery_idx].set = true;
155  batteries[battery_idx].node_id = transfer->source_node_id;
156  batteries[battery_idx].temperature = temperature;
157  batteries[battery_idx].voltage = voltage;
158  batteries[battery_idx].current = current;
159  batteries[battery_idx].average_power_10sec = average_power_10sec;
160  batteries[battery_idx].remaining_capacity_wh = remaining_capacity_wh;
161  batteries[battery_idx].full_charge_capacity_wh = full_charge_capacity_wh;
162  batteries[battery_idx].hours_to_full_charge = hours_to_full_charge;
163  batteries[battery_idx].status_flags = status_flags;
164  batteries[battery_idx].state_of_health_pct = state_of_health_pct;
165  batteries[battery_idx].state_of_charge_pct = state_of_charge_pct;
166  batteries[battery_idx].state_of_charge_pct_stdev = state_of_charge_pct_stdev;
167  batteries[battery_idx].battery_id = battery_id;
168  batteries[battery_idx].model_instance_id = model_instance_id;
169 
170  // Sum the battery currents
171  float current_sum = 0;
172  for (uint8_t i = 0; i < POWER_UAVCAN_BATTERIES_MAX; i++) {
173  if (batteries[i].set) {
174  current_sum += batteries[i].current;
175  }
176  }
177  electrical.current = current_sum;
178  if (voltage > 0) {
179  electrical.vsupply = voltage;
180  }
181 }
182 
183 static void power_uavcan_circuit_cb(struct uavcan_iface_t *iface __attribute__((unused)), CanardRxTransfer *transfer)
184 {
185  uint16_t tmp_float = 0;
186 
187  /* Decode the message */
188  uint16_t circuit_id = 0;
189  canardDecodeScalar(transfer, (uint32_t)0, 16, false, (void *)&circuit_id);
190  canardDecodeScalar(transfer, (uint32_t)16, 16, true, (void *)&tmp_float);
191  float voltage = canardConvertFloat16ToNativeFloat(tmp_float);
192  canardDecodeScalar(transfer, (uint32_t)32, 16, true, (void *)&tmp_float);
193  float current = canardConvertFloat16ToNativeFloat(tmp_float);
194  uint8_t error_flags = 0;
195  canardDecodeScalar(transfer, (uint32_t)48, 8, false, (void *)&error_flags);
196 
197  // Search for the circuit or free spot
198  uint8_t circuit_idx = POWER_UAVCAN_CIRCUITS_MAX;
199  for (uint8_t i = 0; i < POWER_UAVCAN_CIRCUITS_MAX; i++) {
200  if (circuits[i].set && circuits[i].node_id == transfer->source_node_id && circuits[i].circuit_id == circuit_id) {
201  circuit_idx = i;
202  break;
203  }
204  else if(!circuits[i].set) {
205  circuit_idx = i;
206  break;
207  }
208  }
209 
210  // No free spot found
211  if (circuit_idx >= POWER_UAVCAN_CIRCUITS_MAX) {
212  return;
213  }
214 
215  // Set the circuit info
216  circuits[circuit_idx].set = true;
217  circuits[circuit_idx].node_id = transfer->source_node_id;
218  circuits[circuit_idx].circuit_id = circuit_id;
219  circuits[circuit_idx].voltage = voltage;
220  circuits[circuit_idx].current = current;
221  circuits[circuit_idx].error_flags = error_flags;
222 
223  // Sum the 'battery' circuit currents
224  float current_sum = 0;
225  for (uint8_t i = 0; i < POWER_UAVCAN_CIRCUITS_MAX; i++) {
226  if (circuits[i].set && circuits[i].is_battery) {
227  current_sum += circuits[i].current;
228  }
229  }
230  electrical.current = current_sum;
231  if (voltage > 0 && circuits[circuit_idx].is_battery) {
232  electrical.vsupply = voltage;
233  }
234 }
235 
237 {
238  // Init the battery circuits
239  for (uint8_t i = 0; i < sizeof(battery_circuits) / sizeof(struct uavcan_circuit_battery_t); i++) {
240  circuits[i].set = true;
243  circuits[i].is_battery = true;
244  }
245 
246  // Bind uavcan BATTERYINFO message from EQUIPMENT.POWER
249 
250  // Bind uavcan CIRCUIT_STATUS message from EQUIPMENT.POWER
253 }
Main uavcan event structure for registering/calling callbacks.
Definition: uavcan.h:60
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
static struct uavcan_circuit_battery_t battery_circuits[]
Definition: power_uavcan.c:99
static void power_uavcan_battery_cb(struct uavcan_iface_t *iface, CanardRxTransfer *transfer)
Definition: power_uavcan.c:102
#define POWER_UAVCAN_BATTERY_CIRCUITS
Definition: power_uavcan.c:52
static void power_uavcan_circuit_cb(struct uavcan_iface_t *iface, CanardRxTransfer *transfer)
Definition: power_uavcan.c:183
#define UAVCAN_EQUIPMENT_POWER_CIRCUITSTATUS_SIGNATURE
Definition: power_uavcan.c:37
#define UAVCAN_EQUIPMENT_POWER_BATTERYINFO_SIGNATURE
Definition: power_uavcan.c:32
static uavcan_event circuit_uavcan_ev
Definition: power_uavcan.c:57
#define POWER_UAVCAN_CIRCUITS_MAX
Definition: power_uavcan.c:47
static struct uavcan_equipment_power_BatteryInfo batteries[POWER_UAVCAN_BATTERIES_MAX]
Definition: power_uavcan.c:79
void power_uavcan_init(void)
Definition: power_uavcan.c:236
#define UAVCAN_EQUIPMENT_POWER_CIRCUITSTATUS_ID
Definition: power_uavcan.c:36
static uavcan_event power_uavcan_ev
Definition: power_uavcan.c:56
#define POWER_UAVCAN_BATTERIES_MAX
Definition: power_uavcan.c:42
static struct uavcan_equipment_power_CircuitStatus circuits[POWER_UAVCAN_CIRCUITS_MAX]
Definition: power_uavcan.c:92
#define UAVCAN_EQUIPMENT_POWER_BATTERYINFO_ID
Definition: power_uavcan.c:31
Power sensors on the uavcan bus.
uavcan interface structure
Definition: uavcan.h:34
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:412
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88
unsigned int uint32_t
Typedef defining 32 bit unsigned int type.
Definition: vl53l1_types.h:78
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98
int transfer(const Mat *from, const image_t *to)