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

如何等待PyFirmata完成Arduino写入后再执行图像采集?

Arduino PWM控制LED与相机采集同步问题

我用Arduino的PWM端口控制4个LED的亮度,同时用相机采集对应设置下的LED亮度,预期PWM设为0时LED功率最小,设为1时功率最大。但采集数据的图表显示,0值附近存在强度尖峰,原因是之前点亮的LED尚未完全关闭——核心问题是无法确保Arduino完成PWM写入操作后,再执行相机采集命令。

即使延长board.pass_time()和time.sleep()的时长,问题依然存在,推测这些延迟命令在Arduino实际完成写入前就已执行,因此无效。

以下是当前使用的Python代码片段:

# Iterate over each LED
for i in range(4):

    board.pass_time(0.4)
    time.sleep(0.4)

    # Reset all pins to zero
    for j in range(4):
        led_pins[j].write(0)
    
    # Select the relevant pin
    pin = led_pins[i]
    
    # Iterate over each data value
    for j in range(N):

        print(i, j)

        # Set the power of the given LED
        pin.write(vals[j])
        board.pass_time(0.4)
        time.sleep(0.4)
        # os.wait()

        # # Start a thread to take a capture
        # thread = threading.Thread(target=take_capture_thread, args=(cam,))
        # thread.start()
        
        # # Wait to rejoin with thread
        # thread.join()
        
        # Take a capture
        for k in range(10):
            cam.issue_software_trigger()
        frame = cam.get_pending_frame_or_null()
        capture = frame.image_buffer

        # Measure the average power at the center of the image
        data[i, j] = np.average(capture[selection])

解决方案

1. 实现Arduino与主机的命令握手(最可靠)

通过串口让Arduino在完成PWM写入后,主动向主机发送确认信号,主机收到确认后再执行采集操作,从根源上保证同步。

Arduino端代码(修改后)

// 定义LED引脚
int ledPins[] = {9, 10, 11, 12};
const int PIN_COUNT = 4;

void setup() {
  Serial.begin(9600);
  // 初始化所有LED引脚为输出
  for (int i = 0; i < PIN_COUNT; i++) {
    pinMode(ledPins[i], OUTPUT);
    analogWrite(ledPins[i], 0); // 初始化为0
  }
}

void loop() {
  // 等待主机发送的命令:1字节引脚索引 + 1字节PWM值(0-255)
  if (Serial.available() >= 2) {
    int pinIndex = Serial.read();
    int pwmValue = Serial.read();
    
    // 校验引脚索引合法性
    if (pinIndex >= 0 && pinIndex < PIN_COUNT) {
      analogWrite(ledPins[pinIndex], pwmValue);
    }
    // 发送确认信号(任意字节,这里用1)
    Serial.write(1);
  }
}

主机Python代码修改

替换原代码中直接操作led_pins的逻辑,改为串口通信并等待确认:

import serial

# 初始化串口(根据你的端口调整,比如COM3或/dev/ttyUSB0)
ser = serial.Serial('COM3', 9600, timeout=1)

# Iterate over each LED
for i in range(4):
    # 重置所有LED为0,并等待确认
    for j in range(4):
        # 发送重置命令:引脚j + PWM值0
        ser.write(bytes([j, 0]))
        # 等待Arduino确认
        while ser.in_waiting == 0:
            pass
        ser.read() # 读取确认字节
    
    # Iterate over each data value
    for j in range(N):
        print(i, j)
        # 将0-1的vals[j]转为0-255的PWM值
        pwm_val = int(vals[j] * 255)
        # 发送PWM设置命令:引脚i + PWM值
        ser.write(bytes([i, pwm_val]))
        # 等待Arduino完成写入的确认
        while ser.in_waiting == 0:
            pass
        ser.read()

        # 执行相机采集
        for k in range(10):
            cam.issue_software_trigger()
        frame = cam.get_pending_frame_or_null()
        if frame is not None:
            capture = frame.image_buffer
            data[i, j] = np.average(capture[selection])

ser.close()

2. 优化相机采集逻辑

即使Arduino同步完成,相机可能还残留之前的帧,可通过以下方式优化:

  • 采集前多触发几次并丢弃早期帧,只保留最后1-2帧
  • 对连续采集的多帧取平均值,降低噪声和残留影响

3. 避免使用board.pass_time()(若使用的是PyFirmata)

如果使用PyFirmata库,board.pass_time()是让Arduino执行延迟,但主机端不会等待Arduino完成延迟。改用上述握手方式,彻底替代依赖延迟的不可靠同步。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 08:35:55