3. 虚谷号和Arduino的自定义通讯

3.1. 原理简介

虚谷号和板载Arduino的通讯,是通过串口来实现的。xugu库也是基于Firmata协议开发,跑在串口协议上。

3.2. 应用场景

xugu库支持的传感器主要分为两类,一是开关量(也称数字)传感器,返回高低电平;二是模拟传感器,返回0-5V之间的电压。

除了这两类的传感器,还有数字型传感器,如DH11温湿度传感器,DS18B20温度传感器。这些传感器无法使用xugu库,如果项目中用到这类传感器,就需要另写代码,自定义通讯协议。

3.3. 范例:DH11传感器实验

Arduino接DH11传感器,将数据通过串口发送给虚谷号。虚谷号使用Python代码,将串口信息打印出来。

1.Arduino代码

// Example testing sketch for various DHT humidity/temperature sensors
// Written by ladyada, public domain

#include "DHT.h"
#define DHTPIN 13     // what pin we're connected to

// Uncomment whatever type you're using!
#define DHTTYPE DHT11   // DHT 11
//#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)

// Connect pin 1 (on the left) of the sensor to +5V
// Connect pin 2 of the sensor to whatever your DHTPIN is
// Connect pin 4 (on the right) of the sensor to GROUND
// Connect a 10K resistor from pin 2 (data) to pin 1 (power) of the sensor

DHT dht(DHTPIN, DHTTYPE);

void setup() {
  Serial.begin(115200);
}

void loop() {
  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  //String cmd=serial_command();

  String cmd="";
  while(1){
    if(Serial.available()){
      cmd+=char(Serial.read());
      delay(2);

    }else{break;}
  }
  cmd.replace("\n","");
  cmd.replace("\0","");
  if(cmd=="PING"){
  Serial.print("OK");
  }
  //delay(2000);
  float h = dht.readHumidity();
  float t = dht.readTemperature();

  //lcd.clear();
  // check if returns are valid, if they are NaN (not a number) then something went wrong!
  if (isnan(t) || isnan(h)) {
    Serial.println("Failed to read from DHT");
  } else {
    Serial.print(h);
    Serial.print(t);
  }
  delay(150);
}

2.Python代码

import serial
import time
import subprocess
import os

arduino_serial=serial.Serial('/dev/ttyS1',115200)
arduino_serial.close()
time.sleep(0.5)
arduino_serial.open()
time.sleep(0.5)

def arduino_burn():
        """
        :return:
        """
        subprocess.call("arduino_burn.sh /home/scope/Desktop/DHT11/DHT11.ino /home/scope/software/log/arduino_burn_log.txt", shell=True)

def serial_send(msg):
    global arduino_serial
    msg=msg.encode("utf-8")
    arduino_serial.write(msg)
    time.sleep(0.01)

def serial_receive(pin_num = '1'):
    global arduino_serial
    receiver=arduino_serial.read_all()
    if receiver:
        if b'\0' not in receiver:
            receiver=receiver.decode("utf-8")
            if '\r\n' in receiver:
                receiver = receiver.replace('\r\n', '')
            return receiver
    else:
        return -1

def check_protocol():
    serial_send("PING")
    time.sleep(1)
    receiver=serial_receive()
    if("OK" not in str(receiver)):
        print("not found firmata protocol, burn it.")
        arduino_burn()
        print("burn complete")

def getTempandHum():
    """
    读取温度和湿度
    """
    value = serial_receive()
    if value != -1:
        humi = value[:5]
        Temp = value[-5:]
        print("温度:%s 湿度:%s%%"%(Temp,humi))

check_protocol()
while True: #创建一个循环
    getTempandHum()
    time.sleep(1)

3.4. 高级技巧

在Python代码中自动检测Arduino,并调用烧写工具。

3.5. 参考范例:灯带控制

import serial
import time
import subprocess
import os

arduino_serial=serial.Serial('/dev/ttyS1',9600)
arduino_serial.close()
time.sleep(0.5)
arduino_serial.open()
time.sleep(0.5)

def arduino_burn():
    """

    :return:
    """
    path=os.getcwd()
    subprocess.call("arduino_burn.sh /home/scope/Desktop/Neo_xugu_test/Arduino_NeoPixel/Arduino_NeoPixel.ino /home/scope/software/log/arduino_burn_log.txt", shell=True)

def serial_send(msg):
    global arduino_serial
    msg=msg.encode("utf-8")
    print(msg)
    arduino_serial.write(msg)

def serial_receive():
    global arduino_serial
    receiver=arduino_serial.read_all()
    receiver=receiver.decode("utf-8")
    return receiver

def check_protocol():
    serial_send("PING")
    time.sleep(1)
    receiver=serial_receive()
    if(receiver!="OK"):
        print("not found firmata protocol, burn it.")
        arduino_burn()
        print("burn complete")

def set_pixel(index,r,g,b):
    index=str(index)
    r=str(r)
    g=str(g)
    b=str(b)
    cmd="N"+index+"R"+r+"G"+g+"B"+b+";"
    serial_send(cmd)

check_protocol()

while True:
    a=0
    while a <8:
        for i in range(8):
            if i==a:
                set_pixel(i,200,200,0)
            else:
                set_pixel(i,0,0,0,)
        time.sleep(1)
        a+=1


if(__name__=="__main__"):
    print("please import this file to python program")