只有当 Minicom 在 macOS 上运行时,才能与 Arduino 进行串行通信

问题描述 投票:0回答:1

我的 macOS 系统和 Arduino 设备之间遇到串行通信问题。除非 minicom 正在运行,否则我的 Rust 和 Python 脚本都无法向 Arduino 发送消息。以下是问题的详细描述:

问题总结

  • 环境:macOS(mac硅胶M3 max)、Arduino、Rust、Python
  • 串口:/dev/cu.usbmodem101
  • 波特率:9600
  • 行为:
  • 当 minicom 未运行时:Rust 和 Python 脚本都无法成功向 Arduino 发送消息。 arduino RX 灯会亮起,但内置 LED 闪烁 3 次,这不是预期的行为。
  • 当 minicom 运行时:Rust 和 Python 脚本都可以正常工作,并且可以向 Arduino 发送具有预期结果的消息。
  • 即使不使用 minicom,只需从 Arduino IDE 中的 SerialMonitor 发送正确的 json 即可完美工作。

来自 Tauri 应用程序的 Rust 片段。

// Prevents additional console window on Windows in release, DO NOT REMOVE!!
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
use serialport::SerialPort;
use std::time::Duration;
use serde::Serialize;
#[cfg(feature = "hardware-support")]
use std::fs::File;
#[tauri::command]
fn get_temperature() -> Result<f32, String> {
    #[cfg(feature = "hardware-support")]
    {
        // Path to the temperature sensor's device file
        let path = "/sys/bus/w1/devices/28-01191ee2142f/w1_slave"; // Replace '28-xxxx' with your sensor's ID
        let mut file = File::open(path).map_err(|e| e.to_string())?; // Convert the error to a String;

        let mut contents = String::new();
        file.read_to_string(&mut contents).map_err(|e| e.to_string())?;

        // The temperature data is usually at the end of the second line, after 't='
        let temp_str = contents.split_whitespace().last().unwrap().split("=").nth(1).unwrap();
        let temp_raw: i32 = temp_str.parse().unwrap();

        // Convert raw temperature to Celsius
        Ok(temp_raw as f32 / 1000.0)
    }

    #[cfg(not(feature = "hardware-support"))]
    {
        println!("Hardware support is not enabled. Temp running in stub mode.");
        Ok(69.69)
    }
}


#[derive(Serialize)]
struct BlinkData {
    blinks: u8,
}

#[derive(Serialize)]
struct BlinkMessage {
    message_type: String,
    data: BlinkData,
}


#[tauri::command]
fn send_blink_message(port_name: &str, num_blinks: u8) -> Result<(), String> {
    // Open the serial port
    let mut port = serialport::new(port_name, 9600).open().expect("Failed to open port");

    // Create the JSON message
    let message = BlinkMessage {
        message_type: String::from("blink_led"),
        data: BlinkData { blinks: num_blinks },
    };

    // Serialize the message to JSON
    let json_message = match serde_json::to_string(&message) {
        Ok(json) => json,
        Err(e) => return Err(format!("Failed to serialize message: {}", e)),
    };

    // Send the JSON message over the serial port
    if let Err(e) = port.write_all(json_message.as_bytes()) {
        return Err(format!("Failed to write to port: {}", e));
    }

    // Print the JSON message to the console for debugging
    println!("JSON Message Sent: {}", json_message);

    // Add a newline to indicate the end of the message
    if let Err(e) = port.write_all(b"\n") {
        return Err(format!("Failed to write newline to port: {}", e));
    }

    Ok(())
}


fn main() {
    tauri::Builder::default()
        .invoke_handler(tauri::generate_handler![get_temperature, send_blink_message])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}

带有大量串行特定设置的 Python 示例。

import serial
import json
import time

def configure_serial_port(port_name):
    ser = serial.Serial(
        port=port_name,
        baudrate=9600,
        bytesize=serial.EIGHTBITS,
        parity=serial.PARITY_NONE,
        stopbits=serial.STOPBITS_ONE,
        timeout=10,
        xonxoff=False,
        rtscts=False,
        dsrdtr=False
    )
    
    ser.dtr = False
    ser.rts = False
    ser.close()

def send_blink_message(port_name, num_blinks):
    try:
        # Configure the serial port settings
        configure_serial_port(port_name)

        # Open the serial port
        ser = serial.Serial(port_name, 9600, timeout=10)

        # Add a short delay to ensure the Arduino is ready to receive the message
        time.sleep(0.1)

        # Create the JSON message
        message = {
            "message_type": "blink_led",
            "data": {"blinks": num_blinks}
        }

        # Serialize the message to JSON
        json_message = json.dumps(message)

        # Print the JSON message for debugging
        print("JSON Message:", json_message)

        # Send the JSON message over the serial port
        print("Sending JSON message...")
        ser.write(json_message.encode('utf-8'))

        # Add a newline to indicate the end of the message
        print("Sending newline...")
        ser.write(b"\n")

        # Flush the port to ensure all data is sent
        print("Flushing port...")
        ser.flush()

        # Add a delay to ensure everything is sent before exiting the function
        time.sleep(0.1)

        print("Message sent to Arduino")

        ser.close()
        return True

    except serial.SerialException as e:
        print(f"Failed to open port: {e}")
        return False

if __name__ == "__main__":
    port_name = "/dev/cu.usbmodem101"  # Change this to your port
    num_blinks = 3  # Set the number of blinks
    send_blink_message(port_name, num_blinks)

这是草图

#include <ArduinoJson.h>

// Define the built-in LED pin
const int ledPin = LED_BUILTIN;

void setup() {
  // Initialize the built-in LED pin as an output
  pinMode(ledPin, OUTPUT);

  // Start the serial communication at 9600 baud rate
  Serial.begin(9600);
}

void loop() {
  // Check if there is any data available on the serial port
  if (Serial.available() > 0) {
    // Read the incoming serial data
    String incomingMessage = Serial.readStringUntil('\n');
    
    // Parse the JSON message
    StaticJsonDocument<200> jsonDoc;
    DeserializationError error = deserializeJson(jsonDoc, incomingMessage);
    
    // Check if parsing was successful
    if (!error) {
      // Extract the message type and blinks value
      const char* message_type = jsonDoc["message_type"];
      int blinks = jsonDoc["data"]["blinks"];
      
      // Check if the message type is 'blink_led'
      if (strcmp(message_type, "blink_led") == 0) {
        // Blink the LED the specified number of times
        for (int i = 0; i < blinks; i++) {
          digitalWrite(ledPin, HIGH); // Turn the LED on
          delay(500); // Wait for 500 milliseconds
          digitalWrite(ledPin, LOW); // Turn the LED off
          delay(500); // Wait for 500 milliseconds
        }
      }
    } else {
      // If parsing failed, print an error message
      Serial.println("Failed to parse JSONS");
    }
  }
}

问题

  1. 为什么脚本只有在 minicom 运行时才起作用?
  2. minicom 可能设置哪些特定配置或状态,我需要在脚本中复制?
  3. 如何调整 Rust 和 Python 代码以在不需要运行 minicom 的情况下工作?

我在 ChatGPT 上花了很多时间、很多天来解决这个问题。来自知识渊博的人的任何见解或建议将不胜感激。谢谢!

python rust arduino serial-port tauri
1个回答
0
投票

问题在于 Arduino 没有等待足够长的时间来准备接收串行数据。在打开串行端口和发送数据之间添加 2 秒延迟解决了该问题。大概首先打开 minicom(您可以运行它并仍然使用端口),通过让 Arduino 准备好接收数据来解决问题。 2 秒似乎很长一段时间,这可能是我接下来要解决的问题。

© www.soinside.com 2019 - 2024. All rights reserved.