You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于红外的Arduino双板通信故障排查求助

Arduino红外通信故障排查与修复方案

核心问题梳理

你的代码存在多处导致通信失效的问题,逐一拆解如下:

  • 串口波特率不匹配:主控代码Serial.begin(9600),从控代码Serial.begin(19200),波特率不一致会导致接收数据乱码。
  • 数据格式完全不兼容:主控发送的是完整字符串(如"0x1",包含'0'、'x'、'1'和换行符),但从控用char val = Serial.read()读取单个字符,还试图匹配case '0x1'——单个字符不可能等于4字符的字符串,完全无法触发对应逻辑。
  • 红外通信实现误解:你直接使用硬件Serial通信,但普通红外收发模块并非直接对接硬件串口,需要用专用的红外编码/解码库(如IRremote)通过数字引脚实现通信,而非复用USB串口。
  • 从控代码语法错误:else stop();的位置错误,属于if(Serial.available())的分支,但代码括号嵌套错误,会导致编译或逻辑异常。
  • 硬件引脚冲突:从控中E1=5、E2=6,同时将舵机servo_0绑定到引脚5,servo_1绑定到引脚6,同一引脚同时被电机PWM和舵机占用,会导致硬件功能异常。
  • 主控重复发送数据:多个if条件无互斥逻辑,可能同时触发多条指令发送(比如摇杆处于边界时),导致从控接收数据混乱。

修正方案与代码

1. 硬件调整

  • 主控:将红外发射模块的数据引脚连接到数字引脚3,电源接5V/GND。
  • 从控:将红外接收模块的数据引脚连接到数字引脚2,电源接5V/GND;调整舵机引脚到空闲引脚(如9、10),避免和电机引脚冲突。

2. 主控修正代码(使用IRremote库发送指令)

首先在Arduino库管理器中搜索安装IRremote库:

#include <IRremote.h>

IRsend irsend;

// 摇杆引脚
const int joystickX = A0;
const int joystickY = A1;
const int joystickS1 = A2;
const int joystickS2 = A3;

// 定义指令码(用单个字节代替字符串,避免格式问题)
const byte CMD_STOP = 0x00;
const byte CMD_FORWARD = 0x01;
const byte CMD_BACKWARD = 0x02;
const byte CMD_LEFT = 0x03;
const byte CMD_RIGHT = 0x04;
const byte CMD_SERVO1_UP = 0x05;
const byte CMD_SERVO1_DOWN = 0x06;
const byte CMD_SERVO2_UP = 0x07;
const byte CMD_SERVO2_DOWN = 0x08;

void setup() {
  pinMode(joystickX, INPUT);
  pinMode(joystickY, INPUT);
  pinMode(joystickS1, INPUT);
  pinMode(joystickS2, INPUT);
  Serial.begin(9600); // 仅用于调试,红外通信不需要这个
}

void loop() {
  int xVal = analogRead(joystickX);
  int yVal = analogRead(joystickY);
  int s1Val = analogRead(joystickS1);
  int s2Val = analogRead(joystickS2);

  byte cmd = CMD_STOP;

  // 优先判断摇杆指令(互斥逻辑)
  if (xVal > 522) {
    cmd = CMD_FORWARD;
  } else if (xVal < 500) {
    cmd = CMD_BACKWARD;
  } else if (yVal > 522) {
    cmd = CMD_RIGHT;
  } else if (yVal < 500) {
    cmd = CMD_LEFT;
  } else if (s1Val > 522) {
    cmd = CMD_SERVO1_UP;
  } else if (s1Val < 500) {
    cmd = CMD_SERVO1_DOWN;
  } else if (s2Val > 522) {
    cmd = CMD_SERVO2_UP;
  } else if (s2Val < 500) {
    cmd = CMD_SERVO2_DOWN;
  } else {
    cmd = CMD_STOP;
  }

  irsend.sendNEC(cmd, 8); // 发送NEC格式的8位指令
  delay(50); // 避免发送过于频繁
}

3. 从控修正代码(使用IRremote库接收指令)

同样安装IRremote库,调整引脚冲突:

#include <Servo.h>
#include <IRremote.h>

// 电机引脚(避免和舵机冲突)
const int E1 = 5;     // M1 Speed Control
const int E2 = 6;     // M2 Speed Control
const int M1 = 4;     // M1 Direction Control
const int M2 = 7;     // M2 Direction Control

// 舵机引脚调整到空闲引脚
Servo servo_0;
Servo servo_1;
const int SERVO_PIN1 = 9;
const int SERVO_PIN2 = 10;

int sr1 = 90; // 初始角度设为中间值
int sr2 = 90;

// 红外接收引脚
const int IR_RECEIVE_PIN = 2;
IRrecv irrecv(IR_RECEIVE_PIN);
decode_results results;

// 指令码和主控保持一致
const byte CMD_STOP = 0x00;
const byte CMD_FORWARD = 0x01;
const byte CMD_BACKWARD = 0x02;
const byte CMD_LEFT = 0x03;
const byte CMD_RIGHT = 0x04;
const byte CMD_SERVO1_UP = 0x05;
const byte CMD_SERVO1_DOWN = 0x06;
const byte CMD_SERVO2_UP = 0x07;
const byte CMD_SERVO2_DOWN = 0x08;

void stop(void) {
  digitalWrite(E1, LOW);
  digitalWrite(E2, LOW);
}

void advance(char a, char b) {
  analogWrite(E1, a);
  digitalWrite(M1, HIGH);
  analogWrite(E2, b);
  digitalWrite(M2, HIGH);
}

void back_off(char a, char b) {
  analogWrite(E1, a);
  digitalWrite(M1, LOW);
  analogWrite(E2, b);
  digitalWrite(M2, LOW);
}

void turn_L(char a, char b) {
  analogWrite(E1, a);
  digitalWrite(M1, LOW);
  analogWrite(E2, b);
  digitalWrite(M2, HIGH);
}

void turn_R(char a, char b) {
  analogWrite(E1, a);
  digitalWrite(M1, HIGH);
  analogWrite(E2, b);
  digitalWrite(M2, LOW);
}

void setup(void) {
  servo_0.attach(SERVO_PIN1, 500, 2500);
  servo_1.attach(SERVO_PIN2, 500, 2500);

  // 初始化电机引脚
  for (int i = 4; i <= 7; i++) {
    pinMode(i, OUTPUT);
  }

  // 初始化红外接收
  irrecv.enableIRIn();
  Serial.begin(9600); // 用于调试
  Serial.println("IR control ready");
}

void loop(void) {
  servo_0.write(sr1);
  servo_1.write(sr2);

  if (irrecv.decode(&results)) {
    byte cmd = results.value;
    irrecv.resume(); // 准备接收下一个指令

    switch (cmd) {
      case CMD_FORWARD:
        advance(255, 255);
        break;
      case CMD_BACKWARD:
        back_off(255, 255);
        break;
      case CMD_LEFT:
        turn_L(100, 100);
        break;
      case CMD_RIGHT:
        turn_R(100, 100);
        break;
      case CMD_STOP:
        stop();
        break;
      case CMD_SERVO1_UP:
        sr1 = constrain(sr1 + 10, 0, 180); // 限制角度在0-180
        break;
      case CMD_SERVO1_DOWN:
        sr1 = constrain(sr1 - 10, 0, 180);
        break;
      case CMD_SERVO2_UP:
        sr2 = constrain(sr2 + 10, 0, 180);
        break;
      case CMD_SERVO2_DOWN:
        sr2 = constrain(sr2 - 10, 0, 180);
        break;
      default:
        stop(); // 未知指令停止
        break;
    }
  }
}

额外注意事项

  • 确保红外模块的发射和接收头正对,避免遮挡,在有效通信距离内测试。
  • 舵机角度添加constrain限制,避免超出舵机物理范围损坏硬件。
  • 若使用的是带串口的红外模块(如HC-12转红外),则需要调整波特率一致,且发送单个字节而非字符串。

内容的提问来源于stack exchange,提问作者Kyle_3_1415

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 20:24:54