44 #include <px4_platform_common/px4_config.h> 45 #include <px4_platform_common/tasks.h> 49 #include <sys/types.h> 53 #include <semaphore.h> 62 #include <nuttx/arch.h> 63 #include <nuttx/i2c/i2c_master.h> 65 #include <board_config.h> 85 #define I2C_BUS_SPEED 100000 86 #define UPDATE_RATE 200 88 #define BLCTRL_BASE_ADDR 0x29 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 98 #define CONTROL_INPUT_DROP_LIMIT_MS 20 99 #define RC_MIN_VALUE 1010 100 #define RC_MAX_VALUE 2100 121 class MK :
public device::I2C
134 MK(
int bus,
const char *_device_path);
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);
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);
152 static const bool showDebug =
false;
183 static int control_callback(uintptr_t handle,
184 uint8_t control_group,
185 uint8_t control_index,
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);
220 MK::MK(
int bus,
const char *_device_path) :
225 _t_actuator_armed(-1),
227 _px4mode(MAPPING_MK),
228 _frametype(FRAME_PLUS),
232 _primary_pwm_device(false),
234 _overrideSecurityChecks(false),
238 _indicate_esc(false),
265 }
while (
_task != -1);
289 warnx(
"I2C init failed");
299 DEVICE_LOG(
"creating alternate output device");
306 _task = px4_task_spawn_cmd(
"mkblctrl",
308 SCHED_PRIORITY_MAX - 20,
325 return g_mk->task_main();
363 PX4_INFO(
"Mikrokopter ESC addressing. Frame: +");
366 PX4_INFO(
"Mikrokopter ESC addressing. Frame: X");
395 PX4_INFO(
"PX4 ESC addressing.");
400 PX4_INFO(
"4 ESCs = Quadrocopter");
403 PX4_INFO(
"6 ESCs = Hexacopter");
406 PX4_INFO(
"8 ESCs = Octocopter");
432 MK::scaling(
float val,
float inMin,
float inMax,
float outMin,
float outMax)
436 retVal = (val - inMin) / (inMax - inMin) * (outMax - outMin) + outMin;
438 if (retVal < outMin) {
441 }
else if (retVal > outMax) {
452 tune.
tune_id =
static_cast<int>(TuneID::SINGLE_BEEP);
454 for (
int i = 0; i < count; i++) {
464 int32_t param_mkblctrl_test = 0;
482 memset(&outputs, 0,
sizeof(outputs));
491 memset(&esc, 0,
sizeof(esc));
502 fds[0].events = POLLIN;
504 fds[1].events = POLLIN;
515 if (param_mkblctrl_test > 0) {
533 if (fds[0].revents & POLLIN) {
535 bool changed =
false;
554 PX4_ISFINITE(outputs.
output[i]) &&
555 outputs.
output[i] >= -1.0f &&
556 outputs.
output[i] <= 1.0f) {
565 if (outputs.
output[i] < -1.0f) {
566 outputs.
output[i] = -1.0f;
568 }
else if (outputs.
output[i] > 1.0f) {
572 outputs.
output[i] = -1.0f;
595 if (fds[1].revents & POLLIN) {
675 uint8_t foundMotorCount = 0;
693 for (
unsigned i = 0; i < count; i++) {
700 if (
OK == transfer(&msg, 1, &result[0], 3)) {
707 if ((
Motor[i].MaxPWM & 252) == 248) {
717 PX4_INFO(
"MotorsFound: %i", foundMotorCount);
719 for (
unsigned i = 0; i < foundMotorCount; i++) {
720 PX4_INFO(
"blctrl[%i] : found=%i\tversion=%i\tcurrent=%i\tmaxpwm=%i\ttemperature=%i", i,
726 if (foundMotorCount != 4 && foundMotorCount != 6 && foundMotorCount != 8) {
732 return foundMotorCount;
740 uint8_t result[3] = { 0, 0, 0 };
741 uint8_t
msg[2] = { 0, 0 };
742 uint8_t bytesToSendBL2 = 2;
749 }
else if (tmpVal < 0) {
770 if (
Motor[chan].RoundCount >= 16) {
772 if (
OK == transfer(&msg[0], 1, &result[0], 2)) {
784 if (
OK != transfer(&msg[0], 1,
nullptr, 0)) {
796 if (
Motor[chan].SetPointLowerBits == 0) {
800 if (
Motor[chan].RoundCount >= 16) {
802 if (
OK == transfer(&msg[0], bytesToSendBL2, &result[0], 3)) {
814 if (
OK != transfer(&msg[0], bytesToSendBL2,
nullptr, 0)) {
832 PX4_INFO(
"#%i:\tVer: %i\tVal: %i\tCurr: %i\tMaxPWM: %i\tTemp: %i\tState: %i", i,
Motor[i].Version,
852 uint8_t
msg[2] = { 0, 0 };
859 PX4_INFO(
"Motortest - #%i:\tspinup",
_motor);
865 PX4_INFO(
"Motortest finished...");
878 tmpVal = (511 + (511 * val));
902 ret = transfer(&msg[0], 1,
nullptr, 0);
905 ret = transfer(&msg[0], 2,
nullptr, 0);
916 static unsigned int chan = 0;
917 static uint64_t last_timestamp = 0;
919 uint8_t
msg[2] = { 0, 0 };
929 PX4_INFO(
"ESC Locate - #%i:\tgreen", chan);
939 ret = transfer(&msg[0], 1,
nullptr, 0);
947 uint8_t control_group,
948 uint8_t control_index,
953 input = controls->
control[control_index];
965 if (ret == -ENOTTY) {
966 ret = CDev::ioctl(filp, cmd, arg);
1043 const char *buf = (
const char *)arg;
1044 unsigned buflen = strlen(buf);
1122 unsigned count = len / 2;
1131 memcpy(values, buffer, count * 2);
1133 for (uint8_t i = 0; i < count; i++) {
1157 mk_new_mode(
int motorcount,
bool motortest,
int px4mode,
int frametype,
bool overrideSecurityChecks,
unsigned rcmin,
1163 g_mk->set_rc_min_value(rcmin);
1166 g_mk->set_rc_max_value(rcmax);
1169 g_mk->set_px4mode(px4mode);
1172 g_mk->set_frametype(frametype);
1175 g_mk->set_motor_test(motortest);
1178 g_mk->set_overrideSecurityChecks(overrideSecurityChecks);
1182 if (g_mk->mk_check_for_blctrl(8,
false,
false) != 0) {
1190 }
while (shouldStop < 3);
1192 g_mk->set_motor_count(g_mk->mk_check_for_blctrl(8,
true,
false));
1198 mk_start(
unsigned motors,
const char *device_path)
1203 g_mk =
new MK(3, device_path);
1209 if (
OK == g_mk->init(motors)) {
1210 warnx(
"[mkblctrl] scanning i2c3...\n");
1211 ret = g_mk->mk_check_for_blctrl(8,
false,
false);
1222 g_mk =
new MK(1, device_path);
1228 if (
OK == g_mk->init(motors)) {
1229 warnx(
"[mkblctrl] scanning i2c1...\n");
1230 ret = g_mk->mk_check_for_blctrl(8,
false,
false);
1254 bool motortest =
false;
1255 bool overrideSecurityChecks =
false;
1256 bool showHelp =
false;
1257 bool newMode =
true;
1258 const char *devicepath =
"";
1266 for (
int i = 1; i < argc; i++) {
1269 if (strcmp(argv[i],
"-mkmode") == 0 || strcmp(argv[i],
"--mkmode") == 0) {
1271 if (strcmp(argv[i + 1],
"+") == 0 || strcmp(argv[i + 1],
"x") == 0 || strcmp(argv[i + 1],
"X") == 0) {
1275 if (strcmp(argv[i + 1],
"+") == 0) {
1283 errx(1,
"only + or x for frametype supported !");
1287 errx(1,
"missing argument for mkmode (-mkmode)");
1293 if (strcmp(argv[i],
"-t") == 0) {
1299 if (strcmp(argv[i],
"-h") == 0 || strcmp(argv[i],
"--help") == 0) {
1304 if (strcmp(argv[i],
"--override-security-checks") == 0) {
1305 overrideSecurityChecks =
true;
1310 if (strcmp(argv[i],
"-d") == 0 || strcmp(argv[i],
"--device") == 0) {
1312 devicepath = argv[i + 1];
1316 errx(1,
"missing the devicename (-d)");
1322 if (strcmp(argv[i],
"-rc_min") == 0) {
1324 rc_min_value = strtoul(argv[i + 1], &ep, 0);
1327 errx(1,
"bad pwm val (-rc_min)");
1332 errx(1,
"missing value (-rc_min)");
1338 if (strcmp(argv[i],
"-rc_max") == 0) {
1340 rc_max_value = strtoul(argv[i + 1], &ep, 0);
1343 errx(1,
"bad pwm val (-rc_max)");
1348 errx(1,
"missing value (-rc_max)");
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.");
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 !!!)");
1374 if (g_mk ==
nullptr) {
1375 if (mk_start(motorcount, devicepath) !=
OK) {
1376 errx(1,
"failed to start the MK-BLCtrl driver");
1382 return mk_new_mode(motorcount, motortest, px4mode, frametype, overrideSecurityChecks, rc_min_value, rc_max_value);
1388 errx(1,
"MK-BLCtrl driver already running");
1392 if (g_mk ==
nullptr) {
1393 errx(1,
"MK-BLCtrl driver not running. You have to start it first.");
1396 g_mk->set_motor_test(motortest);
volatile bool _task_should_exit
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.
struct esc_report_s esc[8]
const int blctrlAddr_quad_plus[]
#define CONTROL_INPUT_DROP_LIMIT_MS
int orb_copy(const struct orb_metadata *meta, int handle, void *buffer)
#define MIXERIOCLOADBUF
Add mixer(s) from the buffer in (const char *)arg.
#define PWM_SERVO_SET_ARM_OK
set the 'ARM ok' bit, which activates the safety switch
const int blctrlAddr_quad_x[]
actuator_controls_s _controls
virtual ssize_t write(file *filp, const char *buffer, size_t len)
static struct vehicle_status_s status
uint16_t servo_position_t
Servo output signal type, value is actual servo output pulse width in microseconds.
orb_advert_t _t_esc_status
void set_rc_max_value(unsigned value)
volatile bool _task_should_exit
__EXPORT int param_get(param_t param, void *val)
Copy the value of a parameter.
#define PWM_SERVO_GET_COUNT
get the number of servos in *(unsigned *)arg
const int blctrlAddr_octo_plus[]
#define PWM_SERVO_ARM
arm all servo outputs handle by this driver
#define MOTOR_STATE_PRESENT_MASK
static const unsigned _max_actuators
__EXPORT int mkblctrl_main(int argc, char *argv[])
int orb_set_interval(int handle, unsigned interval)
uint8_t esc_connectiontype
__EXPORT void up_pwm_servo_deinit(void)
De-initialise the PWM servo outputs.
static void task_main_trampoline(int argc, char *argv[])
#define PWM_SERVO_GET_UPDATE_RATE
get alternate servo update rate
orb_advert_t orb_advertise(const struct orb_metadata *meta, const void *data)
MotorData_t Motor[MAX_MOTORS]
#define PWM_SERVO_CLEAR_ARM_OK
clear the 'ARM ok' bit, which deactivates the safety switch
unsigned int mk_check_for_blctrl(unsigned int count, bool showOutput, bool initI2C)
#define MOTOR_SPINUP_COUNTER
short scaling(float val, float inMin, float inMax, float outMin, float outMax)
#define PWM_SERVO_SET_SELECT_UPDATE_RATE
selects servo update rates, one bit per servo.
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)
Global flash based parameter store.
int mk_servo_test(unsigned int chan)
#define ESC_UORB_PUBLISH_DELAY
#define PWM_SERVO_SET(_servo)
set a single servo to a specific value
static int task_main_trampoline(int argc, char *argv[])
static char msg[NUM_MSG][CONFIG_USART1_TXBUFSIZE]
int orb_subscribe(const struct orb_metadata *meta)
param_t _param_indicate_esc
int pwm_ioctl(file *filp, int cmd, unsigned long arg)
const int blctrlAddr_px4[]
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
__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)
MK(int bus, const char *_device_path)
void init()
Activates/configures the hardware registers.
#define DEVICE_LOG(FMT,...)
#define ORB_ID_VEHICLE_ATTITUDE_CONTROLS
int mk_servo_arm(bool status)
unsigned int SetPointLowerBits
Simple error/warning functions, heavily inspired by the BSD functions of the same names...
void task_main(int argc, char *argv[])
#define PWM_SERVO_GET_RATEGROUP(_n)
get the _n'th rate group's channels; *(uint32_t *)arg returns a bitmap of channels whose update rates...
const int blctrlAddr_hexa_x[]
const int blctrlAddr_octo_x[]
Driver for the PX4 audio alarm port, /dev/tone_alarm.
#define PWM_SERVO_GET(_servo)
get a single specific servo value
__BEGIN_DECLS typedef void * orb_advert_t
ORB topic advertiser handle.
unsigned int _num_outputs
int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
#define PWM_SERVO_SET_MIN_PWM
set the minimum PWM value the output will send
__EXPORT param_t param_find(const char *name)
Look up a parameter by name.
#define MIXERIOCRESET
reset (clear) the mixer configuration
void play_beep(int count)
#define PWM_SERVO_SET_MAX_PWM
set the maximum PWM value the output will send
void set_frametype(int frametype)
static void write(bootloader_app_shared_t *pshared)
int set_motor_test(bool motortest)
#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)
unsigned long debugCounter
unsigned short RawPwmValue
int set_motor_count(unsigned count)
virtual int ioctl(file *filp, int cmd, unsigned long arg)
unsigned mix(float *outputs, unsigned space)
int mk_servo_set(unsigned int chan, short val)
void set_px4mode(int px4mode)
#define MOTOR_STATE_ERROR_MASK
Group of mixers, built up from single mixers and processed in order when mixing.
static tune_control_s tune_control
void set_rc_min_value(unsigned value)
#define MOTOR_LOCATE_DELAY
static const bool showDebug
orb_advert_t orb_advertise_multi(const struct orb_metadata *meta, const void *data, int *instance, int priority)
const int blctrlAddr_hexa_plus[]
orb_advert_t _tune_control_sub
#define DEVICE_DEBUG(FMT,...)
static int control_callback(uintptr_t handle, uint8_t control_group, uint8_t control_index, float &input)
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
uint32_t param_t
Parameter handle.
virtual int init(unsigned motors)
#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
#define PWM_SERVO_SET_UPDATE_RATE
set alternate servo update rate
Base class for devices connected via I2C.