Arduino 从不断更新的文件中读取

5 投票
1 回答
3319 浏览
提问于 2025-04-18 16:19

我在想,能不能帮我解决一个问题,这个问题我自己完全不知道怎么处理。这样也能让我的高中学生们看到Stackoverflow是个多么棒的资源。

我的学生们正在用Arduino制作一个天气灯,能够实时检测天气。他们用一个Python程序通过Yahoo的API读取某个邮政编码的天气信息,并每15分钟把这些信息写入一个文件。

与此同时,我们的Arduino使用Processing来访问这个文件,把数据发送到串口,然后Arduino从串口读取数据,点亮相应的灯来显示“天气”(比如晴天时会点亮黄色LED灯)。

我们的Processing和Arduino配合得很好(它能从文件中读取数据并显示正确的灯光)。即使在Processing和Arduino环境都在运行时,手动往文件里添加数据也能正常工作。我们的Python程序也没问题,能正确地把天气信息输出到文件中。

问题是……这两个脚本不能同时运行。如果Python在进行实时更新(每15分钟检查一次天气),Processing就无法访问这个文件。文件在Python脚本完全结束之前是无法被读取的,之后我们再启动Processing环境。这就违背了实时更新的目的,也让这个项目失去了意义,因为灯光无法随着时间变化。

另外,我知道如果用Arduino的Wifi扩展板会更好,但我们没有时间和资源去购买。那个扩展板要80美元,而他们只有一周的时间来完成这个项目。

以下是代码。

文件的内容

2, 3, 4, 3, 2

2 - 晴天(点亮引脚2)...

3 - 雨天(点亮引脚3)...

Arduino代码

 void setup() { 
     // initialize the digital pins as an output.
     pinMode(2, OUTPUT);
     pinMode(3, OUTPUT);
     pinMode(4, OUTPUT);
    // Turn the Serial Protocol ON
     Serial.begin(9600);
}

void loop() {
     byte byteRead;

     /* check if data has been sent from the computer: */
     if (Serial.available()) {
         /* read the most recent byte */
         byteRead = Serial.read();
         //You have to subtract '0' from the read Byte to convert from text to a number.
         byteRead=byteRead-'0';

         //Turn off all LEDs if the byte Read = 0
         if(byteRead==0){
             //Turn off all LEDS
             digitalWrite(2, LOW);
             digitalWrite(3, LOW);
             digitalWrite(4, LOW);

         }

         //Turn LED ON depending on the byte Read.
        if(byteRead>0){
             digitalWrite((byteRead), HIGH); // set the LED on
             delay(100);
         }
     }
 }

Processing代码

import processing.serial.*;
import java.io.*;
int mySwitch=0;
int counter=0;
String [] subtext;
Serial myPort;


void setup(){
     //Create a switch that will control the frequency of text file reads.
     //When mySwitch=1, the program is setup to read the text file.
     //This is turned off when mySwitch = 0
     mySwitch=1;

     //Open the serial port for communication with the Arduino
     //Make sure the COM port is correct
     myPort = new Serial(this, "COM3", 9600);
     myPort.bufferUntil('\n');
}

void draw() {
     if (mySwitch>0){
        /*The readData function can be found later in the code.
        This is the call to read a CSV file on the computer hard-drive. */
        readData("C:/Users/Lindsey/GWC Documents/Final Projects/lights.txt");

        /*The following switch prevents continuous reading of the text file, until
        we are ready to read the file again. */
        mySwitch=0;
     }
     /*Only send new data. This IF statement will allow new data to be sent to
     the arduino. */
     if(counter<subtext.length){
        /* Write the next number to the Serial port and send it to the Arduino 
        There will be a delay of half a second before the command is
        sent to turn the LED off : myPort.write('0'); */
        myPort.write(subtext[counter]);
         delay(500);
         myPort.write('0');
         delay(100);
         //Increment the counter so that the next number is sent to the arduino.
         counter++;
     } else{
         //If the text file has run out of numbers, then read the text file again in 5 seconds.
         delay(5000);
         mySwitch=1;
     }
} 


/* The following function will read from a CSV or TXT file */
void readData(String myFileName){

     File file=new File(myFileName);
     BufferedReader br=null;

     try{
        br=new BufferedReader(new FileReader(file));
        String text=null;

        /* keep reading each line until you get to the end of the file */
        while((text=br.readLine())!=null){
            /* Spilt each line up into bits and pieces using a comma as a separator */
            subtext = splitTokens(text,",");
        }
     }catch(FileNotFoundException e){
        e.printStackTrace();

     }catch(IOException e){
        e.printStackTrace();

     }finally{
        try {
            if (br != null){
                br.close();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
     }
}

Python代码

import pywapi
import time

# create a file
file = open("weatherData.txt", "w+")
file.close()

for i in range(0,10):
    weather = pywapi.get_weather_from_weather_com("90210")['current_conditions']['text']
    print(weather)

    if "rain" or "showers" in weather:
        weatherValue = "4"

    if "Sun" in weather:
        weatherValue = "2"
    if "thunder" in weather:
        weatherValue = "5"
    #elif "Cloud" in weather:
    if "Cloudy" in weather: 
        weatherValue = "3"
        print(weatherValue)

    # append the file with number
    # append with a comma after and space
    file = open("weatherData.txt","a")
    file.write(weatherValue + ", ")
    file.close()

    time.sleep(10)

1 个回答

4

其实这个编程挑战不一定要分成三部分,因为你可以使用PySerial这个模块。我以前用过这个模块,可以从网上获取数据,然后通过串口直接传给Arduino。首先,你需要按照我给的链接上的说明来安装这个模块。在你的Python程序中,你可以把代码改成这样:

import pywapi
import time
import serial #The PySerial module

# create a file
file = open("weatherData.txt", "w+")
file.close()

ser = serial.Serial("COM3", 9600) #Change COM3 to whichever COM port your arduino is in

for i in range(0,10):
    weather = pywapi.get_weather_from_weather_com("90210")['current_conditions']['text']
    print(weather)

    if "rain" or "showers" in weather:
        weatherValue = "4"

    if "Sun" in weather:
        weatherValue = "2"
    if "thunder" in weather:
        weatherValue = "5"
    #elif "Cloud" in weather:
    if "Cloudy" in weather: 
        weatherValue = "3"
        print(weatherValue)

    # append the file with number
    # append with a comma after and space
    file = open("weatherData.txt","a")
    file.write(weatherValue + ", ")
    file.close()

    #Sending the file via serial to arduino
    byte_signal = bytes([weatherValue])
    ser.write(byte_signal)

    time.sleep(10)

你甚至不需要把数据写入文件,但如果你打算以其他方式使用这个文件,程序还是应该创建同样的文件。

然后你的Arduino代码可以这样写:

int weather_pin = 0;
void setup() {
  Serial.begin(9600);
  pinMode(2, OUTPUT);
  pinMode(3, OUTPUT);
  pinMode(4, OUTPUT);
}

void loop() {
  if(weather_pin>0){
    digitalWrite(weather_pin, HIGH);
  }
}

void serialEvent() {
  digitalWrite(2, LOW);
  digitalWrite(3, LOW);
  digitalWrite(4, LOW);
  weather_pin = Serial.read();
}

这样应该就能正常工作!我在我的系统上运行得很好,但每个系统都不一样,所以如果不行的话,随时可以给我留言。如果你对代码有任何问题,也是同样的情况。作为一名高中生,我知道StackOverflow的魅力,我觉得你为孩子们做的事情真是太棒了。祝你在制作天气灯的过程中好运!

撰写回答