PX4 IO [14] serial [转载]

2023-05-16

PX4 IO [14] serial

PX4 IO [14] serial
                                                                             -------- 转载请注明出处 
                                                                             -------- 更多笔记请访问我的博客:merafour.blog.163.com 

                                                                             -------- 2014-12-31.冷月追风

                                                                             -------- email:merafour@163.com 

 


1.hrt_ppm_decode 

    我们已经不止一次接触到 fmu跟 IO通讯,之前我们看到的只是 fmu部分源码,那么 IO中又是怎么处理的呢?下面我们就来瞧瞧。 
    IO固件的 mk文件为: "./PX4Firmware/makefiles/config_px4io-v2_default.mk",其内容如下:

#
# Makefile for the px4iov2_default configuration
#
# Board support modules
#
MODULES         += drivers/stm32
MODULES         += drivers/boards/px4io-v2
MODULES         += modules/px4iofirmware

这是 IO固件所用到的一些文件,当然仅仅是 PX4Firmware目录下的。而现在我们要阅读的源码在 "PX4Firmware/src/modules/px4iofirmware/"目录,其内容如下:

radiolink@ubuntu:~/apm$ ls PX4Firmware/src/modules/px4iofirmware/
adc.c       dsm.c  mixer.cpp  protocol.h  px4io.h      safety.c  serial.c
controls.c  i2c.c  module.mk  px4io.c     registers.c  sbus.c
radiolink@ubuntu:~/apm$

因为前面我们知道 fmu跟 IO是通过串口进行通讯的,所以我们现在要阅读的源码主要在 serial.c中。
    前面我们看到,在 io_get_raw_rc_input函数中使用下面的代码来获取遥控器数据:

    if (channel_count > 9) {
        ret = io_reg_get(PX4IO_PAGE_RAW_RC_INPUT, PX4IO_P_RAW_RC_BASE + 9, &regs[prolog + 9], channel_count - 9);

        if (ret != OK)
            return ret;
    }
int PX4IO::io_reg_get(uint8_t page, uint8_t offset, uint16_t *values, unsignednum_values)
{
    /* range check the transfer */
    if (num_values > ((_max_transfer) / sizeof(*values))) {
        debug("io_reg_get: too many registers (%u, max %u)", num_values, _max_transfer / 2);
        return -EINVAL;
    }

    int ret = _interface->read((page << 8) | offset, reinterpret_cast<void *>(values), num_values);

    if (ret != (int)num_values) {
        debug("io_reg_get(%u,%u,%u): data error %d", page, offset, num_values, ret);
        return -1;
    }

    return OK;
}

因此我有理由相信在 IO中也使用了宏 PX4IO_PAGE_RAW_RC_INPUT。所以:

radiolink@ubuntu:~/apm$ grep -nr PX4IO_PAGE_RAW_RC_INPUT ./PX4Firmware/src/modules/px4iofirmware/
./PX4Firmware/src/modules/px4iofirmware/px4io.h:77:externuint16_t                      r_page_raw_rc_input[];  /* PX4IO_PAGE_RAW_RC_INPUT */
./PX4Firmware/src/modules/px4iofirmware/protocol.h:140:#definePX4IO_PAGE_RAW_RC_INPUT          4
./PX4Firmware/src/modules/px4iofirmware/registers.c:866:        casePX4IO_PAGE_RAW_RC_INPUT:
radiolink@ubuntu:~/apm$
int registers_get(uint8_t page, uint8_t offset, uint16_t **values, unsigned*num_values)
{
#define SELECT_PAGE(_page_name)                            \
    do {                                    \
        *values = &_page_name[0];                    \
        *num_values = sizeof(_page_name) / sizeof(_page_name[0]);    \
    } while(0)

    switch (page) {

    /* ... */
    /* status pages */
    case PX4IO_PAGE_CONFIG:
        SELECT_PAGE(r_page_config);
        break;
    case PX4IO_PAGE_ACTUATORS:
        SELECT_PAGE(r_page_actuators);
        break;
    case PX4IO_PAGE_SERVOS:
        SELECT_PAGE(r_page_servos);
        break;
    case PX4IO_PAGE_RAW_RC_INPUT:
        SELECT_PAGE(r_page_raw_rc_input);
        break;

在这段代码中我们并没有看到数据拷贝,所以数据拷贝应该是由调用 registers_get的函数来完成。

static void rx_handle_packet(void)
{
    /* check packet CRC */
    uint8_t crc = dma_packet.crc;
    dma_packet.crc = 0;
    if (crc != crc_packet(&dma_packet)) {
        perf_count(pc_crcerr);

        /* send a CRC error reply */
        dma_packet.count_code = PKT_CODE_CORRUPT;
        dma_packet.page = 0xff;
        dma_packet.offset = 0xff;

        return;
    }

    if (PKT_CODE(dma_packet) == PKT_CODE_WRITE) {

        /* it's a blind write - pass it on */
        if (registers_set(dma_packet.page, dma_packet.offset, &dma_packet.regs[0], PKT_COUNT(dma_packet))) {
            perf_count(pc_regerr);
            dma_packet.count_code = PKT_CODE_ERROR;
        } else {
            dma_packet.count_code = PKT_CODE_SUCCESS;
        }
        return;
    } 

    if (PKT_CODE(dma_packet) == PKT_CODE_READ) {

        /* it's a read - get register pointer for reply */
        unsigned count;
        uint16_t *registers;

        if (registers_get(dma_packet.page, dma_packet.offset, &registers, &count) < 0) {
            perf_count(pc_regerr);
            dma_packet.count_code = PKT_CODE_ERROR;
        } else {
            /* constrain reply to requested size */
            if (count > PKT_MAX_REGS)
                count = PKT_MAX_REGS;
            if (count > PKT_COUNT(dma_packet))
                count = PKT_COUNT(dma_packet);

            /* copy reply registers into DMA buffer */
            memcpy((void *)&dma_packet.regs[0], registers, count * 2);
            dma_packet.count_code = count | PKT_CODE_SUCCESS;
        }
        return;
    }

    /* send a bad-packet error reply */
    dma_packet.count_code = PKT_CODE_CORRUPT;
    dma_packet.page = 0xff;
    dma_packet.offset = 0xfe;
}
static

void rx_dma_callback(DMA_HANDLE handle, uint8_t status, void *arg)
{
    /* ... */
    rx_handle_packet();

在 rx_handle_packet函数中我们看到 IO提供了 registers_get跟 registers_set函数分别用来获取和设置 IO数据。而 rx_dma_callback函数的调用我们很容易想到是在串口收到数据的时候。这个我们回头再来折腾,现在我们要去看另外一个东西:r_page_raw_rc_input。在 registers_get函数中我们要读取的数据是来自 r_page_raw_rc_input,它的数据肯定也是有人放进去的,而不是凭空产生的。所以:

radiolink@ubuntu:~/apm$ grep -nr r_page_raw_rc_input ./PX4Firmware/src/modules/px4iofirmware/
./PX4Firmware/src/modules/px4iofirmware/controls.c:216: bool ppm_updated = ppm_input(r_raw_rc_values, &r_raw_rc_count, &r_page_raw_rc_input[PX4IO_P_RAW_RC_DATA]);
./PX4Firmware/src/modules/px4iofirmware/controls.c:230: r_page_raw_rc_input[PX4IO_P_RAW_RC_NRSSI] = rssi;
./PX4Firmware/src/modules/px4iofirmware/px4io.h:77:externuint16_t                      r_page_raw_rc_input[];  /* PX4IO_PAGE_RAW_RC_INPUT */
./PX4Firmware/src/modules/px4iofirmware/px4io.h:97:#definer_raw_rc_count               r_page_raw_rc_input[PX4IO_P_RAW_RC_COUNT]
./PX4Firmware/src/modules/px4iofirmware/px4io.h:98:#definer_raw_rc_values              (&r_page_raw_rc_input[PX4IO_P_RAW_RC_BASE])
./PX4Firmware/src/modules/px4iofirmware/px4io.h:99:#definer_raw_rc_flags               r_page_raw_rc_input[PX4IO_P_RAW_RC_FLAGS]
./PX4Firmware/src/modules/px4iofirmware/registers.c:114:uint16_t                r_page_raw_rc_input[] =
./PX4Firmware/src/modules/px4iofirmware/registers.c:867:                SELECT_PAGE(r_page_raw_rc_input);
radiolink@ubuntu:~/apm$

经分析, controls.c是用来获取遥控器数据的。其实,从其命名上也是相当明显的。

    /*
     * XXX each S.bus frame will cause a PPM decoder interrupt
     * storm (lots of edges).  It might be sensible to actually
     * disable the PPM decoder completely if we have S.bus signal.
     */
    perf_begin(c_gather_ppm);
    bool ppm_updated = ppm_input(r_raw_rc_values, &r_raw_rc_count, &r_page_raw_rc_input[PX4IO_P_RAW_RC_DATA]);
    if (ppm_updated) {

        r_status_flags |= PX4IO_P_STATUS_FLAGS_RC_PPM;
        r_raw_rc_flags &= ~(PX4IO_P_RAW_RC_FLAGS_FRAME_DROP);
        r_raw_rc_flags &= ~(PX4IO_P_RAW_RC_FLAGS_FAILSAFE);
    }
    perf_end(c_gather_ppm);

    /* limit number of channels to allowable data size */
    if (r_raw_rc_count > PX4IO_RC_INPUT_CHANNELS)
        r_raw_rc_count = PX4IO_RC_INPUT_CHANNELS;

    /* store RSSI */
    r_page_raw_rc_input[PX4IO_P_RAW_RC_NRSSI] = rssi;
static bool ppm_input(uint16_t *values, uint16_t *num_values, uint16_t *frame_len)
{
    bool result = false;

    /* avoid racing with PPM updates */
    irqstate_t state = irqsave();

    /*
     * If we have received a new PPM frame within the last 200ms, accept it
     * and then invalidate it.
     */
    if (hrt_elapsed_time(&ppm_last_valid_decode) < 200000) {

        /* PPM data exists, copy it */
        *num_values = ppm_decoded_channels;
        if (*num_values > PX4IO_RC_INPUT_CHANNELS)
            *num_values = PX4IO_RC_INPUT_CHANNELS;

        for (unsigned i = 0; i < *num_values; i++)
            values[i] = ppm_buffer[i];

        /* clear validity */
        ppm_last_valid_decode = 0;

        /* store PPM frame length */
        if (num_values)
            *frame_len = ppm_frame_length;

        /* good if we got any channels */
        result = (*num_values > 0);
    }

    irqrestore(state);

    return result;
}

从源码中我们看到,数组 r_page_raw_rc_input中所存放的并不仅仅是接收到的遥控器数据。遥控器数据仅仅是其中一部分而已。如果我们去看其定义将会更加清楚:

/**
 * PAGE 0
 *
 * Static configuration parameters.
 */
static const uint16_t    r_page_config[] = {
    [PX4IO_P_CONFIG_PROTOCOL_VERSION]    = PX4IO_PROTOCOL_VERSION,
#ifdef CONFIG_ARCH_BOARD_PX4IO_V2
    [PX4IO_P_CONFIG_HARDWARE_VERSION]    = 2,
#else
    [PX4IO_P_CONFIG_HARDWARE_VERSION]    = 1,
#endif
    [PX4IO_P_CONFIG_BOOTLOADER_VERSION]    = 3,    /* XXX hardcoded magic number */
    [PX4IO_P_CONFIG_MAX_TRANSFER]        = 64,    /* XXX hardcoded magic number */
    [PX4IO_P_CONFIG_CONTROL_COUNT]        = PX4IO_CONTROL_CHANNELS,
    [PX4IO_P_CONFIG_ACTUATOR_COUNT]        = PX4IO_SERVO_COUNT,
    [PX4IO_P_CONFIG_RC_INPUT_COUNT]        = PX4IO_RC_INPUT_CHANNELS,
    [PX4IO_P_CONFIG_ADC_INPUT_COUNT]    = PX4IO_ADC_CHANNEL_COUNT,
    [PX4IO_P_CONFIG_RELAY_COUNT]        = PX4IO_RELAY_CHANNELS,
};

当然我现在也不去研究这个数组中到底都放了些什么数据。我关心的是 ppm_buffer中的数据是怎么来的,直至数据的最源头。但是我们要知道 ppm_buffer跟 ppm_decoded_channels是分不开的。

radiolink@ubuntu:~/apm$ grep -nr ppm_buffer ./PX4Firmware/src/
./PX4Firmware/src/systemcmds/tests/test_hrt.c:90:extern uint16_t ppm_buffer[];
./PX4Firmware/src/systemcmds/tests/test_hrt.c:103:              printf("  %u\n", ppm_buffer[i]);
./PX4Firmware/src/modules/systemlib/ppm_decode.c:91:uint16_t    ppm_buffer[PPM_MAX_CHANNELS];
./PX4Firmware/src/modules/systemlib/ppm_decode.c:179:                                   ppm_buffer[i] = ppm_temp_buffer[i];
./PX4Firmware/src/modules/systemlib/ppm_decode.h:59:__EXPORT externuint16_t    ppm_buffer[PPM_MAX_CHANNELS];   /**< decoded PPM channel values */
./PX4Firmware/src/modules/px4iofirmware/controls.c:472:                 values[i] = ppm_buffer[i];
./PX4Firmware/src/drivers/stm32/drv_hrt.c:352:__EXPORT uint16_t ppm_buffer[PPM_MAX_CHANNELS];
./PX4Firmware/src/drivers/stm32/drv_hrt.c:503:                                  ppm_buffer[i] = ppm_temp_buffer[i];
./PX4Firmware/src/drivers/px4fmu/fmu.cpp:722:                           rc_in.values[i] = ppm_buffer[i];
radiolink@ubuntu:~/apm$

在这里,我们可能会觉得是源文件 ppm_decode.c是我们要找的文件,但是:

void ppm_input_decode(bool reset, unsigned count)
{
    uint16_t width;
    uint16_t interval;
    unsigned i;

    /* if we missed an edge, we have to give up */
    if (reset)
        goto error;

    /* how long since the last edge? */
    width = count - ppm.last_edge;

    if (count < ppm.last_edge)
        width += ppm.count_max;    /* handle wrapped count */

    ppm.last_edge = count;

    if (width >= PPM_MIN_START) {
        if (ppm.next_channel != ppm_decoded_channels) {
            /* ... */
        } else {
            /* frame channel count matches expected, let's use it */
            if (ppm.next_channel > PPM_MIN_CHANNELS) {
                for (i = 0; i < ppm.next_channel; i++)
                    ppm_buffer[i] = ppm_temp_buffer[i];

                ppm_last_valid_decode = hrt_absolute_time();
            }
        }

        /* reset for the next frame */
        ppm.next_channel = 0;

        /* next edge is the reference for the first channel */
        ppm.phase = ARM;

        return;
    }
radiolink@ubuntu:~/apm$ grep -nr ppm_input_decode ./PX4Firmware/src/
./PX4Firmware/src/modules/systemlib/ppm_decode.c:123:ppm_input_decode(bool reset, unsigned count)
./PX4Firmware/src/modules/systemlib/ppm_decode.h:68: *                          ppm_input_decode, used to determine how to
./PX4Firmware/src/modules/systemlib/ppm_decode.h:84:__EXPORT void               ppm_input_decode(bool reset, unsigned count);
radiolink@ubuntu:~/apm$

所以函数 ppm_input_decode根本就没有被调用。而且我们前面的 mk文件中根本就没有添加 systemlib目录。那么我们要找的源码就只能在源文件 drv_hrt.c中了。

/**
 * Handle the PPM decoder state machine.
 */
static void hrt_ppm_decode(uint32_t status)
{
    uint16_t count = rCCR_PPM;
    uint16_t width;
    uint16_t interval;
    unsigned i;

    /* if we missed an edge, we have to give up */
    if (status & SR_OVF_PPM)
        goto error;

    /* how long since the last edge? - this handles counter wrapping implicitely. */
    width = count - ppm.last_edge;

    ppm_edge_history[ppm_edge_next++] = width;

    if (ppm_edge_next >= 32)
        ppm_edge_next = 0;

    /*
     * if this looks like a start pulse, then push the last set of values
     * and reset the state machine
     */
    if (width >= PPM_MIN_START) {

        /*
         * If the number of channels changes unexpectedly, we don't want
         * to just immediately jump on the new count as it may be a result
         * of noise or dropped edges.  Instead, take a few frames to settle.
         */
        if (ppm.next_channel != ppm_decoded_channels) {
            static unsigned new_channel_count;
            static unsigned new_channel_holdoff;

            if (new_channel_count != ppm.next_channel) {
                /* start the lock counter for the new channel count */
                new_channel_count = ppm.next_channel;
                new_channel_holdoff = PPM_CHANNEL_LOCK;

            } else if (new_channel_holdoff > 0) {
                /* this frame matched the last one, decrement the lock counter */
                new_channel_holdoff--;

            } else {
                /* we have seen PPM_CHANNEL_LOCK frames with the new count, accept it */
                ppm_decoded_channels = new_channel_count;
                new_channel_count = 0;
            }

        } else {
            /* frame channel count matches expected, let's use it */
            if (ppm.next_channel > PPM_MIN_CHANNELS) {
                for (i = 0; i < ppm.next_channel; i++)
                    ppm_buffer[i] = ppm_temp_buffer[i];

                ppm_last_valid_decode = hrt_absolute_time();

            }
        }

        /* reset for the next frame */
        ppm.next_channel = 0;

        /* next edge is the reference for the first channel */
        ppm.phase = ARM;

        ppm.last_edge = count;
        return;
    }
/**
 * Handle the compare interupt by calling the callout dispatcher
 * and then re-scheduling the next deadline.
 */


static int 
hrt_tim_isr( int irq, void *context) 

    uint32_t status; 

    /* grab the timer for latency tracking purposes */ 
    latency_actual = rCNT; 

    /* copy interrupt status */ 
    status = rSR; 

    /* ack the interrupts we just read */ 
    rSR = ~status; 

ifdef HRT_PPM_CHANNEL 

    /* was this a PPM edge? */ 
     if (status & (SR_INT_PPM | SR_OVF_PPM)) { 
        /* if required, flip edge sensitivity */ 
ifdef PPM_EDGE_FLIP 
        rCCER ^= CCER_PPM_FLIP; 
endif 

         hrt_ppm_decode(status); 
    } 

endif

这个时候我们已经跟踪到中断服务函数了,在往下那就是中断初始化了。从这里我们也看到,真正的 PPM数据最后是来自 ppm_temp_buffer数组,这是由 hrt_ppm_decode函数剩下的部分代码来完成的,负责 PPM解码工作。

    switch (ppm.phase) {
    case UNSYNCH:
        /* we are waiting for a start pulse - nothing useful to do here */
        break;

    case ARM:

        /* we expect a pulse giving us the first mark */
        if (width < PPM_MIN_PULSE_WIDTH || width > PPM_MAX_PULSE_WIDTH)
            goto error;        /* pulse was too short or too long */

        /* record the mark timing, expect an inactive edge */
        ppm.last_mark = ppm.last_edge;

        /* frame length is everything including the start gap */
        ppm_frame_length = (uint16_t)(ppm.last_edge - ppm.frame_start);
        ppm.frame_start = ppm.last_edge;
        ppm.phase = ACTIVE;
        break;

    case INACTIVE:

        /* we expect a short pulse */
        if (width < PPM_MIN_PULSE_WIDTH || width > PPM_MAX_PULSE_WIDTH)
            goto error;        /* pulse was too short or too long */

        /* this edge is not interesting, but now we are ready for the next mark */
        ppm.phase = ACTIVE;
        break;

    case ACTIVE:
        /* determine the interval from the last mark */
        interval = count - ppm.last_mark;
        ppm.last_mark = count;

        ppm_pulse_history[ppm_pulse_next++] = interval;

        if (ppm_pulse_next >= 32)
            ppm_pulse_next = 0;

        /* if the mark-mark timing is out of bounds, abandon the frame */
        if ((interval < PPM_MIN_CHANNEL_VALUE) || (interval > PPM_MAX_CHANNEL_VALUE))
            goto error;

        /* if we have room to store the value, do so */
        if (ppm.next_channel < PPM_MAX_CHANNELS)
            ppm_temp_buffer[ppm.next_channel++] = interval;

        ppm.phase = INACTIVE;
        break;

    }

    ppm.last_edge = count;
    return;

    /* the state machine is corrupted; reset it */

error:
    /* we don't like the state of the decoder, reset it and try again */
    ppm.phase = UNSYNCH;
    ppm_decoded_channels = 0;

}

实际上就是对脉宽进行测量。

    关于脉宽测量,我们目前还没有必要去研究它,所以就不深入其细节了。

2.user_start 

    现在,我们就来看看 ppm_input函数是如何被调用的。

void
controls_tick() {

    uint16_t rssi = 0;

#ifdef ADC_RSSI
    if (r_setup_features & PX4IO_P_SETUP_FEATURES_ADC_RSSI) {
        unsigned counts = adc_measure(ADC_RSSI);
        if (counts != 0xffff) {
            /* use 1:1 scaling on 3.3V ADC input */
            unsigned mV = counts * 3300 / 4096;

            /* scale to 0..253 */
            rssi = mV / 13;
        }
    }
#endif

    perf_begin(c_gather_dsm);
    uint16_t temp_count = r_raw_rc_count;
    bool dsm_updated = dsm_input(r_raw_rc_values, &temp_count);
    if (dsm_updated) {
        r_raw_rc_flags |= PX4IO_P_STATUS_FLAGS_RC_DSM;
        r_raw_rc_count = temp_count & 0x7fff;
        if (temp_count & 0x8000)
            r_raw_rc_flags |= PX4IO_P_RAW_RC_FLAGS_RC_DSM11;
        else
            r_raw_rc_flags &= ~PX4IO_P_RAW_RC_FLAGS_RC_DSM11;

        r_raw_rc_flags &= ~(PX4IO_P_RAW_RC_FLAGS_FRAME_DROP);
        r_raw_rc_flags &= ~(PX4IO_P_RAW_RC_FLAGS_FAILSAFE);

    }
    perf_end(c_gather_dsm);

    perf_begin(c_gather_sbus);

    bool sbus_status = (r_status_flags & PX4IO_P_STATUS_FLAGS_RC_SBUS);

    bool sbus_failsafe, sbus_frame_drop;
    bool sbus_updated = sbus_input(r_raw_rc_values, &r_raw_rc_count, &sbus_failsafe, &sbus_frame_drop, PX4IO_RC_INPUT_CHANNELS);

    if (sbus_updated) {
        r_status_flags |= PX4IO_P_STATUS_FLAGS_RC_SBUS;

        rssi = 255;

        if (sbus_frame_drop) {
            r_raw_rc_flags |= PX4IO_P_RAW_RC_FLAGS_FRAME_DROP;
            rssi = 100;
        } else {
            r_raw_rc_flags &= ~(PX4IO_P_RAW_RC_FLAGS_FRAME_DROP);
        }

        if (sbus_failsafe) {
            r_raw_rc_flags |= PX4IO_P_RAW_RC_FLAGS_FAILSAFE;
            rssi = 0;
        } else {
            r_raw_rc_flags &= ~(PX4IO_P_RAW_RC_FLAGS_FAILSAFE);
        }

    }

    perf_end(c_gather_sbus);

    /*
     * XXX each S.bus frame will cause a PPM decoder interrupt
     * storm (lots of edges).  It might be sensible to actually
     * disable the PPM decoder completely if we have S.bus signal.
     */
    perf_begin(c_gather_ppm);
    bool ppm_updated = ppm_input(r_raw_rc_values, &r_raw_rc_count, &r_page_raw_rc_input[PX4IO_P_RAW_RC_DATA]);
    if (ppm_updated) {

        r_status_flags |= PX4IO_P_STATUS_FLAGS_RC_PPM;
        r_raw_rc_flags &= ~(PX4IO_P_RAW_RC_FLAGS_FRAME_DROP);
        r_raw_rc_flags &= ~(PX4IO_P_RAW_RC_FLAGS_FAILSAFE);
    }
    perf_end(c_gather_ppm);

    /* limit number of channels to allowable data size */
    if (r_raw_rc_count > PX4IO_RC_INPUT_CHANNELS)
        r_raw_rc_count = PX4IO_RC_INPUT_CHANNELS;

    /* store RSSI */
    r_page_raw_rc_input[PX4IO_P_RAW_RC_NRSSI] = rssi;

我以为 PX4仅仅支持 ppm跟 sbus,但从这里我们知道,其实 PX4还支持另外一种 dsm输入。当然,采用那种输入方式并不是我们现在所关心的。我们现在关系的是谁调用了 controls_tick函数。

radiolink@ubuntu:~/apm$ grep -nr controls_tick ./PX4Firmware/src/
./PX4Firmware/src/modules/px4iofirmware/controls.c:145:controls_tick() {
./PX4Firmware/src/modules/px4iofirmware/px4io.h:217:extern voidcontrols_tick(void);
./PX4Firmware/src/modules/px4iofirmware/px4io.c:354:            controls_tick();
radiolink@ubuntu:~/apm$
int user_start(int argc, char *argv[])
{
    /* ... */
    
    for (;;) {

        /* track the rate at which the loop is running */
        perf_count(loop_perf);

        /* kick the mixer */
        perf_begin(mixer_perf);
        mixer_tick();
        perf_end(mixer_perf);

        /* kick the control inputs */
        perf_begin(controls_perf);
        controls_tick();

user_start函数是 IO的 init进程,这个前面我们已经分析过了。所以,最后是由 IO的主循环对 controls_tick函数进行调用。

    以上就是 IO中遥控器的输入。说完了输入,我们还得说说输出。这个我们稍后再来看。

转载于:https://www.cnblogs.com/eastgeneral/p/10879615.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

PX4 IO [14] serial [转载] 的相关文章

  • px4自定义mavlink收不到消息的问题

    px4版本1 12稳定版 最近在做px4二次开发相关工作 按照网上的一些教程自定义了一个mavlink消息用来控制无人机 按照教程里面的单独开了一个xml来定义消息 最后生成的消息在px4端通过流传输的方式自己写的客户端可以收到消息 但是客
  • PX4 SITL Gazebo 仿真时 libgazebo_multirotor_base_plugin 插件运行时出错

    PX4 SITL Gazebo 仿真时 libgazebo multirotor base plugin 插件运行时出错 问题描述原因分析解决办法总结 问题描述 在 Gazebo 中进行 PX4 的软件在环仿真时 xff0c 执 make
  • Ubuntu20.04+MAVROS+PX4+Gazebo保姆级安装教程

    Ubuntu20 04 43 MAVROS 43 PX4 43 Gazebo 安装PX4步骤安装MAVROS安装QGCPX4仿真 安装PX4步骤 从github上clone源码 span class token function git s
  • PX4+Offboard模式+代码控制无人机起飞(Gazebo)

    参考PX4自动驾驶用户指南 https docs px4 io main zh ros mavros offboard cpp html 我的另一篇博客写了 键盘控制PX4无人机飞行 PX4无人机 键盘控制飞行代码 可以先借鉴本篇博客 xf
  • 基于F4/F7/H7飞控硬件和px4飞控固件的廉价自主无人机系统(1)-飞控

    前言 穿越机F4 F7 H7飞控是一系列采用stm32系列F4xx和F7xx处理器的飞控的统称 xff0c 是目前穿越机爱好者非常喜欢使用的飞控硬件 xff0c 其价格也非常便宜180 xff5e 410 而px4则是一款常见的开源飞控固件
  • PX4 ---- Mixer

    文章目录 Mixer 混合控制 作用输入输出装载混控文件MAVROS代码解析总结示例MAINAUX Mixer 混合控制 作用 经过位置控制和姿态控制后 xff0c 控制量通过 actuator controls发布 xff0c 其中 co
  • PX4 ---- Indoor Flight

    文章目录 室内飞行ROS amp PX4Pose Data 飞机配置MAVROS 基于工训赛 VIO 飞行总结 室内飞行 ROS amp PX4 Pose Data 飞机配置 VIO 参考此处 xff0c 采用 T265 配置 相机与飞控机
  • PX4模块设计之五:自定义MAVLink消息

    PX4模块设计之五 xff1a 自定义MAVLink消息 1 MAVLink Dialects1 1 PX4 Dialects1 2 Paprazzi Dialects1 3 MAVLink XML File Format 2 添加自定义M
  • PX4模块设计之十一:Built-In框架

    PX4模块设计之十一 xff1a Built In框架 1 Nuttx Built In框架2 PX4 Built In框架2 1 NSH Built In关联文件2 2 NSH Built In关联文件生成2 3 NSH Built In
  • PX4模块设计之十七:ModuleBase模块

    PX4模块设计之十七 xff1a ModuleBase模块 1 ModuleBase模块介绍2 ModuleBase类介绍3 ModuleBase类功能介绍3 1 模块入口3 2 模块启动3 3 模块停止3 4 状态查询3 5 任务回调3
  • PX4模块设计之十八:Logger模块

    PX4模块设计之十八 xff1a Logger模块 1 Logger模块简介2 模块入口函数2 1 主入口logger main2 2 自定义子命令Logger custom command2 3 日志主题uORB注册 3 重要实现函数3
  • PX4模块设计之四十三:icm20689模块

    PX4模块设计之四十三 xff1a icm20689模块 1 icm20689模块简介2 模块入口函数2 1 主入口icm20689 main2 2 自定义子命令custom command2 3 模块状态print status 重载 3
  • PX4-4-任务调度

    PX4所有的功能都封装在独立的模块中 xff0c uORB是任务间数据交互和同步的工具 xff0c 而管理和调度每个任务 xff0c PX4也提供了一套很好的机制 xff0c 这一篇我们分享PX4的任务调度机制 我们以PX4 1 11 3版
  • Px4源码框架结构图

    此篇blog的目的是对px4工程有一个整体认识 xff0c 对各个信号的流向有个了解 xff0c 以及控制算法采用的控制框架 PX4自动驾驶仪软件 可分为三大部分 xff1a 实时操作系统 中间件和飞行控制栈 1 NuttX实时操作系统 提
  • px4无人机常识介绍(固件,px4等)

    专业名词解释 aircraft 任何可以飞或者可以携带物品还是搭载旅客的飞行器统称为飞机 航空器 uav 无人驾驶飞机 vehicle 飞行器 airplane plane aero plane 有机翼和一个或多个引擎的飞行器统称为飞机 D
  • PX4中自定义MAVLink消息(记录)

    简单记录一下这个过程 一 自定义uORB消息 这一步比较简单 xff0c 首先在msg 中新建ca trajectory msg文件 uint64 timestamp time since system start span class t
  • PX4飞控的PPM接收机

    xff08 一 xff09 原理图 xff1a PX4飞控的PPM输入捕获由协处理器完成 xff0c 接在A8引脚 xff0c 对应Timer1的通道1 xff08 二 xff09 PPM协议 xff1a PPM的每一帧数据间隔为20ms
  • PX4——Range Finder 篇

    Range Finder 此处选用的是 Benewake 下的 Lidar 参数设置 General Configuration 除了官方的参数设置外 xff0c 我在 EKF2 中还找到了 EKF2 RNG AID 参数 xff0c 用来
  • python serial模块

    安装注意 xff1a 1 easy install 是无法安装 提示找不到serial 2 可以通过exe文件安装 xff0c 不过网上的exe多数是针对win32操作系统的 3 最保险的安装方式 https pypi python org
  • 飞行姿态解算(三)

    继之前研究了一些飞行姿态理论方面的问题后 又找到了之前很流行的一段外国大神写的代码 来分析分析 第二篇文章的最后 讲到了文章中的算法在实际使用中有重大缺陷 大家都知道 分析算法理论的时候很多情况下我们没有考虑太多外界干扰的情况 原因是很多情

随机推荐

  • python学习笔记(7)数据类型转换

    转载于 https www cnblogs com wuzm p 11533108 html
  • 性能实战分析-问题分析(三)

    问题四 xff1a 数据库连接池不释放 搭e6mall需要使用tomcat7搭建 过程 xff1a 压测一个商品的详情页请求 xff0c 看看报错如何 xff1f 按照上面方法分析 1 先访问tomcat的初始页面 xff0c 可以访问 x
  • 解决Navicat无法连接到MySQL的问题

    解决Navicat无法连接到MySQL的问题 问题一 xff1a 本地IP xff08 xxx xxx xxx xxx xff09 没有访问远程数据库的权限 于是下面开启本地IP xff08 xxx xxx xxx xxx xff09 对远
  • Linux下用于查看系统当前登录用户信息的4种方法

    https www cnblogs com weijiangbao p 7868965 html 转载于 https www cnblogs com wuzm p 11377948 html
  • python学习

    https www cnblogs com dinghanhua tag python default html page 61 2 转载于 https www cnblogs com wuzm p 11381519 html
  • python学习笔记(8)迭代器和生成器

    迭代器 迭代是Python最强大的功能之一 xff0c 是访问集合元素的一种方式 迭代器是一个可以记住遍历的位置的对象 迭代器对象从集合的第一个元素开始访问 xff0c 直到所有的元素被访问完结束 迭代器只能往前不会后退 迭代器有两个基本的
  • 基于立体视觉和GPU加速的视觉里程系统(VINS)

    注意 xff1a 本文只适用于 Kerloud SLAM Indoor无人机产品 Kerloud SLAM Indoor配备有Nvidia TX2模块和Intel Realsense D435i立体摄像头 凭借更强大的GPU内核 xff0c
  • python学习笔记(9)函数(一)

    定义一个函数 你可以定义一个由自己想要功能的函数 xff0c 以下是简单的规则 xff1a 函数代码块以 def 关键词开头 xff0c 后接函数标识符名称和圆括号 任何传入参数和自变量必须放在圆括号中间 xff0c 圆括号之间可以用于定义
  • python学习笔记(10)函数(二)

    xff08 函数的参数 amp 递归函数 xff09 一 函数的参数 Python的函数定义非常简单 xff0c 但灵活度却非常大 除了正常定义的必选参数外 xff0c 还可以使用默认参数 可变参数和关键字参数 xff0c 使得函数定义出来
  • python学习笔记(2)数据类型-字符串

    字符串是 Python 中最常用的数据类型 我们可以使用引号 39 或 34 来创建字符串 创建字符串很简单 xff0c 只要为变量分配一个值即可 例如 xff1a var1 61 39 Hello World 39 var2 61 34
  • python学习笔记(11)文件操作

    一 读文件 读写文件是最常见的IO操作 Python内置了读写文件的函数 xff0c 用法和C是兼容的 读写文件前 xff0c 我们先必须了解一下 xff0c 在磁盘上读写文件的功能都是由操作系统提供的 xff0c 现代操作系统不允许普通的
  • 作业2

    作业2 xff1a 写一个随机产生138开头手机号的程序 1 输入一个数量 xff0c 产生xx条手机号 prefix 61 39 138 39 2 产生的这些手机号不能重复 转载于 https www cnblogs com wuzm p
  • mysql索引详细介绍

    博客 xff1a https blog csdn net tongdanping article details 79878302 E4 B8 89 E3 80 81 E7 B4 A2 E5 BC 95 E7 9A 84 E5 88 86
  • 作业1

    作业一 xff1a 写一个登录的程序 xff0c 1 最多登陆失败3次 2 登录成功 xff0c 提示欢迎xx登录 xff0c 今天的日期是xxx xff0c 程序结束 3 要检验输入是否为空 账号和密码不能为空 4 账号不区分大小写 im
  • 常用的SQL优化

    转自 xff1a https www cnblogs com Cheney222 articles 5876382 html 一 优化 SQL 语句的一般步骤 1 通过 show status 命令了解各种 SQL 的执行频率 MySQL
  • B+tree

    https www cnblogs com nullzx p 8729425 html 简介 xff1a 本文主要介绍了B树和B 43 树的插入 删除操作 写这篇博客的目的是发现没有相关博客以举例的方式详细介绍B 43 树的相关操作 xff
  • Mysql监控调优

    一 Mysql性能介绍 1 什么是Mysql xff1f 它有什么优点 xff1f MySQL是一个关系型数据库管理系统 xff0c 由瑞典MySQL AB公司开发 xff0c 目前属于Oracle公司 MySQL是一种关联数据库管理系统
  • [云讷科技] Kerloud PX4飞控的EKF2程序导航

    一 介绍 EKF拓展卡尔曼滤波器是px4开源飞控框架采用的核心状态估计方法 xff0c EKF2是px4飞控中的对应的软件模块 xff0c 可以支持各类传感器信号 xff0c 包括IMU xff0c 磁感计 xff0c 激光测距仪 xff0
  • 第5.4节 Python函数中的变量及作用域

    一 函数中的变量使用规则 函数执行时 xff0c 使用的全局空间是调用方的全局空间 xff0c 参数及函数使用的局部变量存储在函数单独的局部名字空间内 xff1b 函数的形参在函数中修改了值时 xff0c 并不影响调用方本身的数据 xff0
  • PX4 IO [14] serial [转载]

    PX4 IO 14 serial PX4 IO 14 serial 转载请注明出处 更多笔记请访问我的博客 xff1a merafour blog 163 com 2014