Carbon225 / esp32-dshot

DSHOT600 driver with command support for ESP-IDF
MIT License
18 stars 1 forks source link

Initializing Multiple Drivers #3

Open VTeselkin opened 1 year ago

VTeselkin commented 1 year ago

How can I initialize and control the speed of several motors? If I do as in the example below, then the motors do not work. FLESC.install(GPIO_NUM_16, RMT_CHANNEL_0); FRESC.install(GPIO_NUM_18, RMT_CHANNEL_1); FLESC.init(); FRESC.init(); FLESC.setReversed(false); FRESC.setReversed(false); If you comment out any line with initialization ХХESC.init(); then one of the remaining motors will work ... I don’t understand what the mistake is ...

Carbon225 commented 1 year ago
  1. Unfortunately, it seems to be an issue with my implementation.
  2. If you are comfortable with writing ESP-IDF code, you could fix this issue and submit a PR.
  3. Below I describe the exact issue. Over the weekend I will try to write and test some code.

The issue is here:

esp_err_t DShotRMT::install(gpio_num_t gpio, rmt_channel_t rmtChannel)
{
    _rmtChannel = rmtChannel;

    rmt_config_t config;

    config.channel = rmtChannel;
    config.rmt_mode = RMT_MODE_TX;
    config.gpio_num = gpio;
    config.mem_block_num = 1;
    config.clk_div = 7;

    config.tx_config.loop_en = false;
    config.tx_config.carrier_en = false;
    config.tx_config.idle_level = RMT_IDLE_LEVEL_LOW;
    config.tx_config.idle_output_en = true;

    DSHOT_ERROR_CHECK(rmt_config(&config));

    return rmt_driver_install(rmtChannel, 0, 0);
}

My assumption was that the RMT driver was smart enough to initialize correctly for multiple channels. It would seem that is not the case and the second esc.install(...) fails. Could you wrap it in ESP_ERROR_CHECK() and see if it throws an error? Here is the documentation for the IDF version I originally wrote this code for: link.

A proper solution would be to migrate to the new IDF v5 API: link. It has a new function rmt_new_rx_channel which should work well with multiple channels. Frankly, this new v5 IDF has messed up a lot of my projects using other system APIs.

So then if you want, please submit a PR. Otherwise, I will try to work on this next week.

VTeselkin commented 1 year ago

There are no initialization errors. Today I experimented and managed to start all 4 motors. But there is a strange startup initialization scheme. I'll post my work a little later.

Carbon225 commented 1 year ago

Great! I'm trying to update to the new v5 IDF version. I would love to hear how you managed to solve this.

Carbon225 commented 1 year ago

Could it be that you had to send throttle commands in parallel to all motors? If you ran the init function with wait=True in sequence for each motor then I believe the first motor would disarm after not receiving commands while the second was arming. The solution would be to create 1 task per motor.

VTeselkin commented 1 year ago

After the standard initialization, the first second (not necessarily a second) I passed the estimated speed FLESC_speed, FRESC_speed, etc. to the motors. (at the same time, only one motor started working), then I sent the minimum value MIN_THROTTLE (0x48) to all motors, and after a second I started transmitting the calculated speed values again ... all the motors started to rotate and respond to speed changes ... The solution is strange, but working I don't understand why it works like this...

Carbon225 commented 1 year ago

I would try this:

The trick seems to be arming.

Carbon225 commented 1 year ago

Your solution seems to work because sending min throttle arms the ESCs. My solution is just a simplified version.

Carbon225 commented 1 year ago

send min throttle (48) to all motors for about a second (ESCs should arm and beep)

Like this:

while time elapsed < 1s {
    for each motor {
        motor.sendThrottle(48)
    }
    delay 1 tick (!!!)
}