Paparazzi UAS  v7.0_unstable
Paparazzi is a free software Unmanned Aircraft System.
actuators_faulhaber.c
Go to the documentation of this file.
1 /*
2  * Copyright (C) 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, see
18  * <http://www.gnu.org/licenses/>.
19  */
20 
28 #include "mcu_periph/uart.h"
29 #include "mcu_periph/sys_time.h"
31 #include "modules/core/abi.h"
32 #include <stdio.h>
33 #include <string.h>
34 
35 /* Proportional gain on the velocity for the position controller */
36 #ifndef FAULHABER_P_GAIN
37 #define FAULHABER_P_GAIN 0.07
38 #endif
39 
40 /* Maximum velocity for the position controller */
41 #ifndef FAULHABER_MAX_VELOCITY
42 #define FAULHABER_MAX_VELOCITY 12000
43 #endif
44 
45 static struct uart_periph *faulhaber_dev = &(FAULHABER_DEV);
46 
47 /* Faulhaber message parser */
55 
57 };
58 static struct faulhaber_parser_t faulhaber_p;
59 struct faulhaber_t faulhaber;
60 
61 #define Polynom 0xD5
62 static uint8_t faulhaber_crc8(uint8_t u8Byte, uint8_t u8CRC)
63 {
64  uint8_t i;
65  u8CRC = u8CRC ^ u8Byte;
66  for (i = 0; i < 8; i++) {
67  if (u8CRC & 0x01) {
68  u8CRC = (u8CRC >> 1) ^ Polynom;
69  } else {
70  u8CRC >>= 1;
71  }
72  }
73  return u8CRC;
74 }
75 
76 static void faulhaber_send_command(struct uart_periph *dev, uint8_t cmd_code, uint8_t *data, uint8_t data_length)
77 {
78  uart_put_byte(dev, 0, 'S'); // Character (S) as Start of Frame
79  uart_put_byte(dev, 0, data_length + 4); // Telegram length without SOF/EOF (packet length)
80  uint8_t crc8 = faulhaber_crc8(data_length + 4, 0xFF); // Start CRC with 0xFF
81  uart_put_byte(dev, 0, 0x01); // Node number of the slave (0 = Broadcast)
82  crc8 = faulhaber_crc8(0x01, crc8);
83  uart_put_byte(dev, 0, cmd_code); // See Tab. 2
84  crc8 = faulhaber_crc8(cmd_code, crc8);
85  for (uint8_t i = 0; i < data_length; i++) { // Data area (length = packet length – 4)
86  uart_put_byte(dev, 0, data[i]);
87  crc8 = faulhaber_crc8(data[i], crc8);
88  }
89  uart_put_byte(dev, 0, crc8); // CRC8 with polynomial 0xD5 over byte 2–N
90  uart_put_byte(dev, 0, 'E'); // Character (E) as End of Frame
92 }
93 
94 #define UINIT 0
95 #define GOT_SOF 1
96 #define GOT_LENGTH 2
97 #define GOT_NODE_NB 3
98 #define GET_DATA 4
99 #define GET_CRC 5
100 #define GET_EOF 6
101 #define GOT_FULL_PACKET 7
102 
104 {
105  switch (p->state) {
106  case UINIT:
107  if (c == 'S') {
108  p->state = GOT_SOF;
109  p->calc_crc8 = 0xFF;
110  }
111  break;
112  case GOT_SOF:
113  if (c - 4 < 0) {
114  p->state = UINIT;
115  } else {
116  p->data_length = c - 4;
117  p->calc_crc8 = faulhaber_crc8(c, p->calc_crc8);
118  p->state = GOT_LENGTH;
119  }
120  break;
121  case GOT_LENGTH:
122  p->node_nb = c;
123  p->calc_crc8 = faulhaber_crc8(c, p->calc_crc8);
124  p->state = GOT_NODE_NB;
125  break;
126  case GOT_NODE_NB:
127  p->cmd_code = c;
128  p->data_idx = 0;
129  p->calc_crc8 = faulhaber_crc8(c, p->calc_crc8);
130  p->state = GET_DATA;
131  break;
132  case GET_DATA:
133  p->data[p->data_idx++] = c;
134  p->calc_crc8 = faulhaber_crc8(c, p->calc_crc8);
135  if (p->data_idx >= p->data_length) {
136  p->state = GET_CRC;
137  }
138  break;
139  case GET_CRC:
140  if (p->calc_crc8 == c) {
141  p->state = GET_EOF;
142  } else {
143  p->state = UINIT;
144  }
145  break;
146  case GET_EOF:
147  if (c == 'E') {
148  p->state = GOT_FULL_PACKET;
149  } else {
150  p->state = UINIT;
151  }
152  break;
153  default:
154  p->state = UINIT;
155  break;
156  }
157 }
158 
159 // Controlword 0x6040.00
160 // <Statusword 0x6041.00
161 // 0x6060 (Mode of Operation) (6: HOME, 1: PP)
162 // <0x6061.00(Mode of Operation feedback)
163 // 0x607A.00 (Target Position)
164 // <0x607A.00 (Actual Position)
165 // Start positioning via the rising edge in bit 4 of the controlword. Also set the optional bits here.
166 
168 {
170 
172  faulhaber.state = 0;
175  faulhaber.homing_completed = false;
176  faulhaber.position_ready = false;
177  faulhaber.target_reached = false;
180 }
181 
183 {
184  static float last_time = 0;
185  switch (faulhaber.mode) {
186 
187  /* Initialize and home the motor */
188  case FH_MODE_INIT:
189  switch(faulhaber.state) {
190  case 0: {
191  // Start the controller boot timer
193  faulhaber.state++;
194  break;
195  }
196  case 1: {
197  // Check if the controller is ready, 5 seconds delay
198  if (get_sys_time_float() - last_time < 5.0)
199  break;
200 
201  // Enable power on the motor
202  static uint8_t data[] = { 0x40, 0x60, 0x00, 0x0E, 0x00}; // Set 0x6040.00 to 0x000E: Try to start
203  faulhaber_send_command(faulhaber_dev, 0x02, data, 5);
205  faulhaber.state++;
206  break;
207  }
208  case 2: {
209  // Wait 10ms for the next command
210  if(get_sys_time_float() - last_time < 0.01)
211  break;
212 
213  // Set to homing mode
214  static uint8_t data[] = { 0x60, 0x60, 0x00, 0x06 }; // Set 0x6060.00 to 0x06: Homing mode
215  faulhaber_send_command(faulhaber_dev, 0x02, data, 4);
217  faulhaber.state++;
218  break;
219  }
220  case 3: {
221  // Wait 10ms for the next command
222  if(get_sys_time_float() - last_time < 0.01)
223  break;
224 
225  // Set the homing method
226  static uint8_t data[] = { 0x98, 0x60, 0x00, 0x11 }; // Set 0x6098.00 to 0x11: Homing method to 17
227  faulhaber_send_command(faulhaber_dev, 0x02, data, 4);
229  faulhaber.state++;
230  break;
231  }
232  case 4: {
233  // Wait 10ms for the next command
234  if(get_sys_time_float() - last_time < 0.01)
235  break;
236 
237  // Enable operation
238  static uint8_t data[] = { 0x40, 0x60, 0x00, 0x0F, 0x00}; // Set 0x6040.00 to 0x000F: Enable operation
239  faulhaber_send_command(faulhaber_dev, 0x02, data, 5);
241  faulhaber.state++;
242  break;
243  }
244  case 5: {
245  // Wait 10ms for the next command
246  if(get_sys_time_float() - last_time < 0.01)
247  break;
248 
249  // Start moving
250  static uint8_t data[] = { 0x40, 0x60, 0x00, 0x1F, 0x00}; // Set 0x6040.00 to 0x001F: Start moving
251  faulhaber_send_command(faulhaber_dev, 0x02, data, 5);
253  faulhaber.state++;
254  break;
255  }
256  case 6: {
257  // Check if homing is completed
259  // Continue initialization
261  faulhaber.state++;
262  }
263  // Timeout after 40 seconds
264  else if(get_sys_time_float() - last_time > 40.0) {
266  faulhaber.state = 0;
267  }
268  break;
269  }
270  case 7: {
271  // Wait 10ms for the next command
272  if(get_sys_time_float() - last_time < 0.01)
273  break;
274 
275  // Set to velocity mode
276  static uint8_t data[] = { 0x60, 0x60, 0x00, 0x03 }; // Set 0x6060.00 to 0x03: Velocity mode
277  faulhaber_send_command(faulhaber_dev, 0x02, data, 4);
279  faulhaber.state++;
280  break;
281  }
282  case 8: {
283  // Wait 10ms for the next command
284  if(get_sys_time_float() - last_time < 0.01)
285  break;
286 
287  // Enable operation
288  static uint8_t data[] = { 0x40, 0x60, 0x00, 0x0F, 0x00}; // Set 0x6040.00 to 0x000F: Enable operation
289  faulhaber_send_command(faulhaber_dev, 0x02, data, 5);
291  faulhaber.state++;
292  break;
293  }
294  case 9: {
295  // Wait 10ms for the next command
296  if(get_sys_time_float() - last_time < 0.01)
297  break;
298 
299  // Go to position mode
301  faulhaber.state = 0;
302  }
303  }
304  break;
305 
306  /* FH_MODE_VELOCITY */
307  case FH_MODE_VELOCITY: {
308  // Request position and set the new velocity target
309  switch (faulhaber.state) {
310  case 0: {
311  // Request the position
312  uint8_t data[] = { 0x64, 0x60, 0x00}; // Get 0x6064.00: Get the actual position
313  faulhaber_send_command(faulhaber_dev, 0x01, data, 3);
314  faulhaber.state++;
315  break;
316  }
317  default: {
318  // Calculate the new velocity target
322 
323  // Set the new velocity target
324  uint8_t data[] = { 0xFF, 0x60, 0x00, (faulhaber.target_velocity & 0xFF), ((faulhaber.target_velocity >> 8) & 0xFF), ((faulhaber.target_velocity >> 16) & 0xFF), ((faulhaber.target_velocity >> 24) & 0xFF) }; // Set 0x60FF.00 to [velocity]: Target velocity
325  faulhaber_send_command(faulhaber_dev, 0x02, data, 7);
326  faulhaber.state = 0;
327  break;
328  }
329  }
330  break;
331  }
332 
333  /* FH_MODE_REQ_ERR */
334  case FH_MODE_REQ_ERR: {
335  switch(faulhaber.state) {
336  case 0: {
337  // Request the status code
338  uint8_t data[] = { 0x20, 0x23, 0x00}; // Get 0x2320.00: Get the error code
339  faulhaber_send_command(faulhaber_dev, 0x01, data, 3);
340  faulhaber.state++;
341  break;
342  }
343  case 1: {
344  // Request the status code
345  uint8_t data[] = { 0x21, 0x23, 0x00}; // Get 0x2321.00: Get the error mask
346  faulhaber_send_command(faulhaber_dev, 0x01, data, 3);
347  faulhaber.state++;
348  break;
349  }
350  case 2: {
351  // Request the status code
352  uint8_t data[] = { 0x01, 0x10, 0x00}; // Get 0x1001.00: Get the error mask
353  faulhaber_send_command(faulhaber_dev, 0x01, data, 3);
354  faulhaber.state++;
355  break;
356 
357  }
358  default: {
359  // Do nothing and stop requesting
360  break;
361  }
362  }
363  break;
364  }
365 
366  /* FH_MODE_RESET_ERR */
367  case FH_MODE_RESET_ERR: {
368  switch(faulhaber.state) {
369  case 0: {
370  static uint8_t data[] = { 0x40, 0x60, 0x00, 0x0E, 0x00}; // Set 0x6040.00 to 0x000E: Try to start
371  faulhaber_send_command(faulhaber_dev, 0x02, data, 5);
372  faulhaber.state++;
373  break;
374  }
375  case 1: {
376  static uint8_t data[] = { 0x60, 0x60, 0x00, 0x03 }; // Set 0x6060.00 to 0x03: Velocity mode
377  faulhaber_send_command(faulhaber_dev, 0x02, data, 4);
378  faulhaber.state++;
379  break;
380  }
381  default: {
382  // Enable operation
383  static uint8_t data[] = { 0x40, 0x60, 0x00, 0x0F, 0x00}; // Set 0x6040.00 to 0x000F: Enable operation
384  faulhaber_send_command(faulhaber_dev, 0x02, data, 5);
385  faulhaber.state = 0;
387  break;
388  }
389  }
390  break;
391  }
392 
393  /* Do nothing */
394  default:
395  break;
396  }
397 
398 }
399 
401 {
402  // Process position message
403  if (p->cmd_code == 0x01 && p->data[0] == 0x64 && p->data[1] == 0x60 && p->data[2] == 0x00) {
404  faulhaber.real_position = p->data[3] | (p->data[4] << 8) | (p->data[5] << 16) | (p->data[6] << 24);
405 
406  struct act_feedback_t feedback = {0};
407  feedback.position = ((faulhaber.real_position/ACTUATORS_FAULHABER_COMMAND_SCALE) - get_servo_min_FAULHABER(0)) / (double)(get_servo_max_FAULHABER(
408  0) - get_servo_min_FAULHABER(0)) * M_PI_2; // In radians
409  feedback.set.position = true;
410  feedback.idx = get_servo_idx_FAULHABER(0);
411 
412  // Send ABI message
413  AbiSendMsgACT_FEEDBACK(ACT_FEEDBACK_FAULHABER_ID, &feedback, 1);
414  }
415  // Write requests
416  else if(p->cmd_code == 0x02) {
417  // Do nothing
418  }
419  // Parse the statuscode message
420  else if(p->cmd_code == 0x05) {
421  uint16_t status_code = p->data[0] | (p->data[1] << 8);
422 
423  // Homing
424  if(!faulhaber.homing_completed && status_code&0x1000 && status_code&0x400)
426 
427  // Position accepted
428  if(!faulhaber.position_ready && status_code&0x1000)
429  faulhaber.position_ready = true;
430 
431  // Target reached
432  if(!faulhaber.target_reached && status_code&0x400)
433  faulhaber.target_reached = true;
434 
435  // If the drive got disabled
436  if(!(status_code&0x0001) || !(status_code&0x0002) || !(status_code&0x0004)) {
437  char error_msg[250];
438  int rc = snprintf(error_msg, 200, "[FH]%d %04X", p->cmd_code, status_code);
439  DOWNLINK_SEND_INFO_MSG(DefaultChannel, DefaultDevice, rc, error_msg);
440  }
441  }
442  else {
443  // Unknown message
444  char error_msg[250];
445  int rc = snprintf(error_msg, 200, "[FH]%d ", p->cmd_code);
446  for(int i = 0; i < p->data_length; i++) {
447  rc += snprintf(error_msg + rc, 200 - rc, "%02X", p->data[i]);
448  }
449 
450  if (rc > 0) {
451  DOWNLINK_SEND_INFO_MSG(DefaultChannel, DefaultDevice, rc, error_msg);
452  }
453  }
454 }
455 
456 
458 {
464  }
465  }
466 }
467 
469 {
470  faulhaber.mode = mode;
471  faulhaber.state = 0;
472 }
Main include for ABI (AirBorneInterface).
#define ACT_FEEDBACK_FAULHABER_ID
static void faulhaber_send_command(struct uart_periph *dev, uint8_t cmd_code, uint8_t *data, uint8_t data_length)
static struct uart_periph * faulhaber_dev
#define GET_DATA
#define GOT_FULL_PACKET
static uint8_t faulhaber_crc8(uint8_t u8Byte, uint8_t u8CRC)
void actuators_faulhaber_event(void)
struct faulhaber_t faulhaber
#define UINIT
#define GOT_LENGTH
#define GET_CRC
#define GOT_NODE_NB
#define FAULHABER_MAX_VELOCITY
#define Polynom
static void faulhaber_parser(struct faulhaber_parser_t *p, uint8_t c)
#define GET_EOF
static struct faulhaber_parser_t faulhaber_p
#define FAULHABER_P_GAIN
static void faulhaber_parse_msg(struct faulhaber_parser_t *p)
void actuators_faulhaber_periodic(void)
void actuators_faulhaber_init(void)
#define GOT_SOF
void actuators_faulhaber_SetMode(uint8_t mode)
float p_gain
The proportional gain of the velocity controller.
int32_t max_velocity
The maximum velocity of the controller.
int32_t real_position
The real position from the feedback of the controller.
#define ACTUATORS_FAULHABER_COMMAND_SCALE
bool target_reached
When the target position is reached.
enum faulhaber_modes_t mode
Current mode of the controller.
bool homing_completed
Once the homing is completed.
int32_t setpoint_position
The setpoint position controlled from the actuator.
int32_t target_velocity
The target velocity send to the controller.
uint8_t state
The state of the mode.
bool position_ready
Ready for receiving (new) positions.
@ FH_MODE_ERROR
@ FH_MODE_VELOCITY
@ FH_MODE_RESET_ERR
@ FH_MODE_REQ_ERR
@ FH_MODE_INIT
static float last_time
static float p[2][2]
void uart_put_byte(struct uart_periph *periph, long fd, uint8_t data)
Definition: uart_arch.c:306
int uart_char_available(struct uart_periph *p)
Check UART for available chars in receive buffer.
Definition: uart_arch.c:357
uint8_t uart_getch(struct uart_periph *p)
Definition: uart_arch.c:348
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 uint8_t mode
mode holds the current sonar mode mode = 0 used at high altitude, uses 16 wave patterns mode = 1 used...
Definition: sonar_bebop.c:65
static const struct usb_device_descriptor dev
Definition: usb_ser_hw.c:74
Architecture independent timing functions.
static float get_sys_time_float(void)
Get the time in seconds since startup.
Definition: sys_time.h:138
void WEAK uart_send_message(struct uart_periph *p, long fd)
Definition: uart.c:275
arch independent UART (Universal Asynchronous Receiver/Transmitter) API
UART peripheral.
Definition: uart.h:72
unsigned short uint16_t
Typedef defining 16 bit unsigned short type.
Definition: vl53l1_types.h:88
int int32_t
Typedef defining 32 bit int type.
Definition: vl53l1_types.h:83
unsigned char uint8_t
Typedef defining 8 bit unsigned char type.
Definition: vl53l1_types.h:98