我正在为学校做一个项目,我应该使用三项任务来控制一个小型机器人,一项任务是使用超声波传感器测量机器人到最近物体的距离,一项任务是控制向第三个任务发送命令的红外接收器执行命令的任务。我遇到了 IR 接收器任务的问题,主要是 IrReceiver.decode(),它应该检查是否已发出来自控制器的命令。但是,当我同时运行所有三个任务时,IrReceiver.decode() 会阻止所有三个任务,并且不会执行任何任务。如果我只使用两个任务,其中一个是 motorControl/distanceSensor 任务,另一个是 IR 任务,那么它工作得很好。我使用 HC-SR04 超声波传感器和 TSOP3823 IR 接收器以及 Arduino UNO。完整草图如下。
#include <Arduino_FreeRTOS.h>
#include <queue.h>
#include <semphr.h>
#include <IRremote.hpp>
// IR and distance sensor pins
#define TRIG_PIN 4
#define ECHO_PIN 3
#define IR_RECEIVE_PIN 7
// Motor commands
#define FORWARD 1
#define BACKWARD 2
#define STOP 0
#define LEFT 3
#define RIGHT 4
#define SPEED_LOW 5
#define SPEED_MEDIUM 6
#define SPEED_HIGH 7
// Motor pins
#define LEFT_MOTOR_PWM 5
#define LEFT_MOTOR_DIR1 9 // FORWARD
#define LEFT_MOTOR_DIR2 8 // BACKWARD
#define RIGHT_MOTOR_PWM 6
#define RIGHT_MOTOR_DIR1 10
#define RIGHT_MOTOR_DIR2 12
SemaphoreHandle_t distanceMutex;
QueueHandle_t commandQueue;
double distance = 0;
int motorCommand = 0;
int speed = 255;
int duration = 0;
void distanceSensorTask(void* pvParameters)
{
while(1)
{
xSemaphoreTake(distanceMutex, portMAX_DELAY);
digitalWrite(TRIG_PIN, LOW);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIG_PIN, LOW);
duration = pulseIn(ECHO_PIN, HIGH);
distance = (duration * 0.0340)/2; // pulse to cm
Serial.println(distance);
xSemaphoreGive(distanceMutex);
delay(100);
}
}
void IRsensorTask()
{
while(1)
{
if(IrReceiver.decode())
{
uint16_t command = IrReceiver.decodedIRData.command;
switch (command)
{
case 0x44:
motorCommand = SPEED_LOW;
break;
case 0x40:
motorCommand = SPEED_MEDIUM;
break;
case 0x43:
motorCommand = SPEED_HIGH;
break;
case 0x0C:
motorCommand = LEFT;
break;
case 0x5E:
motorCommand = RIGHT;
break;
case 0x19:
motorCommand = FORWARD;
break;
case 0x1C:
motorCommand = BACKWARD;
break;
case 0x18:
motorCommand = STOP;
break;
default:
break;
}
IrReceiver.resume();
}
delay(50);
}
}
void motorControlTask()
{
int receivedCommand;
while(1)
{
xQueueReceive(commandQueue, &receivedCommand, portMAX_DELAY); // receive command from IR sensor
xSemaphoreTake(distanceMutex, portMAX_DELAY);
if(distance < 20)
{
receivedCommand = STOP;
}
xSemaphoreGive(distanceMutex);
switch(receivedCommand)
{
case FORWARD:
Serial.print("hej");
motorForward(speed);
break;
case BACKWARD:
motorBackward(speed);
break;
case LEFT:
motorLeft(speed);
break;
case RIGHT:
motorRight(speed);
break;
case STOP:
Serial.println("stop");
motorStop();
break;
case SPEED_LOW:
speed = 76;
break;
case SPEED_MEDIUM:
speed = 153;
break;
case SPEED_HIGH:
speed = 255;
break;
default:
break;
}
delay(100);
}
}
void motorForward(int speed)
{
digitalWrite(LEFT_MOTOR_DIR1, HIGH);
digitalWrite(LEFT_MOTOR_DIR2, LOW);
analogWrite(LEFT_MOTOR_PWM, speed);
digitalWrite(RIGHT_MOTOR_DIR1, HIGH);
digitalWrite(RIGHT_MOTOR_DIR2, LOW);
analogWrite(RIGHT_MOTOR_PWM, speed);
}
void motorBackward(int speed)
{
digitalWrite(LEFT_MOTOR_DIR1, LOW);
digitalWrite(LEFT_MOTOR_DIR2, HIGH);
analogWrite(LEFT_MOTOR_PWM, speed);
digitalWrite(RIGHT_MOTOR_DIR1, LOW);
digitalWrite(RIGHT_MOTOR_DIR2, HIGH);
analogWrite(RIGHT_MOTOR_PWM, speed);
}
void motorLeft(int speed)
{
digitalWrite(LEFT_MOTOR_DIR1, HIGH);
digitalWrite(LEFT_MOTOR_DIR2, LOW);
analogWrite(LEFT_MOTOR_PWM, speed);
digitalWrite(RIGHT_MOTOR_DIR1, LOW);
digitalWrite(RIGHT_MOTOR_DIR2, LOW);
analogWrite(RIGHT_MOTOR_PWM, speed);
}
void motorRight(int speed)
{
digitalWrite(LEFT_MOTOR_DIR1, LOW);
digitalWrite(LEFT_MOTOR_DIR2, LOW);
analogWrite(LEFT_MOTOR_PWM, speed);
digitalWrite(RIGHT_MOTOR_DIR1, HIGH);
digitalWrite(RIGHT_MOTOR_DIR2, LOW);
analogWrite(RIGHT_MOTOR_PWM, speed);
}
void motorStop()
{
digitalWrite(LEFT_MOTOR_DIR1, LOW);
digitalWrite(LEFT_MOTOR_DIR2, LOW);
digitalWrite(RIGHT_MOTOR_DIR1, LOW);
digitalWrite(RIGHT_MOTOR_DIR2, LOW);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(TRIG_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
pinMode(LEFT_MOTOR_PWM, OUTPUT);
pinMode(LEFT_MOTOR_DIR1, OUTPUT);
pinMode(LEFT_MOTOR_DIR2, OUTPUT);
pinMode(RIGHT_MOTOR_PWM, OUTPUT);
pinMode(RIGHT_MOTOR_DIR1, OUTPUT);
pinMode(RIGHT_MOTOR_DIR2, OUTPUT);
distanceMutex = xSemaphoreCreateMutex();
commandQueue = xQueueCreate(10, sizeof(int));
xTaskCreate(distanceSensorTask, "distanceSensorTask", 128, NULL, 3, NULL);
xTaskCreate(IRsensorTask, "IRsensorTask", 128, NULL, 2, NULL);
xTaskCreate(motorControlTask, "motorControlTask", 128, NULL, 2, NULL);
IrReceiver.begin(IR_RECEIVE_PIN, ENABLE_LED_FEEDBACK);
vTaskStartScheduler();
}
void loop() {
}
我尝试创建三个独立的任务,其中两个只打印一些内容,而第三个任务仅在 ir 接收器使用 IrReceiver.decode() 接收到命令时才打印,并且该任务有效。所以我相信我有一些同步问题,但我似乎无法修复它。
void IRsensorTask()
{
while(1)
{
if(IrReceiver.decode())
{
uint16_t command = IrReceiver.decodedIRData.command;
switch (command)
{
// ...
}
IrReceiver.resume();
}
delay(50);
}
}
只有解码帧后,您才可以恢复任务。否则你就会陷入 while 循环中。你应该一直恢复。
我对 FreeRtos 不太熟悉,但示例没有使用延迟,而是使用 vTaskDelay,我想这是有原因的。