PX4 Firmware
PX4 Autopilot Software http://px4.io
mkblctrl.cpp
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * Copyright (C) 2012-2015 PX4 Development Team. All rights reserved.
4  * Author: Marco Bauer <marco@wtns.de>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  * notice, this list of conditions and the following disclaimer in
14  * the documentation and/or other materials provided with the
15  * distribution.
16  * 3. Neither the name PX4 nor the names of its contributors may be
17  * used to endorse or promote products derived from this software
18  * without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  *
33  ****************************************************************************/
34 
35 /**
36  * @file mkblctrl.cpp
37  *
38  * Driver/configurator for the Mikrokopter BL-Ctrl.
39  *
40  * @author Marco Bauer <marco@wtns.de>
41  *
42  */
43 
44 #include <px4_platform_common/px4_config.h>
45 #include <px4_platform_common/tasks.h>
46 #include <drivers/device/i2c.h>
47 #include <parameters/param.h>
48 
49 #include <sys/types.h>
50 #include <stdint.h>
51 #include <stdbool.h>
52 #include <stdlib.h>
53 #include <semaphore.h>
54 #include <string.h>
55 #include <fcntl.h>
56 #include <poll.h>
57 #include <errno.h>
58 #include <stdio.h>
59 #include <math.h>
60 #include <unistd.h>
61 
62 #include <nuttx/arch.h>
63 #include <nuttx/i2c/i2c_master.h>
64 
65 #include <board_config.h>
66 
67 #include <drivers/device/device.h>
68 #include <drivers/drv_pwm_output.h>
69 #include <drivers/drv_hrt.h>
70 #include <drivers/drv_rc_input.h>
71 #include <drivers/drv_mixer.h>
72 #include <drivers/drv_tone_alarm.h>
73 
74 #include <systemlib/err.h>
75 #include <lib/mixer/MixerGroup.hpp>
76 
80 #include <uORB/topics/esc_status.h>
82 
83 #include <systemlib/err.h>
84 
85 #define I2C_BUS_SPEED 100000
86 #define UPDATE_RATE 200
87 #define MAX_MOTORS 8
88 #define BLCTRL_BASE_ADDR 0x29
89 #define BLCTRL_OLD 0
90 #define BLCTRL_NEW 1
91 #define BLCTRL_MIN_VALUE -0.920F
92 #define MOTOR_STATE_PRESENT_MASK 0x80
93 #define MOTOR_STATE_ERROR_MASK 0x7F
94 #define MOTOR_SPINUP_COUNTER 30
95 #define MOTOR_LOCATE_DELAY 10000000
96 #define ESC_UORB_PUBLISH_DELAY 500000
97 
98 #define CONTROL_INPUT_DROP_LIMIT_MS 20
99 #define RC_MIN_VALUE 1010
100 #define RC_MAX_VALUE 2100
101 
102 
103 struct MotorData_t {
104  unsigned int Version; // the version of the BL (0 = old)
105  unsigned int SetPoint; // written by attitude controller
106  unsigned int SetPointLowerBits; // for higher Resolution of new BLs
107  float SetPoint_PX4; // Values from PX4
108  unsigned int State; // 7 bit for I2C error counter, highest bit indicates if motor is present
109  unsigned int ReadMode; // select data to read
110  unsigned short RawPwmValue; // length of PWM pulse
111  // the following bytes must be exactly in that order!
112  unsigned int Current; // in 0.1 A steps, read back from BL
113  unsigned int MaxPWM; // read back from BL is less than 255 if BL is in current limit
114  unsigned int Temperature; // old BL-Ctrl will return a 255 here, the new version the temp. in
115  unsigned int RoundCount;
116 };
117 
118 
119 
120 
121 class MK : public device::I2C
122 {
123 public:
124  enum MappingMode {
125  MAPPING_MK = 0,
127  };
128 
129  enum FrameType {
130  FRAME_PLUS = 0,
132  };
133 
134  MK(int bus, const char *_device_path);
135  ~MK();
136 
137  virtual int ioctl(file *filp, int cmd, unsigned long arg);
138  virtual int init(unsigned motors);
139  virtual ssize_t write(file *filp, const char *buffer, size_t len);
140 
141  int set_motor_count(unsigned count);
142  int set_motor_test(bool motortest);
143  int set_overrideSecurityChecks(bool overrideSecurityChecks);
144  void set_px4mode(int px4mode);
145  void set_frametype(int frametype);
146  unsigned int mk_check_for_blctrl(unsigned int count, bool showOutput, bool initI2C);
147  void set_rc_min_value(unsigned value);
148  void set_rc_max_value(unsigned value);
149 
150 private:
151  static const unsigned _max_actuators = MAX_MOTORS;
152  static const bool showDebug = false;
153 
155  int _task;
158  unsigned int _motor;
159  int _px4mode;
161  char _device[20];
165  unsigned int _num_outputs;
169  volatile bool _task_should_exit;
170  bool _armed;
171  unsigned long debugCounter;
174  unsigned _rc_min_value;
175  unsigned _rc_max_value;
179 
180  static int task_main_trampoline(int argc, char *argv[]);
181  int task_main();
182 
183  static int control_callback(uintptr_t handle,
184  uint8_t control_group,
185  uint8_t control_index,
186  float &input);
187 
188  int pwm_ioctl(file *filp, int cmd, unsigned long arg);
189  int mk_servo_arm(bool status);
190  int mk_servo_set(unsigned int chan, short val);
191  int mk_servo_test(unsigned int chan);
192  int mk_servo_locate();
193  short scaling(float val, float inMin, float inMax, float outMin, float outMax);
194  void play_beep(int count);
195 
196 };
197 
198 
199 
200 
201 const int blctrlAddr_quad_plus[] = { 2, 2, -2, -2, 0, 0, 0, 0 }; // Addresstranslator for Quad + configuration
202 const int blctrlAddr_hexa_plus[] = { 0, 2, 2, -2, 1, -3, 0, 0 }; // Addresstranslator for Hexa + configuration
203 const int blctrlAddr_octo_plus[] = { 0, 3, -1, 0, 3, 0, 0, -5 }; // Addresstranslator for Octo + configuration
204 
205 const int blctrlAddr_quad_x[] = { 2, 2, -2, -2, 0, 0, 0, 0 }; // Addresstranslator for Quad X configuration
206 const int blctrlAddr_hexa_x[] = { 2, 4, -2, 0, -3, -1, 0, 0 }; // Addresstranslator for Hexa X configuration
207 const int blctrlAddr_octo_x[] = { 1, 4, 0, 1, -4, 1, 1, -4 }; // Addresstranslator for Octo X configuration
208 
209 const int blctrlAddr_px4[] = { 0, 0, 0, 0, 0, 0, 0, 0}; // Native PX4 order - nothing to translate
210 
211 int addrTranslator[] = {0, 0, 0, 0, 0, 0, 0, 0}; // work copy
212 
213 namespace
214 {
215 
216 MK *g_mk;
217 
218 } // namespace
219 
220 MK::MK(int bus, const char *_device_path) :
221  I2C("mkblctrl", "/dev/mkblctrl0", bus, 0, I2C_BUS_SPEED),
222  _update_rate(UPDATE_RATE),
223  _task(-1),
224  _t_actuators(-1),
225  _t_actuator_armed(-1),
226  _motor(-1),
227  _px4mode(MAPPING_MK),
228  _frametype(FRAME_PLUS),
229  _t_outputs(0),
230  _t_esc_status(0),
231  _num_outputs(0),
232  _primary_pwm_device(false),
233  _motortest(false),
234  _overrideSecurityChecks(false),
235  _task_should_exit(false),
236  _armed(false),
237  _mixers(nullptr),
238  _indicate_esc(false),
239  _rc_min_value(RC_MIN_VALUE),
240  _rc_max_value(RC_MAX_VALUE)
241 {
242  strncpy(_device, _device_path, sizeof(_device));
243  /* enforce null termination */
244  _device[sizeof(_device) - 1] = '\0';
245 }
246 
248 {
249  if (_task != -1) {
250  /* tell the task we want it to go away */
251  _task_should_exit = true;
252 
253  unsigned i = 10;
254 
255  do {
256  /* wait 50ms - it should wake every 100ms or so worst-case */
257  usleep(50000);
258 
259  /* if we have given up, kill it */
260  if (--i == 0) {
261  task_delete(_task);
262  break;
263  }
264 
265  } while (_task != -1);
266  }
267 
268  /* clean up the alternate device node */
269  if (_primary_pwm_device) {
271  }
272 
273  g_mk = nullptr;
274 }
275 
276 int
277 MK::init(unsigned motors)
278 {
279  _param_indicate_esc = param_find("MKBLCTRL_TEST");
280 
281  _num_outputs = motors;
282  debugCounter = 0;
283  int ret;
284  ASSERT(_task == -1);
285 
286  ret = I2C::init();
287 
288  if (ret != OK) {
289  warnx("I2C init failed");
290  return ret;
291  }
292 
293  usleep(500000);
294 
295  if (sizeof(_device) > 0) {
296  ret = register_driver(_device, &fops, 0666, (void *)this);
297 
298  if (ret == OK) {
299  DEVICE_LOG("creating alternate output device");
300  _primary_pwm_device = true;
301  }
302 
303  }
304 
305  /* start the IO interface task */
306  _task = px4_task_spawn_cmd("mkblctrl",
307  SCHED_DEFAULT,
308  SCHED_PRIORITY_MAX - 20,
309  1500,
310  (main_t)&MK::task_main_trampoline,
311  nullptr);
312 
313 
314  if (_task < 0) {
315  DEVICE_DEBUG("task start failed: %d", errno);
316  return -errno;
317  }
318 
319  return OK;
320 }
321 
322 int
323 MK::task_main_trampoline(int argc, char *argv[])
324 {
325  return g_mk->task_main();
326 }
327 
328 void
329 MK::set_px4mode(int px4mode)
330 {
331  _px4mode = px4mode;
332 }
333 
334 void
335 MK::set_frametype(int frametype)
336 {
337  _frametype = frametype;
338 }
339 
340 void
341 MK::set_rc_min_value(unsigned value)
342 {
343  _rc_min_value = value;
344  PX4_INFO("rc_min = %i", _rc_min_value);
345 }
346 
347 void
348 MK::set_rc_max_value(unsigned value)
349 {
350  _rc_max_value = value;
351  PX4_INFO("rc_max = %i", _rc_max_value);
352 }
353 
354 int
355 MK::set_motor_count(unsigned count)
356 {
357  if (count > 0) {
358 
359  _num_outputs = count;
360 
361  if (_px4mode == MAPPING_MK) {
362  if (_frametype == FRAME_PLUS) {
363  PX4_INFO("Mikrokopter ESC addressing. Frame: +");
364 
365  } else if (_frametype == FRAME_X) {
366  PX4_INFO("Mikrokopter ESC addressing. Frame: X");
367  }
368 
369  if (_num_outputs == 4) {
370  if (_frametype == FRAME_PLUS) {
372 
373  } else if (_frametype == FRAME_X) {
375  }
376 
377  } else if (_num_outputs == 6) {
378  if (_frametype == FRAME_PLUS) {
380 
381  } else if (_frametype == FRAME_X) {
383  }
384 
385  } else if (_num_outputs == 8) {
386  if (_frametype == FRAME_PLUS) {
388 
389  } else if (_frametype == FRAME_X) {
391  }
392  }
393 
394  } else {
395  PX4_INFO("PX4 ESC addressing.");
396  memcpy(&addrTranslator, &blctrlAddr_px4, sizeof(blctrlAddr_px4));
397  }
398 
399  if (_num_outputs == 4) {
400  PX4_INFO("4 ESCs = Quadrocopter");
401 
402  } else if (_num_outputs == 6) {
403  PX4_INFO("6 ESCs = Hexacopter");
404 
405  } else if (_num_outputs == 8) {
406  PX4_INFO("8 ESCs = Octocopter");
407  }
408 
409  return OK;
410 
411  } else {
412  return -1;
413  }
414 
415 }
416 
417 int
418 MK::set_motor_test(bool motortest)
419 {
420  _motortest = motortest;
421  return OK;
422 }
423 
424 int
425 MK::set_overrideSecurityChecks(bool overrideSecurityChecks)
426 {
427  _overrideSecurityChecks = overrideSecurityChecks;
428  return OK;
429 }
430 
431 short
432 MK::scaling(float val, float inMin, float inMax, float outMin, float outMax)
433 {
434  short retVal = 0;
435 
436  retVal = (val - inMin) / (inMax - inMin) * (outMax - outMin) + outMin;
437 
438  if (retVal < outMin) {
439  retVal = outMin;
440 
441  } else if (retVal > outMax) {
442  retVal = outMax;
443  }
444 
445  return retVal;
446 }
447 
448 void
449 MK::play_beep(int count)
450 {
451  tune_control_s tune = {};
452  tune.tune_id = static_cast<int>(TuneID::SINGLE_BEEP);
453 
454  for (int i = 0; i < count; i++) {
456  usleep(300000);
457  }
458 
459 }
460 
461 int
463 {
464  int32_t param_mkblctrl_test = 0;
465  /*
466  * Subscribe to the appropriate PWM output topic based on whether we are the
467  * primary PWM output or not.
468  */
469  _t_actuators = orb_subscribe(ORB_ID(actuator_controls_0));
470  orb_set_interval(_t_actuators, int(1000 / _update_rate)); /* set the topic update rate (200Hz)*/
471 
472  /*
473  * Subscribe to actuator_armed topic.
474  */
475  _t_actuator_armed = orb_subscribe(ORB_ID(actuator_armed));
476  orb_set_interval(_t_actuator_armed, 200); /* 5Hz update rate */
477 
478  /*
479  * advertise the mixed control outputs.
480  */
481  actuator_outputs_s outputs;
482  memset(&outputs, 0, sizeof(outputs));
483  int dummy;
484  _t_outputs = orb_advertise_multi(ORB_ID(actuator_outputs),
485  &outputs, &dummy, ORB_PRIO_HIGH);
486 
487  /*
488  * advertise the blctrl status.
489  */
491  memset(&esc, 0, sizeof(esc));
492  _t_esc_status = orb_advertise(ORB_ID(esc_status), &esc);
493 
494  /*
495  * advertise the tune_control.
496  */
497  tune_control_s tune = {};
498  _tune_control_sub = orb_advertise_queue(ORB_ID(tune_control), &tune, tune_control_s::ORB_QUEUE_LENGTH);
499 
500  pollfd fds[2];
501  fds[0].fd = _t_actuators;
502  fds[0].events = POLLIN;
503  fds[1].fd = _t_actuator_armed;
504  fds[1].events = POLLIN;
505 
506  up_pwm_servo_set_rate(_update_rate); /* unnecessary ? */
507 
508  DEVICE_LOG("starting");
509 
510  /* loop until killed */
511  while (!_task_should_exit) {
512 
513  param_get(_param_indicate_esc, &param_mkblctrl_test);
514 
515  if (param_mkblctrl_test > 0) {
516  _indicate_esc = true;
517 
518  } else {
519  _indicate_esc = false;
520  }
521 
522  /* waiting for data */
523  int ret = ::poll(&fds[0], 2, CONTROL_INPUT_DROP_LIMIT_MS);
524 
525  /* this would be bad... */
526  if (ret < 0) {
527  DEVICE_LOG("poll error %d", errno);
528  usleep(1000000);
529  continue;
530  }
531 
532  /* do we have a control update? */
533  if (fds[0].revents & POLLIN) {
534 
535  bool changed = false;
536  orb_check(_t_actuators, &changed);
537 
538  if (changed) {
539 
540  /* get controls - must always do this to avoid spinning */
542 
543  /* can we mix? */
544  if (_mixers != nullptr) {
545 
546  /* do mixing */
547  outputs.noutputs = _mixers->mix(&outputs.output[0], _num_outputs);
548  outputs.timestamp = hrt_absolute_time();
549 
550  /* iterate actuators */
551  for (unsigned int i = 0; i < _num_outputs; i++) {
552  /* last resort: catch NaN, INF and out-of-band errors */
553  if (i < outputs.noutputs &&
554  PX4_ISFINITE(outputs.output[i]) &&
555  outputs.output[i] >= -1.0f &&
556  outputs.output[i] <= 1.0f) {
557  /* scale for PWM output 900 - 2100us */
558  /* nothing to do here */
559  } else {
560  /*
561  * Value is NaN, INF or out of band - set to the minimum value.
562  * This will be clearly visible on the servo status and will limit the risk of accidentally
563  * spinning motors. It would be deadly in flight.
564  */
565  if (outputs.output[i] < -1.0f) {
566  outputs.output[i] = -1.0f;
567 
568  } else if (outputs.output[i] > 1.0f) {
569  outputs.output[i] = 1.0f;
570 
571  } else {
572  outputs.output[i] = -1.0f;
573  }
574  }
575 
577  /* don't go under BLCTRL_MIN_VALUE */
578  if (outputs.output[i] < BLCTRL_MIN_VALUE) {
579  outputs.output[i] = BLCTRL_MIN_VALUE;
580  }
581  }
582 
583  /* output to BLCtrl's */
584  if (_motortest != true && _indicate_esc != true) {
585  Motor[i].SetPoint_PX4 = outputs.output[i];
586  mk_servo_set(i, scaling(outputs.output[i], -1.0f, 1.0f, 0,
587  2047)); // scale the output to 0 - 2047 and sent to output routine
588  }
589  }
590  }
591  }
592  }
593 
594  /* how about an arming update? */
595  if (fds[1].revents & POLLIN) {
596  actuator_armed_s aa;
597 
598  /* get new value */
599  orb_copy(ORB_ID(actuator_armed), _t_actuator_armed, &aa);
600 
601  /* update PWM servo armed status if armed and not locked down */
602  mk_servo_arm(aa.armed && !aa.lockdown);
603  }
604 
605  /*
606  * Only update esc topic every half second.
607  */
608 
610  esc.counter++;
612  esc.esc_count = (uint8_t) _num_outputs;
613  esc.esc_connectiontype = esc_status_s::ESC_CONNECTION_TYPE_I2C;
614 
615  for (unsigned int i = 0; i < _num_outputs; i++) {
616  esc.esc[i].esc_address = (uint8_t) BLCTRL_BASE_ADDR + i;
617  esc.esc[i].esc_voltage = 0.0F;
618  esc.esc[i].esc_current = static_cast<float>(Motor[i].Current) * 0.1F;
619  esc.esc[i].esc_rpm = (uint16_t) 0;
620 
621  esc.esc[i].esc_temperature = static_cast<uint8_t>(Motor[i].Temperature);
622  esc.esc[i].esc_state = (uint8_t) Motor[i].State;
623  esc.esc[i].esc_errorcount = (uint16_t) 0;
624 
625  // if motortest is requested - do it... (deprecated in future)
626  if (_motortest == true) {
627  mk_servo_test(i);
628  }
629 
630  // if esc locate is requested
631  if (_indicate_esc == true) {
632  mk_servo_locate();
633  }
634  }
635 
636  orb_publish(ORB_ID(esc_status), _t_esc_status, &esc);
637 
638  }
639 
640  }
641 
642  ::close(_t_actuators);
643  ::close(_t_actuator_armed);
644 
645 
646  /* make sure servos are off */
648 
649  DEVICE_LOG("stopping");
650 
651  /* note - someone else is responsible for restoring the GPIO config */
652 
653  /* tell the dtor that we are exiting */
654  _task = -1;
655  return 0;
656 }
657 
658 
659 int
661 {
662  _armed = status;
663  return 0;
664 }
665 
666 
667 unsigned int
668 MK::mk_check_for_blctrl(unsigned int count, bool showOutput, bool initI2C)
669 {
670  if (initI2C) {
671  I2C::init();
672  }
673 
674  _retries = 50;
675  uint8_t foundMotorCount = 0;
676 
677  for (unsigned i = 0; i < MAX_MOTORS; i++) {
678  Motor[i].Version = 0;
679  Motor[i].SetPoint = 0;
680  Motor[i].SetPointLowerBits = 0;
681  Motor[i].State = 0;
682  Motor[i].ReadMode = 0;
683  Motor[i].RawPwmValue = 0;
684  Motor[i].Current = 0;
685  Motor[i].MaxPWM = 0;
686  Motor[i].Temperature = 0;
687  Motor[i].RoundCount = 0;
688  }
689 
690  uint8_t msg = 0;
691  uint8_t result[3];
692 
693  for (unsigned i = 0; i < count; i++) {
694  result[0] = 0;
695  result[1] = 0;
696  result[2] = 0;
697 
698  set_device_address(BLCTRL_BASE_ADDR + i);
699 
700  if (OK == transfer(&msg, 1, &result[0], 3)) {
701  Motor[i].Current = result[0];
702  Motor[i].MaxPWM = result[1];
703  Motor[i].Temperature = result[2];
704  Motor[i].State |= MOTOR_STATE_PRESENT_MASK; // set present bit;
705  foundMotorCount++;
706 
707  if ((Motor[i].MaxPWM & 252) == 248) {
708  Motor[i].Version = BLCTRL_NEW;
709 
710  } else {
711  Motor[i].Version = BLCTRL_OLD;
712  }
713  }
714  }
715 
716  if (showOutput) {
717  PX4_INFO("MotorsFound: %i", foundMotorCount);
718 
719  for (unsigned i = 0; i < foundMotorCount; i++) {
720  PX4_INFO("blctrl[%i] : found=%i\tversion=%i\tcurrent=%i\tmaxpwm=%i\ttemperature=%i", i,
721  Motor[i].State, Motor[i].Version, Motor[i].Current, Motor[i].MaxPWM, Motor[i].Temperature);
722  }
723 
724 
726  if (foundMotorCount != 4 && foundMotorCount != 6 && foundMotorCount != 8) {
727  _task_should_exit = true;
728  }
729  }
730  }
731 
732  return foundMotorCount;
733 }
734 
735 int
736 MK::mk_servo_set(unsigned int chan, short val)
737 {
738  short tmpVal = 0;
739  _retries = 0;
740  uint8_t result[3] = { 0, 0, 0 };
741  uint8_t msg[2] = { 0, 0 };
742  uint8_t bytesToSendBL2 = 2;
743 
744  tmpVal = val;
745 
746  if (tmpVal > 2047) {
747  tmpVal = 2047;
748 
749  } else if (tmpVal < 0) {
750  tmpVal = 0;
751  }
752 
753  Motor[chan].SetPoint = (uint8_t)(tmpVal >> 3) & 0xff;
754  Motor[chan].SetPointLowerBits = ((uint8_t)tmpVal % 8) & 0x07;
755 
756  if (_armed == false) {
757  Motor[chan].SetPoint = 0;
758  Motor[chan].SetPointLowerBits = 0;
759  }
760 
761  //if(Motor[chan].State & MOTOR_STATE_PRESENT_MASK) {
762  set_device_address(BLCTRL_BASE_ADDR + (chan + addrTranslator[chan]));
763 
764  if (Motor[chan].Version == BLCTRL_OLD) {
765  /*
766  * Old BL-Ctrl 8Bit served. Version < 2.0
767  */
768  msg[0] = Motor[chan].SetPoint;
769 
770  if (Motor[chan].RoundCount >= 16) {
771  // on each 16th cyle we read out the status messages from the blctrl
772  if (OK == transfer(&msg[0], 1, &result[0], 2)) {
773  Motor[chan].Current = result[0];
774  Motor[chan].MaxPWM = result[1];
775  Motor[chan].Temperature = 255;
776 
777  } else {
778  if ((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) { Motor[chan].State++; } // error
779  }
780 
781  Motor[chan].RoundCount = 0;
782 
783  } else {
784  if (OK != transfer(&msg[0], 1, nullptr, 0)) {
785  if ((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) { Motor[chan].State++; } // error
786  }
787  }
788 
789  } else {
790  /*
791  * New BL-Ctrl 11Bit served. Version >= 2.0
792  */
793  msg[0] = Motor[chan].SetPoint;
794  msg[1] = Motor[chan].SetPointLowerBits;
795 
796  if (Motor[chan].SetPointLowerBits == 0) {
797  bytesToSendBL2 = 1; // if setpoint lower bits are zero, we send only the higher bits - this saves time
798  }
799 
800  if (Motor[chan].RoundCount >= 16) {
801  // on each 16th cyle we read out the status messages from the blctrl
802  if (OK == transfer(&msg[0], bytesToSendBL2, &result[0], 3)) {
803  Motor[chan].Current = result[0];
804  Motor[chan].MaxPWM = result[1];
805  Motor[chan].Temperature = result[2];
806 
807  } else {
808  if ((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) { Motor[chan].State++; } // error
809  }
810 
811  Motor[chan].RoundCount = 0;
812 
813  } else {
814  if (OK != transfer(&msg[0], bytesToSendBL2, nullptr, 0)) {
815  if ((Motor[chan].State & MOTOR_STATE_ERROR_MASK) < MOTOR_STATE_ERROR_MASK) { Motor[chan].State++; } // error
816  }
817  }
818 
819  }
820 
821  Motor[chan].RoundCount++;
822  //}
823 
824  if (showDebug == true) {
825  debugCounter++;
826 
827  if (debugCounter == 2000) {
828  debugCounter = 0;
829 
830  for (unsigned int i = 0; i < _num_outputs; i++) {
832  PX4_INFO("#%i:\tVer: %i\tVal: %i\tCurr: %i\tMaxPWM: %i\tTemp: %i\tState: %i", i, Motor[i].Version,
833  Motor[i].SetPoint, Motor[i].Current, Motor[i].MaxPWM, Motor[i].Temperature, Motor[i].State);
834  }
835  }
836 
837  PX4_INFO("\n");
838  }
839  }
840 
841  return 0;
842 }
843 
844 
845 int
846 MK::mk_servo_test(unsigned int chan)
847 {
848  int ret = 0;
849  float tmpVal = 0;
850  float val = -1;
851  _retries = 0;
852  uint8_t msg[2] = { 0, 0 };
853 
855  debugCounter = 0;
856  _motor++;
857 
858  if (_motor < _num_outputs) {
859  PX4_INFO("Motortest - #%i:\tspinup", _motor);
860  }
861 
862  if (_motor >= _num_outputs) {
863  _motor = -1;
864  _motortest = false;
865  PX4_INFO("Motortest finished...");
866  }
867  }
868 
869  debugCounter++;
870 
871  if (_motor == chan) {
872  val = BLCTRL_MIN_VALUE;
873 
874  } else {
875  val = -1;
876  }
877 
878  tmpVal = (511 + (511 * val));
879 
880  if (tmpVal > 1024) {
881  tmpVal = 1024;
882  }
883 
884  Motor[chan].SetPoint = (uint8_t)(tmpVal / 4);
885 
886  if (_motor != chan) {
887  Motor[chan].SetPoint = 0;
888  Motor[chan].SetPointLowerBits = 0;
889  }
890 
891  if (Motor[chan].Version == BLCTRL_OLD) {
892  msg[0] = Motor[chan].SetPoint;
893 
894  } else {
895  msg[0] = Motor[chan].SetPoint;
896  msg[1] = Motor[chan].SetPointLowerBits;
897  }
898 
899  set_device_address(BLCTRL_BASE_ADDR + (chan + addrTranslator[chan]));
900 
901  if (Motor[chan].Version == BLCTRL_OLD) {
902  ret = transfer(&msg[0], 1, nullptr, 0);
903 
904  } else {
905  ret = transfer(&msg[0], 2, nullptr, 0);
906  }
907 
908  return ret;
909 }
910 
911 
912 int
914 {
915  int ret = 0;
916  static unsigned int chan = 0;
917  static uint64_t last_timestamp = 0;
918  _retries = 0;
919  uint8_t msg[2] = { 0, 0 };
920 
921 
922  if (hrt_absolute_time() - last_timestamp > MOTOR_LOCATE_DELAY) {
923  last_timestamp = hrt_absolute_time();
924 
925  set_device_address(BLCTRL_BASE_ADDR + (chan + addrTranslator[chan]));
926  chan++;
927 
928  if (chan <= _num_outputs) {
929  PX4_INFO("ESC Locate - #%i:\tgreen", chan);
930  play_beep(chan);
931  }
932 
933  if (chan > _num_outputs) {
934  chan = 0;
935  }
936  }
937 
938  // do i2c transfer to selected esc
939  ret = transfer(&msg[0], 1, nullptr, 0);
940 
941  return ret;
942 }
943 
944 
945 int
946 MK::control_callback(uintptr_t handle,
947  uint8_t control_group,
948  uint8_t control_index,
949  float &input)
950 {
951  const actuator_controls_s *controls = (actuator_controls_s *)handle;
952 
953  input = controls->control[control_index];
954  return 0;
955 }
956 
957 int
958 MK::ioctl(file *filp, int cmd, unsigned long arg)
959 {
960  int ret;
961 
962  ret = pwm_ioctl(filp, cmd, arg);
963 
964  /* if nobody wants it, let CDev have it */
965  if (ret == -ENOTTY) {
966  ret = CDev::ioctl(filp, cmd, arg);
967  }
968 
969  return ret;
970 }
971 
972 int
973 MK::pwm_ioctl(file *filp, int cmd, unsigned long arg)
974 {
975  int ret = OK;
976 
977  lock();
978 
979  switch (cmd) {
980  case PWM_SERVO_ARM:
981  mk_servo_arm(true);
982  break;
983 
986  // these are no-ops, as no safety switch
987  break;
988 
989  case PWM_SERVO_DISARM:
990  mk_servo_arm(false);
991  break;
992 
994  ret = OK;
995  break;
996 
998  *(uint32_t *)arg = _update_rate;
999  break;
1000 
1002  ret = OK;
1003  break;
1004 
1005 
1006  case PWM_SERVO_SET(0) ... PWM_SERVO_SET(_max_actuators - 1):
1007  if (arg < 2150) {
1008  Motor[cmd - PWM_SERVO_SET(0)].RawPwmValue = (unsigned short)arg;
1009  mk_servo_set(cmd - PWM_SERVO_SET(0), scaling(arg, _rc_min_value, _rc_max_value, 0, 2047));
1010 
1011  } else {
1012  ret = -EINVAL;
1013  }
1014 
1015  break;
1016 
1017  case PWM_SERVO_GET(0) ... PWM_SERVO_GET(_max_actuators - 1):
1018  /* copy the current output value from the channel */
1019  *(servo_position_t *)arg = Motor[cmd - PWM_SERVO_GET(0)].RawPwmValue;
1020 
1021  break;
1022 
1023  case PWM_SERVO_GET_RATEGROUP(0):
1024  case PWM_SERVO_GET_RATEGROUP(1):
1025  case PWM_SERVO_GET_RATEGROUP(2):
1026  case PWM_SERVO_GET_RATEGROUP(3):
1027  //*(uint32_t *)arg = up_pwm_servo_get_rate_group(cmd - PWM_SERVO_GET_RATEGROUP(0));
1028  break;
1029 
1030  case PWM_SERVO_GET_COUNT:
1031  *(unsigned *)arg = _num_outputs;
1032  break;
1033 
1034  case MIXERIOCRESET:
1035  if (_mixers != nullptr) {
1036  delete _mixers;
1037  _mixers = nullptr;
1038  }
1039 
1040  break;
1041 
1042  case MIXERIOCLOADBUF: {
1043  const char *buf = (const char *)arg;
1044  unsigned buflen = strlen(buf);
1045 
1046  if (_mixers == nullptr) {
1047  _mixers = new MixerGroup();
1048  }
1049 
1050  if (_mixers == nullptr) {
1051  ret = -ENOMEM;
1052 
1053  } else {
1054 
1055  ret = _mixers->load_from_buf(control_callback, (uintptr_t)&_controls, buf, buflen);
1056 
1057  if (ret != 0) {
1058  DEVICE_DEBUG("mixer load failed with %d", ret);
1059  delete _mixers;
1060  _mixers = nullptr;
1061  ret = -EINVAL;
1062  }
1063  }
1064 
1065  break;
1066  }
1067 
1068  case PWM_SERVO_SET_MIN_PWM: {
1069  struct pwm_output_values *pwm = (struct pwm_output_values *)arg;
1070 
1071  if (pwm->channel_count > _max_actuators)
1072  /* fail with error */
1073  {
1074  return -E2BIG;
1075  }
1076 
1077  set_rc_min_value((unsigned)pwm->values[0]);
1078  ret = OK;
1079  break;
1080  }
1081 
1082  case PWM_SERVO_GET_MIN_PWM:
1083  ret = OK;
1084  break;
1085 
1086  case PWM_SERVO_SET_MAX_PWM: {
1087  struct pwm_output_values *pwm = (struct pwm_output_values *)arg;
1088 
1089  if (pwm->channel_count > _max_actuators)
1090  /* fail with error */
1091  {
1092  return -E2BIG;
1093  }
1094 
1095  set_rc_max_value((unsigned)pwm->values[0]);
1096  ret = OK;
1097  break;
1098  }
1099 
1100  case PWM_SERVO_GET_MAX_PWM:
1101  ret = OK;
1102  break;
1103 
1104 
1105  default:
1106  ret = -ENOTTY;
1107  break;
1108  }
1109 
1110  unlock();
1111 
1112  return ret;
1113 }
1114 
1115 /*
1116  this implements PWM output via a write() method, for compatibility
1117  with px4io
1118  */
1119 ssize_t
1120 MK::write(file *filp, const char *buffer, size_t len)
1121 {
1122  unsigned count = len / 2;
1123  uint16_t values[8];
1124 
1125  if (count > _num_outputs) {
1126  // we only have 8 I2C outputs in the driver
1127  count = _num_outputs;
1128  }
1129 
1130  // allow for misaligned values
1131  memcpy(values, buffer, count * 2);
1132 
1133  for (uint8_t i = 0; i < count; i++) {
1134  Motor[i].RawPwmValue = (unsigned short)values[i];
1135  mk_servo_set(i, scaling(values[i], _rc_min_value, _rc_max_value, 0, 2047));
1136  }
1137 
1138  return count * 2;
1139 }
1140 
1141 
1142 namespace
1143 {
1144 
1146  MAPPING_MK = 0,
1147  MAPPING_PX4,
1148 };
1149 
1151  FRAME_PLUS = 0,
1152  FRAME_X,
1153 };
1154 
1155 
1156 int
1157 mk_new_mode(int motorcount, bool motortest, int px4mode, int frametype, bool overrideSecurityChecks, unsigned rcmin,
1158  unsigned rcmax)
1159 {
1160  int shouldStop = 0;
1161 
1162  /* set rc min pulse value */
1163  g_mk->set_rc_min_value(rcmin);
1164 
1165  /* set rc max pulse value */
1166  g_mk->set_rc_max_value(rcmax);
1167 
1168  /* native PX4 addressing) */
1169  g_mk->set_px4mode(px4mode);
1170 
1171  /* set frametype (geometry) */
1172  g_mk->set_frametype(frametype);
1173 
1174  /* motortest if enabled */
1175  g_mk->set_motor_test(motortest);
1176 
1177  /* ovveride security checks if enabled */
1178  g_mk->set_overrideSecurityChecks(overrideSecurityChecks);
1179 
1180  /* count used motors */
1181  do {
1182  if (g_mk->mk_check_for_blctrl(8, false, false) != 0) {
1183  shouldStop = 4;
1184 
1185  } else {
1186  shouldStop++;
1187  }
1188 
1189  sleep(1);
1190  } while (shouldStop < 3);
1191 
1192  g_mk->set_motor_count(g_mk->mk_check_for_blctrl(8, true, false));
1193 
1194  return OK;
1195 }
1196 
1197 int
1198 mk_start(unsigned motors, const char *device_path)
1199 {
1200  int ret;
1201 
1202  // try i2c3 first
1203  g_mk = new MK(3, device_path);
1204 
1205  if (!g_mk) {
1206  return -ENOMEM;
1207  }
1208 
1209  if (OK == g_mk->init(motors)) {
1210  warnx("[mkblctrl] scanning i2c3...\n");
1211  ret = g_mk->mk_check_for_blctrl(8, false, false);
1212 
1213  if (ret > 0) {
1214  return OK;
1215  }
1216  }
1217 
1218  delete g_mk;
1219  g_mk = nullptr;
1220 
1221  // fallback to bus 1
1222  g_mk = new MK(1, device_path);
1223 
1224  if (!g_mk) {
1225  return -ENOMEM;
1226  }
1227 
1228  if (OK == g_mk->init(motors)) {
1229  warnx("[mkblctrl] scanning i2c1...\n");
1230  ret = g_mk->mk_check_for_blctrl(8, false, false);
1231 
1232  if (ret > 0) {
1233  return OK;
1234  }
1235  }
1236 
1237  delete g_mk;
1238  g_mk = nullptr;
1239 
1240  return -ENXIO;
1241 }
1242 
1243 
1244 } // namespace
1245 
1246 extern "C" __EXPORT int mkblctrl_main(int argc, char *argv[]);
1247 
1248 int
1249 mkblctrl_main(int argc, char *argv[])
1250 {
1251  int motorcount = 8;
1252  int px4mode = MAPPING_PX4;
1253  int frametype = FRAME_PLUS; // + plus is default
1254  bool motortest = false;
1255  bool overrideSecurityChecks = false;
1256  bool showHelp = false;
1257  bool newMode = true;
1258  const char *devicepath = "";
1259  unsigned rc_min_value = RC_MIN_VALUE;
1260  unsigned rc_max_value = RC_MAX_VALUE;
1261  char *ep;
1262 
1263  /*
1264  * optional parameters
1265  */
1266  for (int i = 1; i < argc; i++) {
1267 
1268  /* look for the optional frame parameter */
1269  if (strcmp(argv[i], "-mkmode") == 0 || strcmp(argv[i], "--mkmode") == 0) {
1270  if (argc > i + 1) {
1271  if (strcmp(argv[i + 1], "+") == 0 || strcmp(argv[i + 1], "x") == 0 || strcmp(argv[i + 1], "X") == 0) {
1272  px4mode = MAPPING_MK;
1273  //newMode = true;
1274 
1275  if (strcmp(argv[i + 1], "+") == 0) {
1276  frametype = FRAME_PLUS;
1277 
1278  } else {
1279  frametype = FRAME_X;
1280  }
1281 
1282  } else {
1283  errx(1, "only + or x for frametype supported !");
1284  }
1285 
1286  } else {
1287  errx(1, "missing argument for mkmode (-mkmode)");
1288  return 1;
1289  }
1290  }
1291 
1292  /* look for the optional test parameter */
1293  if (strcmp(argv[i], "-t") == 0) {
1294  motortest = true;
1295  //newMode = true;
1296  }
1297 
1298  /* look for the optional -h --help parameter */
1299  if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
1300  showHelp = true;
1301  }
1302 
1303  /* look for the optional --override-security-checks parameter */
1304  if (strcmp(argv[i], "--override-security-checks") == 0) {
1305  overrideSecurityChecks = true;
1306  //newMode = true;
1307  }
1308 
1309  /* look for the optional device parameter */
1310  if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--device") == 0) {
1311  if (argc > i + 1) {
1312  devicepath = argv[i + 1];
1313  //newMode = true;
1314 
1315  } else {
1316  errx(1, "missing the devicename (-d)");
1317  return 1;
1318  }
1319  }
1320 
1321  /* look for the optional -rc_min parameter */
1322  if (strcmp(argv[i], "-rc_min") == 0) {
1323  if (argc > i + 1) {
1324  rc_min_value = strtoul(argv[i + 1], &ep, 0);
1325 
1326  if (*ep != '\0') {
1327  errx(1, "bad pwm val (-rc_min)");
1328  return 1;
1329  }
1330 
1331  } else {
1332  errx(1, "missing value (-rc_min)");
1333  return 1;
1334  }
1335  }
1336 
1337  /* look for the optional -rc_max parameter */
1338  if (strcmp(argv[i], "-rc_max") == 0) {
1339  if (argc > i + 1) {
1340  rc_max_value = strtoul(argv[i + 1], &ep, 0);
1341 
1342  if (*ep != '\0') {
1343  errx(1, "bad pwm val (-rc_max)");
1344  return 1;
1345  }
1346 
1347  } else {
1348  errx(1, "missing value (-rc_max)");
1349  return 1;
1350  }
1351  }
1352 
1353 
1354  }
1355 
1356  if (showHelp) {
1357  PX4_INFO("mkblctrl: help:");
1358  PX4_INFO(" [-mkmode {+/x}] [-b i2c_bus_number] [-d devicename] [--override-security-checks] [-h / --help]");
1359  PX4_INFO("\t -mkmode {+/x} \t\t Type of frame, if Mikrokopter motor order is used.");
1360  PX4_INFO("\t -d {devicepath & name}\t\t Create alternate pwm device.");
1361  PX4_INFO("\t --override-security-checks \t\t Disable all security checks (arming and number of ESCs). Used to test single Motors etc. (DANGER !!!)");
1362  PX4_INFO("\t -rcmin {pwn-value}\t\t Set RC_MIN Value.");
1363  PX4_INFO("\t -rcmax {pwn-value}\t\t Set RC_MAX Value.");
1364  PX4_INFO("\n");
1365  PX4_INFO("Motortest:");
1366  PX4_INFO("First you have to start mkblctrl, the you can enter Motortest Mode with:");
1367  PX4_INFO("mkblctrl -t");
1368  PX4_INFO("This will spin up once every motor in order of motoraddress. (DANGER !!!)");
1369  exit(1);
1370  }
1371 
1372 
1373  if (!motortest) {
1374  if (g_mk == nullptr) {
1375  if (mk_start(motorcount, devicepath) != OK) {
1376  errx(1, "failed to start the MK-BLCtrl driver");
1377  }
1378 
1379  /* parameter set ? */
1380  if (newMode) {
1381  /* switch parameter */
1382  return mk_new_mode(motorcount, motortest, px4mode, frametype, overrideSecurityChecks, rc_min_value, rc_max_value);
1383  }
1384 
1385  exit(0);
1386 
1387  } else {
1388  errx(1, "MK-BLCtrl driver already running");
1389  }
1390 
1391  } else {
1392  if (g_mk == nullptr) {
1393  errx(1, "MK-BLCtrl driver not running. You have to start it first.");
1394 
1395  } else {
1396  g_mk->set_motor_test(motortest);
1397  exit(0);
1398 
1399  }
1400  }
1401 }
#define RC_MIN_VALUE
Definition: mkblctrl.cpp:99
int load_from_buf(Mixer::ControlCallback control_cb, uintptr_t cb_handle, const char *buf, unsigned &buflen)
Adds mixers to the group based on a text description in a buffer.
Definition: MixerGroup.cpp:173
struct esc_report_s esc[8]
Definition: esc_status.h:67
const int blctrlAddr_quad_plus[]
Definition: mkblctrl.cpp:201
#define CONTROL_INPUT_DROP_LIMIT_MS
Definition: mkblctrl.cpp:98
int orb_copy(const struct orb_metadata *meta, int handle, void *buffer)
Definition: uORB.cpp:90
#define MIXERIOCLOADBUF
Add mixer(s) from the buffer in (const char *)arg.
Definition: drv_mixer.h:79
#define PWM_SERVO_SET_ARM_OK
set the &#39;ARM ok&#39; bit, which activates the safety switch
const int blctrlAddr_quad_x[]
Definition: mkblctrl.cpp:205
actuator_controls_s _controls
Definition: mkblctrl.cpp:177
R/C input interface.
virtual ssize_t write(file *filp, const char *buffer, size_t len)
Definition: mkblctrl.cpp:1120
#define BLCTRL_OLD
Definition: mkblctrl.cpp:89
static struct vehicle_status_s status
Definition: Commander.cpp:138
uint16_t servo_position_t
Servo output signal type, value is actual servo output pulse width in microseconds.
orb_advert_t _t_esc_status
Definition: mkblctrl.cpp:163
void set_rc_max_value(unsigned value)
Definition: mkblctrl.cpp:348
volatile bool _task_should_exit
Definition: mkblctrl.cpp:169
unsigned int _motor
Definition: mkblctrl.cpp:158
__EXPORT int param_get(param_t param, void *val)
Copy the value of a parameter.
Definition: parameters.cpp:589
#define PWM_SERVO_GET_COUNT
get the number of servos in *(unsigned *)arg
const int blctrlAddr_octo_plus[]
Definition: mkblctrl.cpp:203
#define PWM_SERVO_ARM
arm all servo outputs handle by this driver
unsigned int MaxPWM
Definition: mkblctrl.cpp:113
#define MOTOR_STATE_PRESENT_MASK
Definition: mkblctrl.cpp:92
static const unsigned _max_actuators
Definition: mkblctrl.cpp:151
int _frametype
Definition: mkblctrl.cpp:160
__EXPORT int mkblctrl_main(int argc, char *argv[])
Definition: mkblctrl.cpp:1249
#define BLCTRL_NEW
Definition: mkblctrl.cpp:90
int orb_set_interval(int handle, unsigned interval)
Definition: uORB.cpp:126
uint8_t esc_connectiontype
Definition: esc_status.h:64
__EXPORT void up_pwm_servo_deinit(void)
De-initialise the PWM servo outputs.
unsigned _rc_min_value
Definition: mkblctrl.cpp:174
Definition: I2C.hpp:51
float esc_current
Definition: esc_report.h:57
static void task_main_trampoline(int argc, char *argv[])
bool _primary_pwm_device
Definition: mkblctrl.cpp:166
#define PWM_SERVO_GET_UPDATE_RATE
get alternate servo update rate
orb_advert_t orb_advertise(const struct orb_metadata *meta, const void *data)
Definition: uORB.cpp:43
uint64_t timestamp
Definition: esc_status.h:61
uint32_t esc_errorcount
Definition: esc_report.h:54
MotorData_t Motor[MAX_MOTORS]
Definition: mkblctrl.cpp:178
#define PWM_SERVO_CLEAR_ARM_OK
clear the &#39;ARM ok&#39; bit, which deactivates the safety switch
unsigned int mk_check_for_blctrl(unsigned int count, bool showOutput, bool initI2C)
Definition: mkblctrl.cpp:668
#define MOTOR_SPINUP_COUNTER
Definition: mkblctrl.cpp:94
int32_t esc_rpm
Definition: esc_report.h:55
char _device[20]
Definition: mkblctrl.cpp:161
short scaling(float val, float inMin, float inMax, float outMin, float outMax)
Definition: mkblctrl.cpp:432
unsigned int SetPoint
Definition: mkblctrl.cpp:105
int _update_rate
Definition: mkblctrl.cpp:154
#define PWM_SERVO_SET_SELECT_UPDATE_RATE
selects servo update rates, one bit per servo.
int _task
Definition: mkblctrl.cpp:155
#define I2C_BUS_SPEED
Definition: mkblctrl.cpp:85
High-resolution timer with callouts and timekeeping.
orb_advert_t orb_advertise_queue(const struct orb_metadata *meta, const void *data, unsigned int queue_size)
Definition: uORB.cpp:48
MixerGroup * _mixers
Definition: mkblctrl.cpp:172
int _px4mode
Definition: mkblctrl.cpp:159
Global flash based parameter store.
int mk_servo_test(unsigned int chan)
Definition: mkblctrl.cpp:846
#define ESC_UORB_PUBLISH_DELAY
Definition: mkblctrl.cpp:96
#define PWM_SERVO_SET(_servo)
set a single servo to a specific value
static int task_main_trampoline(int argc, char *argv[])
Definition: mkblctrl.cpp:323
Mixer ioctl interfaces.
static char msg[NUM_MSG][CONFIG_USART1_TXBUFSIZE]
Definition: px4io.c:89
unsigned int Version
Definition: mkblctrl.cpp:104
bool _indicate_esc
Definition: mkblctrl.cpp:173
int orb_subscribe(const struct orb_metadata *meta)
Definition: uORB.cpp:75
param_t _param_indicate_esc
Definition: mkblctrl.cpp:176
int pwm_ioctl(file *filp, int cmd, unsigned long arg)
Definition: mkblctrl.cpp:973
const int blctrlAddr_px4[]
Definition: mkblctrl.cpp:209
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
Definition: uORB.h:87
int mk_servo_locate()
Definition: mkblctrl.cpp:913
__EXPORT int up_pwm_servo_set_rate(unsigned rate)
Set the servo update rate for all rate groups.
uint16_t values[PWM_OUTPUT_MAX_CHANNELS]
int set_overrideSecurityChecks(bool overrideSecurityChecks)
Definition: mkblctrl.cpp:425
MK(int bus, const char *_device_path)
Definition: mkblctrl.cpp:220
void init()
Activates/configures the hardware registers.
int unregister_driver(const char *name)
unsigned int State
Definition: mkblctrl.cpp:108
uint8_t esc_temperature
Definition: esc_report.h:58
#define DEVICE_LOG(FMT,...)
Definition: Device.hpp:51
uint8_t esc_state
Definition: esc_report.h:60
MappingMode
Definition: mkblctrl.cpp:1145
#define ORB_ID_VEHICLE_ATTITUDE_CONTROLS
Definition: uORB.h:256
float esc_voltage
Definition: esc_report.h:56
int mk_servo_arm(bool status)
Definition: mkblctrl.cpp:660
unsigned int Current
Definition: mkblctrl.cpp:112
#define MAX_MOTORS
Definition: mkblctrl.cpp:87
Definition: mkblctrl.cpp:121
uint32_t channel_count
unsigned int SetPointLowerBits
Definition: mkblctrl.cpp:106
#define warnx(...)
Definition: err.h:95
float SetPoint_PX4
Definition: mkblctrl.cpp:107
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
void task_main(int argc, char *argv[])
UartEsc * esc
int register_driver(const char *name, const cdev::px4_file_operations_t *fops, cdev::mode_t mode, void *data)
int task_main()
Definition: mkblctrl.cpp:462
static char _device[64]
int _t_actuators
Definition: mkblctrl.cpp:156
#define PWM_SERVO_GET_RATEGROUP(_n)
get the _n&#39;th rate group&#39;s channels; *(uint32_t *)arg returns a bitmap of channels whose update rates...
uint16_t counter
Definition: esc_status.h:62
const int blctrlAddr_hexa_x[]
Definition: mkblctrl.cpp:206
const int blctrlAddr_octo_x[]
Definition: mkblctrl.cpp:207
int _t_actuator_armed
Definition: mkblctrl.cpp:157
Driver for the PX4 audio alarm port, /dev/tone_alarm.
bool _armed
Definition: mkblctrl.cpp:170
#define PWM_SERVO_GET(_servo)
get a single specific servo value
__BEGIN_DECLS typedef void * orb_advert_t
ORB topic advertiser handle.
Definition: uORB.h:134
unsigned int _num_outputs
Definition: mkblctrl.cpp:165
int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
Definition: uORB.cpp:70
#define PWM_SERVO_SET_MIN_PWM
set the minimum PWM value the output will send
FrameType
Definition: mkblctrl.cpp:129
__EXPORT param_t param_find(const char *name)
Look up a parameter by name.
Definition: parameters.cpp:370
#define MIXERIOCRESET
reset (clear) the mixer configuration
Definition: drv_mixer.h:71
uint8_t esc_count
Definition: esc_status.h:63
void play_beep(int count)
Definition: mkblctrl.cpp:449
orb_advert_t _t_outputs
Definition: mkblctrl.cpp:162
#define BLCTRL_BASE_ADDR
Definition: mkblctrl.cpp:88
#define PWM_SERVO_SET_MAX_PWM
set the maximum PWM value the output will send
void set_frametype(int frametype)
Definition: mkblctrl.cpp:335
static void write(bootloader_app_shared_t *pshared)
int addrTranslator[]
Definition: mkblctrl.cpp:211
unsigned int RoundCount
Definition: mkblctrl.cpp:115
MappingMode
Definition: mkblctrl.cpp:124
int set_motor_test(bool motortest)
Definition: mkblctrl.cpp:418
#define PWM_SERVO_GET_MIN_PWM
get the minimum PWM value the output will send
struct @83::@85::@87 file
int orb_check(int handle, bool *updated)
Definition: uORB.cpp:95
#define RC_MAX_VALUE
Definition: mkblctrl.cpp:100
unsigned long debugCounter
Definition: mkblctrl.cpp:171
uint8_t esc_address
Definition: esc_report.h:59
unsigned short RawPwmValue
Definition: mkblctrl.cpp:110
#define errx(eval,...)
Definition: err.h:89
int set_motor_count(unsigned count)
Definition: mkblctrl.cpp:355
virtual int ioctl(file *filp, int cmd, unsigned long arg)
Definition: mkblctrl.cpp:958
unsigned _rc_max_value
Definition: mkblctrl.cpp:175
unsigned mix(float *outputs, unsigned space)
Definition: MixerGroup.cpp:53
int mk_servo_set(unsigned int chan, short val)
Definition: mkblctrl.cpp:736
void set_px4mode(int px4mode)
Definition: mkblctrl.cpp:329
#define UPDATE_RATE
Definition: mkblctrl.cpp:86
bool _motortest
Definition: mkblctrl.cpp:167
~MK()
Definition: mkblctrl.cpp:247
#define OK
Definition: uavcan_main.cpp:71
unsigned int Temperature
Definition: mkblctrl.cpp:114
#define MOTOR_STATE_ERROR_MASK
Definition: mkblctrl.cpp:93
FrameType
Definition: mkblctrl.cpp:1150
#define BLCTRL_MIN_VALUE
Definition: mkblctrl.cpp:91
Group of mixers, built up from single mixers and processed in order when mixing.
Definition: MixerGroup.hpp:42
static tune_control_s tune_control
void set_rc_min_value(unsigned value)
Definition: mkblctrl.cpp:341
#define MOTOR_LOCATE_DELAY
Definition: mkblctrl.cpp:95
static const bool showDebug
Definition: mkblctrl.cpp:152
orb_advert_t orb_advertise_multi(const struct orb_metadata *meta, const void *data, int *instance, int priority)
Definition: uORB.cpp:53
const int blctrlAddr_hexa_plus[]
Definition: mkblctrl.cpp:202
orb_advert_t _tune_control_sub
Definition: mkblctrl.cpp:164
unsigned int ReadMode
Definition: mkblctrl.cpp:109
#define DEVICE_DEBUG(FMT,...)
Definition: Device.hpp:52
static int control_callback(uintptr_t handle, uint8_t control_group, uint8_t control_index, float &input)
Definition: mkblctrl.cpp:946
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
uint32_t param_t
Parameter handle.
Definition: param.h:98
virtual int init(unsigned motors)
Definition: mkblctrl.cpp:277
uint8_t tune_id
Definition: tune_control.h:61
#define PWM_SERVO_DISARM
disarm all servo outputs (stop generating pulses)
#define PWM_SERVO_GET_MAX_PWM
get the maximum PWM value the output will send
bool _overrideSecurityChecks
Definition: mkblctrl.cpp:168
#define PWM_SERVO_SET_UPDATE_RATE
set alternate servo update rate
Base class for devices connected via I2C.