36 #include <px4_platform_common/defines.h> 37 #include <px4_platform_common/module.h> 38 #include <px4_platform_common/tasks.h> 39 #include <px4_platform_common/getopt.h> 40 #include <px4_platform_common/posix.h> 49 #include <px4_platform_common/module_params.h> 68 #if !defined(BOARD_TAP_ESC_MODE) 69 # define BOARD_TAP_ESC_MODE 0 72 #if !defined(DEVICE_ARGUMENT_MAX_LENGTH) 73 # define DEVICE_ARGUMENT_MAX_LENGTH 32 77 #if !defined(TAP_ESC_CTRL_UORB_UPDATE_INTERVAL) 78 # define TAP_ESC_CTRL_UORB_UPDATE_INTERVAL 2 // [ms] min: 2, max: 100 100 static int print_usage(
const char *reason =
nullptr);
129 px4_pollfd_struct_t
_poll_fds[actuator_controls_s::NUM_ACTUATOR_CONTROL_GROUPS];
145 (ParamInt<px4::params::MC_AIRMODE>) _param_mc_airmode
151 uint8_t control_group, uint8_t control_index,
float &input);
152 inline int control_callback(uint8_t control_group, uint8_t control_index,
float &input);
160 ModuleParams(nullptr),
168 _control_topics[1] =
ORB_ID(actuator_controls_1);
169 _control_topics[2] =
ORB_ID(actuator_controls_2);
170 _control_topics[3] =
ORB_ID(actuator_controls_3);
174 for (
int i = 0; i < actuator_controls_s::NUM_ACTUATOR_CONTROL_GROUPS; ++i) {
187 for (
unsigned i = 0; i < actuator_controls_s::NUM_ACTUATOR_CONTROL_GROUPS; i++) {
203 PX4_INFO(
"stopping");
212 const char *
device =
nullptr;
213 uint8_t channels_count = 0;
217 const char *myoptarg =
nullptr;
224 while ((ch = px4_getopt(argc, argv,
"d:n:", &myoptind, &myoptarg)) != EOF) {
231 channels_count = atoi(myoptarg);
237 if (channels_count == 0) {
242 if (device ==
nullptr || strlen(device) == 0) {
249 if (tap_esc ==
nullptr) {
250 PX4_ERR(
"failed to instantiate module");
254 if (tap_esc->
init() != 0) {
255 PX4_ERR(
"failed to initialize module");
276 PX4_ERR(
"failed to initialise UART.");
296 for (uint8_t phy_chan_index = 0; phy_chan_index <
_channels_count; phy_chan_index++) {
297 config.channelMapTable[phy_chan_index] =
_device_mux_map[phy_chan_index] &
299 config.channelMapTable[phy_chan_index] |= (
_device_dir_map[phy_chan_index] << 4) &
303 config.maxChannelValue =
RPMMAX;
304 config.minChannelValue =
RPMMIN;
317 memset(unlock_packet.
d.
bytes, 0,
sizeof(unlock_packet.
d.
bytes));
319 int unlock_times = 10;
321 while (unlock_times--) {
351 for (
unsigned i = 0; i < actuator_controls_s::NUM_ACTUATOR_CONTROL_GROUPS; i++) {
352 if (sub_groups & (1 << i)) {
353 PX4_DEBUG(
"subscribe to actuator_controls_%d", i);
357 if (unsub_groups & (1 << i)) {
358 PX4_DEBUG(
"unsubscribe from actuator_controls_%d", i);
375 for (uint8_t i = 0; i < motor_cnt; i++) {
402 PX4_WARN(
"TX ERROR: ret: %d, errno: %d", ret, errno);
413 for (
unsigned i = 0; i < actuator_controls_s::NUM_ACTUATOR_CONTROL_GROUPS; i++) {
430 PX4_ERR(
"poll error %d", errno);
435 unsigned poll_id = 0;
437 for (
unsigned i = 0; i < actuator_controls_s::NUM_ACTUATOR_CONTROL_GROUPS; i++) {
439 if (
_poll_fds[poll_id].revents & POLLIN) {
469 for (
unsigned i = 0; i < num_outputs; i++) {
493 bool test_motor_updated;
496 if (test_motor_updated) {
500 if (test_motor.
action == test_motor_s::ACTION_STOP) {
507 PX4_INFO(
"setting motor %i to %.1lf", test_motor.
motor_number,
512 for (
unsigned i = 0; i < num_outputs; i++) {
529 switch (num_outputs) {
549 for (uint8_t i = 0; i < num_outputs; ++i) {
570 if (feed_back_data.
channelID < esc_status_s::CONNECTED_ESC_MAX) {
588 for (
int i = 0; i < actuator_controls_s::NUM_ACTUATOR_CONTROL_GROUPS; i++) {
592 if (required && (timestamp_sample > 0)) {
643 }
else if (input < -1.0
f) {
649 if ((control_group == actuator_controls_s::GROUP_INDEX_ATTITUDE ||
650 control_group == actuator_controls_s::GROUP_INDEX_ATTITUDE_ALTERNATE) &&
651 control_index == actuator_controls_s::INDEX_THROTTLE) {
676 const char *buf = (
const char *)arg;
677 unsigned buflen = strlen(buf);
691 PX4_DEBUG(
"mixer load failed with %d", ret);
718 while (!should_exit()) {
727 _task_id = px4_task_spawn_cmd(
"tap_esc",
729 SCHED_PRIORITY_ACTUATOR_OUTPUTS,
731 (px4_main_t)&run_trampoline,
735 PX4_ERR(
"task start failed");
741 if (wait_until_running() < 0) {
753 PX4_WARN(
"%s\n", reason);
756 PRINT_MODULE_DESCRIPTION(
759 This module controls the TAP_ESC hardware via UART. It listens on the 760 actuator_controls topics, does the mixing and writes the PWM outputs. 763 Currently the module is implementd as a threaded version only, meaning that it 764 runs in its own thread instead of on the work queue. 767 The module is typically started with: 768 tap_esc start -d /dev/ttyS2 -n <1-8> 772 PRINT_MODULE_USAGE_NAME("tap_esc",
"driver");
774 PRINT_MODULE_USAGE_COMMAND_DESCR(
"start",
"Start the task");
775 PRINT_MODULE_USAGE_PARAM_STRING(
'd',
nullptr,
"<device>",
"Device used to talk to ESCs",
true);
776 PRINT_MODULE_USAGE_PARAM_INT(
'n', 4, 0, 8,
"Number of ESCs",
true);
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.
constexpr _Tp constrain(_Tp val, _Tp min_val, _Tp max_val)
uint32_t _groups_required
struct esc_report_s esc[8]
void send_esc_outputs(const uint16_t *pwm, const uint8_t motor_cnt)
uint32_t _groups_subscribed
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 TAP_ESC_CTRL_UORB_UPDATE_INTERVAL
uint16_t get_saturation_status()
measure the time elapsed performing an event
perf_counter_t _perf_control_latency
int send_packet(int uart_fd, EscPacket &packet, int responder)
Sends a packet to all ESCs and requests a specific ESC to respond.
int main(int argc, char **argv)
RunInfoRepsonse rspRunInfo
int read_data_from_uart(int uart_fd, ESC_UART_BUF *const uart_buf)
Read data from the UART into a buffer.
DEFINE_PARAMETERS((ParamInt< px4::params::MC_AIRMODE >) _param_mc_airmode) void subscribe()
int orb_set_interval(int handle, unsigned interval)
uint8_t esc_connectiontype
static int print_usage(const char *reason=nullptr)
void perf_set_elapsed(perf_counter_t handle, int64_t elapsed)
Register a measurement.
orb_advert_t orb_advertise(const struct orb_metadata *meta, const void *data)
int deinitialise_uart(int &uart_fd)
Closes a device previously opened with initialise_uart().
virtual int ioctl(cdev::file_t *filp, int cmd, unsigned long arg)
Perform an ioctl operation on the device.
Namespace encapsulating all device framework classes, functions and data.
High-resolution timer with callouts and timekeeping.
int control_callback(uint8_t control_group, uint8_t control_index, float &input)
int orb_subscribe(const struct orb_metadata *meta)
static int control_callback_trampoline(uintptr_t handle, uint8_t control_group, uint8_t control_index, float &input)
#define DEVICE_ARGUMENT_MAX_LENGTH
#define ORB_ID(_name)
Generates a pointer to the uORB metadata structure for a given topic.
uint16_t saturation_status
char _device[DEVICE_ARGUMENT_MAX_LENGTH]
Abstract class for any character device.
void perf_free(perf_counter_t handle)
Free a counter.
#define ESC_MASK_MAP_CHANNEL
orb_advert_t _esc_feedback_pub
void init()
Activates/configures the hardware registers.
static TAP_ESC * instantiate(int argc, char *argv[])
actuator_controls_s _controls[actuator_controls_s::NUM_ACTUATOR_CONTROL_GROUPS]
actuator_outputs_s _outputs
int orb_unsubscribe(int handle)
Vector< float, 6 > f(float t, const Matrix< float, 6, 1 > &, const Matrix< float, 3, 1 > &)
orb_advert_t _to_mixer_status
mixer status flags
int parse_tap_esc_feedback(ESC_UART_BUF *const serial_buf, EscPacket *const packetdata)
Parse feedback from an ESC.
__EXPORT int tap_esc_main(int argc, char *argv[])
px4_pollfd_struct_t _poll_fds[actuator_controls_s::NUM_ACTUATOR_CONTROL_GROUPS]
static const uint8_t _device_dir_map[TAP_ESC_MAX_MOTOR_NUM]
uORB::Subscription _parameter_update_sub
uint64_t timestamp_sample
bool updated()
Check if there is a new update.
__BEGIN_DECLS typedef uint64_t hrt_abstime
Absolute time, in microsecond units.
static int task_spawn(int argc, char *argv[])
__BEGIN_DECLS typedef void * orb_advert_t
ORB topic advertiser handle.
int orb_publish(const struct orb_metadata *meta, orb_advert_t handle, const void *data)
uint8_t _channels_count
nnumber of ESC channels
#define RUN_FEEDBACK_ENABLE_MASK
#define MIXERIOCRESET
reset (clear) the mixer configuration
void groups_required(uint32_t &groups)
ConfigInfoBasicRequest reqConfigInfoBasic
#define TAP_ESC_DEVICE_PATH
int _control_subs[actuator_controls_s::NUM_ACTUATOR_CONTROL_GROUPS]
void set_airmode(Mixer::Airmode airmode)
static const uint8_t _device_mux_map[TAP_ESC_MAX_MOTOR_NUM]
int initialise_uart(const char *const device, int &uart_fd)
Opens a device for use as UART.
#define TAP_ESC_MAX_MOTOR_NUM
int orb_check(int handle, bool *updated)
#define RUN_BLUE_LED_ON_MASK
int orb_unadvertise(orb_advert_t handle)
CDev(const char *devname)
Constructor.
unsigned mix(float *outputs, unsigned space)
#define ESC_MASK_MAP_RUNNING_DIRECTION
orb_advert_t _outputs_pub
TAP_ESC(char const *const device, uint8_t channels_count)
static int custom_command(int argc, char *argv[])
Group of mixers, built up from single mixers and processed in order when mixing.
uint16_t rpm_flags[TAP_ESC_MAX_MOTOR_NUM]
bool copy(void *dst)
Copy the struct.
esc_status_s _esc_feedback
orb_id_t _control_topics[actuator_controls_s::NUM_ACTUATOR_CONTROL_GROUPS]
__EXPORT hrt_abstime hrt_absolute_time(void)
Get absolute time in [us] (does not wrap).
#define BOARD_TAP_ESC_MODE
Performance measuring tools.