Independent and Simultaneous Tasks (ESP-IDF FreeRTOS)

Nespressif
Posts: 76
Joined: Tue Sep 12, 2017 11:25 am

Independent and Simultaneous Tasks (ESP-IDF FreeRTOS)

Postby Nespressif » Tue Jul 13, 2021 9:57 am

Good morning, I want to move two servo motors simultaneously but independently. To do this I have thought of creating a task for each one and tie them to a core each one. In this way, I understand that having the same priority they must be executed simultaneously and independently.

What I don't have clear is how to activate both tasks simultaneously from the timer. The idea is that when the timer that controls the duration of the movement is started, both tasks are started at the same time. I could do it by means of a notification, but I would have to do it first to one and then to the other. Or I could notify to one and from this first one notify to the other, I don't know if the movement would start at the same time.

Perhaps the most appropriate would be to use the Event Groups.

Please, if someone can explain me how to do this in the best way, I have used notifications, Semaphores, event groups, message queues...but I don't see what tools to use to achieve this.

Thanks in advance.
Last edited by Nespressif on Thu Sep 21, 2023 6:30 am, edited 1 time in total.

ESP_Sprite
Posts: 9739
Joined: Thu Nov 26, 2015 4:08 am

Re: Independent and Simultaneous Tasks (RTOS)

Postby ESP_Sprite » Wed Jul 14, 2021 1:07 am

There's no such thing as 'at the same time', as a processor can only do one thing at a time, so it can't really start two motors simultaneously. As such, you'd need to ask: how much delay is acceptable in my use case? If it's microseconds, better to integrate both in one task so you can start them as close together as possible. If it's milliseconds, it's perfectly OK to execute the bit of the tasks that start the motor sequentially. If you give them the same priority, they will switch execution every FreeRTOS tick (1ms minimum) but I'd imagine starting a servo takes less time than that to begin with, so you'd likely have less delay.

Nespressif
Posts: 76
Joined: Tue Sep 12, 2017 11:25 am

Re: Independent and Simultaneous Tasks (RTOS)

Postby Nespressif » Wed Jul 14, 2021 8:25 am

ESP_Sprite wrote:
Wed Jul 14, 2021 1:07 am
There's no such thing as 'at the same time', as a processor can only do one thing at a time, so it can't really start two motors simultaneously. As such, you'd need to ask: how much delay is acceptable in my use case? If it's microseconds, better to integrate both in one task so you can start them as close together as possible. If it's milliseconds, it's perfectly OK to execute the bit of the tasks that start the motor sequentially. If you give them the same priority, they will switch execution every FreeRTOS tick (1ms minimum) but I'd imagine starting a servo takes less time than that to begin with, so you'd likely have less delay.
I understand what you are saying and thank you very much for your response. But I thought that the dual-core processor could run two tasks at the same time, since the FreeRTOS API allows to tie each task to a certain core (PRO or APP) when they are created. I thought that by creating an EventGroup object and the processor changing a bit in this object, both tasks would be started at the same time in independent threads...as far as I can see, this is not the case.

Thanks again.

Nespressif
Posts: 76
Joined: Tue Sep 12, 2017 11:25 am

Re: Independent and Simultaneous Tasks (RTOS)

Postby Nespressif » Fri Aug 18, 2023 11:32 am

Hi, I wonder if with the new MCPWM driver version 5.1 I could use the synchronisation of two PWM signals (that move the two servos of a turret, horizontal and vertical servo) to improve the synchronisation of the turret movement.
Thanks from advance

https://github.com/espressif/esp-idf/bl ... ple_main.c

Nespressif
Posts: 76
Joined: Tue Sep 12, 2017 11:25 am

Re: Independent and Simultaneous Tasks (RTOS)

Postby Nespressif » Thu Sep 21, 2023 6:29 am

Good morning everyone, sorry for reopening this post, the thing is that seeing this video https://youtu.be/fBWu8sCuat4?si=uoCsErB2rurPCQ1K, I return to the idea of being able to move two servos simultaneously using two different tasks, each tied to a different core.

If I use SoC with dual core, like ESP32 or ESP32-S3, it should be possible. And also synchronize both tasks to start at the same time.

I haven't tried it yet but I'm going to do it as soon as I can, I don't use Arduino IDE, I use ESP_IDF and with ESP_IDF FreeRTOS, I think it can be done.

If anyone can comment on this, I would really appreciate it.

Thanks in advance.

ESP_Sprite
Posts: 9739
Joined: Thu Nov 26, 2015 4:08 am

Re: Independent and Simultaneous Tasks (ESP-IDF FreeRTOS)

Postby ESP_Sprite » Thu Sep 21, 2023 7:01 am

Okay, I'm going to be very clear here: If you need to notify two tasks, do not worry about the fact that they are not notified or do not run at exactly the same time. You have a 240MHz CPU here, the time it takes for the notification to take place (or even for the task to entirely complete) is zero when looked at from the timescale of a mechanical servo that starts moving: slack in the servo gears most likely will account for more variability than the speed of starting the tasks.

Nespressif
Posts: 76
Joined: Tue Sep 12, 2017 11:25 am

Re: Independent and Simultaneous Tasks (ESP-IDF FreeRTOS)

Postby Nespressif » Thu Sep 21, 2023 8:35 am

ESP_Sprite wrote:
Thu Sep 21, 2023 7:01 am
Okay, I'm going to be very clear here: If you need to notify two tasks, do not worry about the fact that they are not notified or do not run at exactly the same time. You have a 240MHz CPU here, the time it takes for the notification to take place (or even for the task to entirely complete) is zero when looked at from the timescale of a mechanical servo that starts moving: slack in the servo gears most likely will account for more variability than the speed of starting the tasks.
Ok, as you tell me that the two tasks do not start at exactly the same tick, it is not relevant and I understand that, because that time is invaluable.

But right now, I send the order to move each servo within the same task, first the horizontal servo and then the vertical servo. In this way if I try to make a slower movement introducing delays, I observe small jumps in the laser light that moves that servo tower. Therefore, what I want to do is to execute the movement of each servo separately, each one in a different task and that they are executed in different cores. In this way, I want to get an independent movement in both servos and thus have a more fluid laser movement at low speed.

Thanks you so much

MicroController
Posts: 1708
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Independent and Simultaneous Tasks (ESP-IDF FreeRTOS)

Postby MicroController » Fri Sep 22, 2023 11:18 am

(Not really thread-safe, but as an idea:)

Code: Select all

struct ServoMove {
  volatile uint8_t target;
  volatile uint8_t increment;
};


ServoMove servos[NUM_SERVOS] = {};


void servoMoverTask(void*) {
  while(1) {

    for( int i = 0; i < NUM_SERVOS; ++i ) {
      const uint8_t target = servos[i].target;
      const uint8_t increment = servos[i].increment;
      
      const uint8_t currPos = getCurrentServoPosition(i);
      
      if(currPos != target) {
        uint8_t newPos = target;
        
        if(increment != 0) {
          if(currPos > target) {
            if(currPos - target > increment) {
              newPos = currPos + increment;
            }
          } else {
            if(target - currPos > increment) {
              newPos = currPos - increment;
            }
          }
        }
        
        setServoPosition(newPos);
      }
    }
    
    vTaskDelay(1);
  }
  
}



void startServoMove(const uint8_t servo, const uint8_t targetPos, const uint8_t speed ) {
  // There's a race condition here which can be removed by using e.g. a critical section.
  servos[servo].target = targetPos; // Initiate new move.  
  servos[servo].increment = speed;
}

Nespressif
Posts: 76
Joined: Tue Sep 12, 2017 11:25 am

Re: Independent and Simultaneous Tasks (ESP-IDF FreeRTOS)

Postby Nespressif » Tue Sep 26, 2023 12:47 pm

MicroController wrote:
Fri Sep 22, 2023 11:18 am
(Not really thread-safe, but as an idea:)

Code: Select all

struct ServoMove {
  volatile uint8_t target;
  volatile uint8_t increment;
};


ServoMove servos[NUM_SERVOS] = {};


void servoMoverTask(void*) {
  while(1) {

    for( int i = 0; i < NUM_SERVOS; ++i ) {
      const uint8_t target = servos[i].target;
      const uint8_t increment = servos[i].increment;
      
      const uint8_t currPos = getCurrentServoPosition(i);
      
      if(currPos != target) {
        uint8_t newPos = target;
        
        if(increment != 0) {
          if(currPos > target) {
            if(currPos - target > increment) {
              newPos = currPos + increment;
            }
          } else {
            if(target - currPos > increment) {
              newPos = currPos - increment;
            }
          }
        }
        
        setServoPosition(newPos);
      }
    }
    
    vTaskDelay(1);
  }
  
}



void startServoMove(const uint8_t servo, const uint8_t targetPos, const uint8_t speed ) {
  // There's a race condition here which can be removed by using e.g. a critical section.
  servos[servo].target = targetPos; // Initiate new move.  
  servos[servo].increment = speed;
}
Thanks so much MicroController, but I think it is not the idea that I have to move each servo in an independent task that runs on each core, I think I have not explained well. Anyway, I thank you very much for taking the trouble to answer.

MicroController
Posts: 1708
Joined: Mon Oct 17, 2022 7:38 pm
Location: Europe, Germany

Re: Independent and Simultaneous Tasks (ESP-IDF FreeRTOS)

Postby MicroController » Tue Sep 26, 2023 8:40 pm

it is not the idea that I have to move each servo in an independent task that runs on each core
Indeed, it's not. It's an alternative suggestion on how to control any number of servos simultaneously from a single dedicated task. One or more other tasks or ISRs can asynchronously give "commands" to the servos by calling startServoMove() and all servos will move at the same time, each at its own prescribed speed until it stops at its target position or receives another command.
An approach like this is more efficient than creating one task per servo and scales to more servos than you have PWM channels with virtually no increment in RAM or CPU use.
But I may also have misunderstood the actual issue.

Who is online

Users browsing this forum: ESP_Sprite and 123 guests