【问题标题】:Comparing data from sensors in arrays before writing a Csv file doesn't work, Raspberry Pi在写入 Csv 文件之前比较来自阵列中传感器的数据不起作用,Raspberry Pi
【发布时间】:2019-09-25 07:52:46
【问题描述】:

我正在为我的 Raspberry Pi 编写一个数据记录程序,该程序运行良好。但在 csv 文件中写入新行之前,我想检查数据是否不同,以确保我不会两次写入相同的数据。 问题是,我使用一个数组来存储新数据,并使用一个数组来存储旧数据。当它们不同时,代码将在 CSV 文件中写入新行并使新旧数据相同,然后新数据将再次更改。但由于某种原因,旧的 != new 无法查找数据是否已更改。

我尝试使用更多全局变量而不使用局部变量。我尝试使用 Values Array(所有传感器数据,也有很多 0)而不是 Info Array(活动传感器数据)。我认为这可能是一个指针问题,但我不认为 Python 使用指针。 当我在 if new != old: 循环中写下“old = new”行时。 (见代码) 它只经过一次并停止。 真正让我感到沮丧的是,当我更改传感器值并使用 CTRL + C 中断时。似乎旧的和新的总是一样的。但它们已更新为新值。 我尝试调试代码,但当我到达库时,Pi 和 Thonny 都冻结了。

######################Variables#######################
AnalogSensor = [False, True, False, False, False, True, True, True]    #8 analog inputs
AnalogSensorDelay = [1, 1, 1, 1, 1, 0.4, 2, 0.8]                       #the timing to read all of these inputs.
LoggingDelay = 1                                                       #the timing to write the Csv file
# DHT = 17 #not yet connected
Decimalen = 0                                                          #the amount of decimals after the decimal dot (1 means only logging 100th of seconds, 2 means 10th of a second. etc.)

###############Libraries##################
import time
import csv
from datetime import date
import datetime
import os.path
import Adafruit_GPIO.SPI as SPI
import Adafruit_MCP3008

###############Initial values of variables#############

name = "/media/pi/DIRK\040PI/" + str(date.today()) + ".0.csv"          #this will write a file to this path (USB stick in the pi) with the name 2019-09-25.0.csv
old = 1
new = 0
SPI_PORT   = 0
SPI_DEVICE = 0
starttime = time.time()
Sensortimer = [0]*8
values = [0]*8
Loggingtimer = 0
dataArray = [0]

###############Setup###################################

if Decimalen == 0:
    Decimalen = -1                                                    #gets rid of the decimal dot of there are no decimals.
mcp = Adafruit_MCP3008.MCP3008(spi=SPI.SpiDev(SPI_PORT, SPI_DEVICE))
data = [0]*(AnalogSensor.count(True))                                 #creates an array with the size of the amount of inputs put on True

def Filename(name):                                                   #this function changes the '2019-09-25.0.csv' name and changes the .0 to .1 .2 etc if the file already exists.
    x = 0
    while os.path.isfile(name):                                       #checks if the file exists.
        print("There was already a file named",name)
        x = x + 1                                                     #increase file number
        name = "/media/pi/DIRK\040PI/" + str(date.today()) + "." + str(x) + ".csv" 
    print("Creating file ", name)
    return name

def Writecsv(name, delay, info):                                      #writes a csv file with the name returned by the Filename function, with the delay chosen with LoggingDelay, and info is an array filled with active sensor data.
    global Loggingtimer
    global totaltime
    global starttime
    global old
    global new
    if (Loggingtimer + delay <= totaltime - starttime):              #checks if delay time has passed ( this is to bypass the sleep function and to be able to do other things )
        Loggingtimer = time.time() - starttime
        new = info                                                   #changes new to an array with the same values as info ( an array with active sensor values )
        if new != old:                                               # if new data is different from old data
            print(info)                                              # prints data in the Shell for comfort.
            write = str(datetime.datetime.now())                     ##
            write = write.split()                                    ##
            write[1] = write[1][:(9+Decimalen)]                      ##
            data = [write[0],write[1]]                               ## Creates a timestamp with 2 values, the date, and the time with chosen decimals
            for x in range((AnalogSensor.count(True))):              ## Add the data from the info array to the timestamp array to create the LOG.
                data.append(info[x])                                 ##
            with open(name,'a',newline="") as f: 
                writer = csv.writer(f)
                writer.writerow(data)                                # Write a row with the complete log
            print("Writing to file")
----------------------------------------------------------------------
#            old = new
----------------------------------------------------------------------            

def Analogread(pin, delay):                                          # This function reads the values of the MCP3008 and puts them in array Values, note. the array Values has the values of all 8 inputs, even if some inputs are disabled
    global totaltime
    global Sensortimer
    global starttime
    if (Sensortimer[pin] + delay <= totaltime - starttime):
        Sensortimer[pin] = time.time() - starttime
        values[pin] = mcp.read_adc(pin)
        return values[pin]

name = Filename(name)
while True:
    totaltime = time.time()                                          # Keeps updating the time
    y = 0
    for counter in range(8):                                         # Looks in the AnalogSensor array how many sensors are on True
        if AnalogSensor[counter] == True:
            Analogread(counter, AnalogSensorDelay[counter])          # Read the value of the inputs that are on True, ( the inputs on false will always be 0 )
            data[y] = values[counter]                                # Puts the data from the active sensors in a different array with only active sensor data
            y = y + 1
    Writecsv(name, LoggingDelay, data)                               

我希望输出类似于:

There was already a file named /media/pi/DIRK PI/2019-09-25.0.csv
There was already a file named /media/pi/DIRK PI/2019-09-25.1.csv
There was already a file named /media/pi/DIRK PI/2019-09-25.2.csv
Creating file /media/pi/DIRK PI/2019-09-25.3.csv
[7, 0, 700, 254]
Writing to file
[4, 0, 702, 254]
Writing to file
[9, 0, 697, 356]
Writing to file
[3, 0, 707, 456]
Writing to file
[2, 0, 712, 677]
Writing to file

但是之后

[7, 0, 700, 254]
Writing to file

它只是停止。没有错误。并不断更新由于某种原因保持不变的旧数据数组和新数据数组。即使 old 和 new 不同并且在 csv 文件中写入新行后,也只能将 old 更新为 new 的值。

【问题讨论】:

    标签: python arrays csv raspberry-pi


    【解决方案1】:

    我认为错误在这里,试试那个代码:

    def Analogread(pin, delay):
        global totaltime
        global Sensortimer
        global starttime
        if (Sensortimer[pin] + delay <= totaltime - starttime):
            Sensortimer[pin] = time.time() - starttime
            return mcp.read_adc(pin)
    

    改变

    Analogread(counter, AnalogSensorDelay[counter])
    data[y] = values[counter]
    

    data[y] = Analogread(counter, AnalogSensorDelay[counter])
    

    【讨论】:

    • 我试过这个,它导致(虽然仍然只写 1 行数据)[7, None, None, None] 和另一个运行 [None, None, None, None]
    【解决方案2】:

    所以我不完全确定问题出在上面的代码中, 但是在获得了更多使用 python 的经验后,我开始使用类。 这是我的数据记录器代码的第二个版本,它完美运行:D。

    import csv
    from os.path import exists
    import datetime
    import RPi.GPIO as GPIO
    from time import sleep
    from random import randrange
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    
    
    class Logger:
        path = '/home/pi/Documents/Namelogs/'
        date = str(datetime.date.today())
        fieldnames = ['date','time']
        def __init__(self, name = 'datalog.0.csv'):
           '''
           Omschrijving
            -------------------
                Deze class beschikt over alle functies die te maken hebben met het loggen van data. 
    
            Variabelen
            ----------
            path: 'string'
                Het pad waar de csv file opgeslagen gaat worden.
            date: 'string'
                De datum wanneer het programma begint.
            fieldnames: [list]
                De extra waarden die in de datalog moeten staan(behalve de data), default = datum en tijd.
            data: {dictionary}
                Hierin staat alles wat gelogd moet worden, het is een dictonary opgebouwd uit 4 keys:
                    -Data : hierin komt alle nieuwe data te staan
                    -Old : hierin komt alle oude data te staan
                    -Date : hierin komt de huidige datum te staan
                    -Time : hierin komt de huidige tijd te staan
    
            Parameters
            ----------
            name : `string`
                De naam van het bestand dat je wilt loggen, de standaard naam is datalog
    
            Alle andere helper functies:
                - log_data()
                - collect_data()
                - check_data()
                - print_data()
                - check_file()
                - check_date()
            '''
            self.data = {}
            self.name = name
            self.data['data'] = 0
    
            self.fileName = str(self.path + self.name + str(datetime.date.today()) + ".0.csv")
    
    
        def collect_data(self):
            '''
            Deze functie verzamelt de data die gelogd moet worden, de data wordt opgeslagen onder "data"
            wanneer nieuwe data gelogd wordt worden de waardes uit "data" verplaatst naar "old"
    
            De oude data kan gebruikt worden door de volgende functie:
                - check_data()
    
            '''
            self.data['old'] = self.data['data']
            data_array = {}
            for sensor in Sensor.sensorArray:
                if sensor.state:
                    data_array[sensor.name] = sensor.read_data()
            self.data['data'] = data_array
    
        def log_data(self):
            '''
            Korte Omschrijving
            ------------------
                Deze functie logt de huidige data uit de data dictionary in een csv bestand onder de naam gespecificeerd bij de class.
    
            Uitgebreide Omschrijving
            ------------------------
                Deze functie haalt de huidige datum en tijd op, en combineert dit met de data uit de data dictionary.
                Deze combineert hij in een nieuwe dictionary en hij schrijft deze weg onder de juiste headers.
                Deze headers zijn aangemaakt bij de create_file() functie.
            '''
            self.data['date'] = str(datetime.datetime.now().date())
            self.data['time'] = str(datetime.datetime.now().time())
            with open(self.fileName,'a',newline="") as f:
                writer = csv.DictWriter(f, fieldnames = Logger.fieldnames)
                writer.writerow({'date' :self.data['date'], 'time' : self.data['time'][:12], **self.data['data']})
    
        def check_data(self, compare_data = True):
            '''
            Omschrijving
            ------------
                Deze functie vergelijkt de data uit collect_data() met de oude data uit collect_data() en geeft op basis daarvan een waarde terug, zie Return.
                Deze functie kan gecombineerd worden met de log_data() functie zodat alleen verschillende data gelogd wordt.
    
            Voorbeeld
            ---------
                if logger.check_data():
                    logger.log_data()
    
            Parameters
            ----------
            compare_data : Boolean (True of False, standaard = True)
                Deze variabele bepaald of deze functie wel of niet uitgevoerd wordt.
    
            Return
            ------
            True / False: Boolean
                Deze functie geeft False terug wanneer de data het zelfde is als de oude data.
                In alle andere gevallen geeft deze functie True terug.
            '''
            if compare_data:
                if self.data['data'] == self.data['old']:
                    print("Data not logged, since data == old data")
                    return False
                else:
                    return True        
            return True
    
        def print_data(self):
            '''
            Omschrijving
            ------------
                Deze functie print de data die verzamelt is met de collect_data() functie op een nette en leesbare manier in de shell.
            '''
            print("-"*150)
            print(self.data['data'])
            print("-"*150)
    
        def create_file(self):
            '''
            Korte omschrijving
            -------------------
                Deze functie maakt het bestand met de gekoze naam aan en schrijft een header.
    
                Belangrijk! - Dit is altijd de eerste functie die aangeroepen wordt.
    
            Uitgebreide omschrijfing
            -------------------------
                Deze functie kijkt of er al een bestand is met de gekozen naam. ("gekozen naam"_"datum".0.csv)
                Als dit bestand al bestaat gaat de functie het getal in de naam aanpassen totdat er een bestandsnaam gevonden is die wel beschikbaar is.
                Zodra deze gevonden is gaat de functie een header schrijver met de datum, de tijd en alle actieve sensoren.
    
            Return
            -------
            self.fileName : 'Sting'
                De complete naam van het log bestand 
                ("gekozen naam"_"datum".x.csv)
            '''
            x = 0
            self.fileName = self.path + self.name + "_{}.{}.csv".format(str(datetime.date.today()),x)
            while exists(self.fileName):
                x+=1
                self.fileName = self.path + self.name + "_{}.{}.csv".format(str(datetime.date.today()),x)
            with open(self.fileName,'a',newline="") as f:
                writer = csv.DictWriter(f, fieldnames = Logger.fieldnames)
                writer.writeheader()
            return self.fileName
    
        def check_date(self):
            '''
            Korte omschrijving
            -------------------
                Deze functie kijkt of het een nieuwe dag is, zo ja maakt hij een nieuw bestand.
    
            Uitgebreide omschrijfing
            -------------------------
                Deze functie vergelijkt de datum wanneer het laatste bestand gemaakt is met de huidige datum,
                als deze niet het zelfde zijn wordt de create_file() functie aangeroepen die een nieuw datalog bestand maakt, zie create_file().
                waarna de datum wanneer het laatste bestand gemaakt is veranderdt wordt naar vandaag.
            '''
            dateNow = str(datetime.date.today())
            if dateNow != self.date:
                self.date = dateNow
                self.create_file()
    
    class Sensor(Logger):
        sensorArray = []
        def __init__(self, name, state, pin):
            self.name = name
            self.state = state
            self.pin = pin
    
            GPIO.setup(pin, GPIO.OUT)   
            GPIO.output(pin, state)
            if self.state:
                Logger.fieldnames.append(self.name)
                Sensor.sensorArray.append(self)
    
        def read_data(self):
            if self.name == 'digital sensor 1':
                data = randrange(2)
            else:
                data = randrange(3)*randrange(15)
            return data
    
    
    #while True:
    #    logger.collect_data()
    #    logger.check_date()
    #    logger.print_data()
    #    if logger.check_data():
    #        logger.log_data()
    #    sleep(0.2)
    

    【讨论】:

      猜你喜欢
      • 2016-09-14
      • 2021-11-02
      • 2018-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多