实时绘图传感器数据 Python Raspberry pi

时间:2020-12-23 14:30:23

标签: python matplotlib raspberry-pi sensors

我有一个 BNO055 传感器通过 I2C 协议连接到我的 Raspberry Pi。 该传感器可以输出9个测量值,包括所有3个轴的加速度。(x,y,z)

我想要实时绘制 x_acceleration 作为时间的函数。

我正在尝试在我的 Raspberry Pi 上为一个项目运行此代码。

def animate(i,t_updt,f,sp1,sensor1):
    initialtime = time.perf_counter()
    lastTime = initialtime;
    times=np.array([])
    x=np.array([])
    while(1): 
        currentTime = time.perf_counter()
        if  (currentTime - lastTime >= 1/f):
            lastTime = currentTime
            times = np.append(times,lastTime - initialtime)
            sens1Acc = sensor1.acceleration     
            x = np.append(x,sens1Acc[0])       
        if len(times) == t_updt*f:
            break
    #Clear and draw new values   
    sp1.clear()
    sp1.plot(times,x)
    sp1.set_title('X - accel - sensor1')
    sp1.set_ylim([-10,10])
import adafruit_bno055
import time
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.animation as animation
import datetime as dt
from busio import I2C
from board import SDA, SCL
from time import sleep

##Creating sensor1 object
sensor1 = adafruit_bno055.BNO055_I2C(i2c,40)
sensor1.mode = adafruit_bno055.NDOF_MODE
sleep(2) # wait for system to stabilize

f=50 #Sampling freq

fig = plt.figure()
sp1 = fig.add_subplot(1,1,1)       

ani = animation.FuncAnimation(fig, animate, fargs=(5,f,sp1,sensor1),interval=1000)
plt.show()


如您所见,我已经实现了每 1 秒调用一次的 animate 函数。 在这个函数的运行过程中,有一个while循环运行了5秒(因为传递了fargs[0]参数),其中我们以50hz的速率采样了5秒的数据。

我唯一的问题是: 图不更新。 我已经打印出来并看到 x 值确实得到了更新,但情节本身并没有更新......

有什么想法吗?

1 个答案:

答案 0 :(得分:1)

我在 Pi 上使用传感器测量温度和湿度,在读取点时捕获时间/纪元 总体思路

  1. 读取传感器并返回传感器数据字典的包装类,包括时间/纪元
  2. Pi 上的控制器,使用包装类并将数据发布到 RESTful API(烧瓶)
  3. 活动实时更新网页(使用 AJAX 和 ChartJS

PiSensor.py
import os, platform
import time, datetime, random
try:
    import Adafruit_DHT
except ImportError:
    plat = "{sys}.{mc}".format(sys=platform.system(), mc=platform.machine())
    if (plat == "Linux.armv7l"):
        raise
    else:
        print(f"Adafruit_DHT not supported on this platform {plat}")
from typing import (Tuple, Optional)

try:
    DHT_SENSOR = Adafruit_DHT.DHT11
except NameError:
    pass
DHT_PIN = 17


#----------------------------------------------------------------
#   Note:
#       ds18b20's data pin must be connected to pin7.
#----------------------------------------------------------------

class PiSensor:
    __hostname = ""
    __latitude = 1.3740981993768249
    __longitude = 103.85034994827384

    def __init__(self) -> None:
        self.__hostname = os.uname()[1].split(".")[0]

    def set_gps(self, latitude:float, longitude:float) -> None:
        self.__latitude = latitude
        self.__longitude = longitude

    def get_gps(self) -> Tuple[float, float]:
        return self.__longitude, self.__latitude

    def sensorData(self, id:str, temp:float, humidity:Optional[float]=None) -> list:
        data = [{"id":id, "time":datetime.datetime.now().strftime("%I:%M:%S%p"),
                "value":temp, "hostname":self.__hostname, "epoch":int(time.time()*1000),
                "latitude":self.__latitude, "longitude":self.__longitude, "type":"temperature"}]
        if humidity is not None:
            data2 = data[0].copy()
            data2["id"] = data2["id"] + "_humidity" # type: ignore
            data2["value"] = humidity
            data2["type"] = "humidity"
            data.append(data2)

        return data

    # Reads temperature from sensor and prints to stdout
    # id is the id of the sensor
    def readSensor(self, id:str) -> list:
        with open("/sys/bus/w1/devices/"+id+"/w1_slave") as tfile:
            text = tfile.read()
        secondline = text.split("\n")[1]
        temperaturedata = secondline.split(" ")[9]
        temperature = float(temperaturedata[2:])
        temperature = temperature / 1000

        return self.sensorData(id, temperature)


    # Reads temperature from all sensors found in /sys/bus/w1/devices/
    # starting with "28-...
    def readSensors(self) -> list:
        count = 0
        data:list = []
        for file in os.listdir("/sys/bus/w1/devices/"):
            if (file.startswith("28-")):
                data += self.readSensor(file)
                count+=1
        if (count == 0):
            print("No sensor found! Check connection")


        humidity, temp = Adafruit_DHT.read_retry(DHT_SENSOR, DHT_PIN)
        if humidity is not None and temp is not None:
            data += self.sensorData("DHT11", temp, humidity)
        else:
            print("oh no DHT11 not working")


        return data

控制器(只是示例代码)

def read_sensor(alive, mode:int, ser:SerialInterface, config) -> None:
    sess = requests.Session()
    sensor = PiSensor()

    logenv.alog().info("thread started... sleeping {s}".format(s=config["sensorsleep"]))

    data += sensor.readSensors()

    try:
        resp = sess.post("{u}/sensor_data".format(u=u), json=data, verify=False)
    except requests.exceptions.ConnectionError:
        # maybe one of servers has gone down....
        logenv.alog().warning("no data sent {u} not alive".format(u=u))
    finally:
        sess.close()
        logenv.alog().info("shutting down thread")

烧瓶 API

@app.route('/sensor_data', methods=['POST'])
def sensor_data() -> str:
    c = mycache()
    dfsensor = c.get("dfsensor")
    newsensor = json_normalize(request.get_json())
    newsensor[["x","y"]] = newsensor[["epoch", "value"]]
    newsensor["xy"] = newsensor[['x', 'y']].agg(pd.Series.to_dict, axis=1)
    newsensor["amin"] = newsensor["value"]
    newsensor["amax"] = newsensor["value"]
    newsensor = newsensor.drop(columns=["x","y"])

    # add new data from serial interface to start of list (append old data to new data).
    # default time as now to new data
    dfsensor = newsensor.append(dfsensor, sort=False)
    # keep size down - only last 500 observations
    c.set("dfsensor", dfsensor[:500])
    del dfsensor

    return jsonify(result={"status":"ok"})

# used in conjnction with AJAX functionality in home.html template
@app.route('/serial_json', methods=['GET'])
def serial_json() -> Response:
    type = request.args.get("type", "temperature")
    freq = request.args.get("freq", "")
    graphtype = request.args.get("graphtype")

    df = mycache().get("dfsensor{f}".format(f=freq))
    df = df[df["type"]==type] # type: ignore

    # resample data down to proportion of data set and defined number of points
    if "sensorcookie" in request.cookies:
        ck = json.loads(urllib.parse.unquote(request.cookies.get("sensorcookie")))
        if not "pointsslider" in ck:
            ck = {"pointsslider": 100, "pointstoplot":20, **ck}
    else:
        ck = {"pointsslider": 100, "pointstoplot":20}
    df, min_epoch, max_epoch = sensor_ts.resample_for_plot(df, int(ck["pointsslider"]), int(ck["pointstoplot"]))

    extdata = restdata_source.tickdata(df=df, required="graph", graphtype=graphtype)
    del df
    resp = make_response(jsonify(result={"data":extdata}))
    ck = {"min_epoch":int(min_epoch), "max_epoch":int(max_epoch), **ck}
    resp.set_cookie("sensorcookie", json.dumps(ck))

    return resp

相关问题