Task only runs once

I created 2 tasks ButtonControl and VoiceControl. At first, when there’s a voice signal, VoiceControl is created and then deleted itself. But after that, it never ran again. I really don’t know where I should fix. Here are my codes and the result on monitor.

#include <Arduino_FreeRTOS.h>
#include<String.h>
#include <SoftwareSerial.h>// thư viện này cho phép bất cứ cổng digital nào của arduino để giao tiếp theo phương thức serial
#define TX_PIN      8  //định nghĩa các chân giao tiếp với bluetooth
#define RX_PIN      7
int baudRate[] = {300, 1200, 2400, 4800, 9600, 19200, 38400, 57600, 115200}; // tốc độ giao tiếp giữa arduino và module bluetooth có thể có
SoftwareSerial bluetooth(RX_PIN, TX_PIN);
int enbA = 3;
int in1 = 5;
int in2 = 6;
int in3 = 9;
int in4 = 10;
int enbB = 11;
String chuoi ;
char kytu;

TaskHandle_t VoiceControl_1t;
TaskHandle_t ButtonControl_t;

void setup() {
  Serial.begin(9600);
  bluetooth.begin(9600);
  pinMode(in1, OUTPUT);
  pinMode(in2, OUTPUT);
  pinMode(in3, OUTPUT);
  pinMode(in4, OUTPUT);
  pinMode(enbA, OUTPUT);
  pinMode(enbB, OUTPUT);
  digitalWrite(in1, LOW);
  digitalWrite(in2, LOW);
  digitalWrite(in3, LOW);
  digitalWrite(in4, LOW);
  digitalWrite(enbA, LOW);
  digitalWrite(enbB, LOW);
  xTaskCreate(ButtonControl, "ButtonControl", 256, NULL, 2, &ButtonControl_t);
  vTaskStartScheduler();
}

void loop() {}

void ButtonControl(void *p)
{
  Serial.println("ButtonControl is running");
  for (;;)
  {
    if (bluetooth.available())
    {
      kytu = bluetooth.read();
      switch (kytu)
      {
        case '@':
          DiThang();
          break;
        case '#':
          DiLui();
          break;
        case '*':
          ReTrai();
          break;
        case '$':
          RePhai();
          break;
        case '!':
          DungLai();
          break;
        case '%':
          LuiTrai();
          break;
        case '^':
          LuiPhai();
          break;
        default:
          {
            chuoi = chuoi + kytu;
            Serial.println("This is for VoiceControl");
            Serial.println("ButtonControl deletes itself");
            xTaskCreate(VoiceControl_1, "VoiceControl_1", 256, NULL, 1, &VoiceControl_1t);
            delay(100);
            Serial.println("This is for VoiceControl nnnnnnnnnn");
            vTaskDelete(NULL);
          }
      }
    }
  }
}

void VoiceControl_1(void *p)
{
  Serial.println("VoiceControl_1 is running");
  for (;;)
  {
    while (bluetooth.available())
    {
      kytu = bluetooth.read();
      chuoi = chuoi + kytu;
    }
    if (chuoi.indexOf("đi thẳng") >= 0) {
      Serial.println("DiThang");
      DiThang();
      delay(2000);
      DungLai();
      chuoi = "";
    }
    else if (chuoi.indexOf("đi lùi") >= 0) {
      Serial.println("DiLui");
      DiLui();
      delay(1500);
      DungLai();
      chuoi = "";
    }
    else if (chuoi.indexOf("rẽ trái") >= 0) {
      Serial.println("ReTrai");
      ReTrai();
      delay(1000);
      DungLai();
      chuoi = "";
    }
    else if (chuoi.indexOf("rẽ phải") >= 0) {
      Serial.println("RePhai");
      RePhai();
      delay(1000);
      DungLai();
      chuoi = "";
    }
    else if (chuoi.indexOf("lùi phải") >= 0) {
      Serial.println("LuiPhai");
      LuiPhai();
      delay(1000);
      DungLai();
      chuoi = "";
    }
    else if (chuoi.indexOf("lùi trái") >= 0) {
      Serial.println("LuiTrai");
      LuiTrai();
      delay(1000);
      DungLai();
      chuoi = "";
    }
    else if (chuoi.indexOf("dừng lại") >= 0) {
      Serial.println("Dung");
      DungLai();
      chuoi = "";
    }
    else
    {
      chuoi = chuoi + kytu;
      Serial.println("This is for ButtonControl");
      Serial.println("VoiceControl deletes itself");
      xTaskCreate(ButtonControl, "ButtonControl", 256, NULL, 2, &ButtonControl_t);
      vTaskDelete(NULL);
    }
  }
}

I’d start checking the return codes of the FreeRTOS calls like xTaskCreate to see if the calls were successful. Maybe you’re running out of heap space to create the task.
In addition I would not recommend to create and delete tasks dynamically. It’s not efficient and you might run into resource problems. Task resources like stack and TCB are cleaned up later on by the idle task.
Why not creating both tasks once and signal an event to each task (e.g. using a task notification or a binary semaphore) to trigger the desired action ?

Thank you for helping me. I thought about using semaphore, vTaskSuspend and vTaskResume, but it couldn’t resolve my problem. If VoiceControl is delayed and I tap on a button, I want my car to move following ButtonControl. Did I miss something?

Since I don’t know what you’re trying to achieve or what exactly your bigger problem is, it’s hard to give an advice.
However, I wouldn’t recommend using vTaskSuspend/Resume for task synchronization. These functions are somewhat special and can cause a number of problems.

As you can see, there are two tasks in my code, ButtonControl with priority 2 and VoiceControl with priority 1. At first, if the received data isn’t in any cases, then I assume that data is for VoiceControl. That’s why i delete ButtonControl and create VoiceControl. Then, VoiceControl will call the function with the received data. But after each function, there is a vTaskDelay(2000) and then, function Stop(). In my code, I set up that the car ‘go straight’ in 2s, ‘turn left’ in 1s, etc, in case that there is only a voice signal. But what if I say ‘go straight’, then ‘turn left’? I dont want my car to ‘go straight’ in 2s, ‘turn left’ in 1s. It seems lag. I want my car to move following the last signal. That’s why I create VoiceControl then delete it… Up to now, I have no idea how to fix this problem. :frowning:

I still don’t fully understand, but if you want to control something (a car) depending on Bluetooth input events, why couldn’t you just do so ?
Seems a single task resp. state machine is sufficient to handle incoming events and issue the appropriate (car) action. If you need some timeouts e.g. stopping the car after 2 sec without any further input, you can realize that waiting or polling for input events the required time.
Try to keep it simple.

I dont understand what you mean. :frowning: My project is about controlling a car using button and voice via Bluetooth. When I say ‘go straight’, I want the car to go straight in 2s then stop. And I use vTaskDelay(2000) for that. But how can I handle if there is a voice signal in that 2s?

Seems you get both types of Bluetooth events by just reading them using the same interface. Then you can decide what to do. Regardless if the event was a button or voice event. It’s just an event to control the car state machine.
If there was an event to let the care run for max. 2 sec or until another event comes in, you could handle that by starting the car and e.g. setting a flag or set the state RUN of your state machine and for instance use xTaskCheckForTimeOut while polling for further Bluetooth events (see the example code how it can be used appropriately).
If the timeout happens, stop the car, reset the flag or better the state of the state machine to STOP state and continue to poll for input events. If meanwhile another event occurs, just handle it as desired by another state transition.

It’s not what I mean. I’ve already used delay() or vTaskDelay() to make my car run for a max time. All I worried is that if there was an other voice signal, the car should follow it. And after that, it should not come back to vTaskDelay().

I mean. When the car is going straight for 2s, VoiceControl is sleeping. What if there was an other voice signal? I need the VoiceControl to start again to handle it, not just wake up.

Sorry Lucy, I’m obviously not able to explain it clear enough…
Using a fixed delay to let the car run for 2 sec is the wrong approach, right ?
Because during that time you’re simply not able to process any further event. The task is blocked.
Hence on detecting a START command (either by a button or by voice, after all you just read it from the Bluetooth interface, right ?) just start the car, arm a timeout (or alternatively you could use a timer), set the state machine state to START and just proceed with polling for further input events from the Bluetooth interface like a STOP command WHILE checking for the timeout to expire.
On expiration stop the car and return to the STOP state doing the necessary things on that transition. On detecting another input event before the timeout expired e.g. a LEFT command, turn the car left and maybe re-start the timeout and set e.g. the state LEFT of the state machine and continue polling for further input events, etc.
Hope it helps - good luck :slight_smile:

1 Like