Stap 15: Design - luisteren
In deze sectie zullen we werken aan de ontvanger-software, die zal praten met een ontvanger XBee en erachter te komen wat de sensorgegevens betekent. Ik zal de code schrijven in python die een vrij-gemakkelijk is te gebruiken scripttaal. Het draait op alle OS's en heeft amandel van tutorials online. Google AppEngine gebruikt het ook, dus het is een goede tijd om te leren!
Dit hele gedeelte wordt ervan uitgegaan dat u slechts 1 zender en 1 ontvanger, meestal te maken gemakkelijker om te gaan met graphing. In de volgende sectie zullen we in meer sensoren binden, wanneer we naar het dataloggen deel!
Ruwe analoge ingang
We beginnen door gewoon ruwe gegevens van de XBee ophalen en het uitchecken. De pakketindeling voor XBees is gepubliceerd, maar in plaats van het wroeten rond in het, ik gebruik gewoon de handige XBee bibliotheek geschreven voor python. Met het, kan ik concentreren op de gegevens in plaats van bytes tellen en het berekenen van controlesommen.
Gebruik van de bibliotheek, eerst de pyserial -module gebruiken om open te stellen een seriële poort (dwz COM4 onder windows, / dev/ttyUSB0 onder mac/linux/etc) je kunt kijken de XBee projectpagina voor informatie over hoe om erachter te komen welke COM-poort die u zoekt. We verbinden op de standaard-baudrate voor XBees, die 9600 is en pakketten zoeken
importeren van xbee xbee
seriële importeren
SERIALPORT = "COM4" # de com/seriële poort de XBee is aangesloten op
BAUDRATE = 9600 # de baud-rate, we met de xbee praten
# open te stellen de FTDI seriële poort om de gegevens die worden verzonden naar xbee
ser seriële =. Serieel (SERIALPORT, BAUDRATE)
ser.Open()
terwijl juist:
# grijpen een pakket uit de xbee of time-out
Packet = xbee.find_packet(ser)
als pakket:
Xb = xbee(packet)
Print xb
U deze code uitvoert, krijgt u de volgende uitvoer:
< xbee {app_id: 0x83, address_16: 1, rssi: 85, address_broadcast: valse, pan_broadcast: valse, total_samples: 19, digitale: [[-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1 , -1, -1, -1, -1], [-1, -1 , -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1 , -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1 , -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1 , -1, -1 , -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1 , -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1 , -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1, -1], [-1, -1, -1, -1, -1, -1, -1, -1 , -1], [-1 , -1, -1, -1, -1, -1, -1, -1, -1]], analog: [[190, -1, -1, -1, 489, -1], [109, -1, -1, -1, 484, -1], [150, -1, -1, -1, 492, -1], [262, -1, -1, -1, 492 , -1], [423, -1, -1, -1, 492, -1], [589, -1, -1, -1, 492, -1], [740, -1, -1, -1, 492, -1], [843, -1, -1, -1, 492, -1], [870, -1, -1, -1 , 496, -1], [805, -1, -1, -1, 491, -1], [680, -1, -1, -1, 492, -1], [518, -1, -1, -1, 492, -1], [349, -1, -1, -1, 491, -1], [199, -1, -1, -1, 491, -1], [116, -1, -1, -1, 468, -1], [108, -1, -1, -1, 492, -1], [198, -1, -1, -1, 492, -1], [335, -1, -1, -1, 492, -1], [523, -1, -1, -1, 492 -1]]} >
die zullen wij opnieuw formatteren om te maken een beetje meer leesbaar
< xbee {}
app_id: 0x83,
address_16: 1,
RSSI: 85,
address_broadcast: False
pan_broadcast: False
total_samples: 19,
digitale: [[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1],
[-1, -1, -1, -1, -1, -1, -1, -1, -1]],
analoge: [[190 -1, -1, -1, 489, -1],
[109, -1, -1, -1, 484, -1],
[150 -1, -1, -1, 492, -1],
[262, -1, -1, -1, 492, -1],
[423, -1, -1, -1, 492, -1],
[589, -1, -1, -1, 492, -1],
[740, -1, -1, -1, 492, -1],
[843, -1, -1, -1, 492, -1],
[870, -1, -1, -1, 496, -1],
[805, -1, -1, -1, 491, -1],
[680, -1, -1, -1, 492, -1],
[518 -1, -1, -1, 492, -1],
[349, -1, -1, -1, 491, -1],
[199, -1, -1, -1, 491, -1],
[116, -1, -1, -1, 468, -1],
[108, -1, -1, -1, 492, -1],
[198 -1, -1, -1, 492, -1],
[335 -1, -1, -1, 492, -1],
[523, -1, -1, -1, 492, -1]]
} >
OK nu haar duidelijk wat hier gebeurt. Eerste af, we krijgen sommige gegevens zoals de ID van de zender (address_16) en signaalsterkte (RSSI). Het pakket vertelt ons ook hoeveel monster zijn beschikbaar (19). Nu, de digitale monsters zijn alle -1 omdat we niet vragen om te worden verzonden. De bibliotheek nog ingevuld hen tho dus dat is waarom de niet-gegevens. Het tweede stuk is 19 soorten analoge gegevens, variërend van 0 tot 1023. Zoals u kunt zien, het eerste monster (#0) en vijfde monster (#4) echte gegevens bevatten, de rest is -1. Dat komt overeen met het gedeelte van de hardware waar wij setup AD0 en AD4 onze spanning en de huidige sensoren.
Wij zullen onze code aanpassen zodat we kunnen extraheren van deze gegevens alleen en de rest van het pakket negeren.
Deze code maakt twee matrices, voltagedata en ampdata waar wij de gegevens zal steken. We gooien het eerste monster omdat meestal ADCs een beetje wankel op het eerste monster zijn, en dan zijn goed om te gaan na die. Het wellicht niet nodig tho
#! / usr/bin/env python
seriële importeren
importeren van xbee xbee
SERIALPORT = "COM4" # de com/seriële poort de XBee is aangesloten op
BAUDRATE = 9600 # de baud-rate, we met de xbee praten
CURRENTSENSE = 4 # XBee ADC heeft stroom trekken gegevens
VOLTSENSE = 0 # welke XBee ADC heeft lichtnet spanning gegevens
# open te stellen de FTDI seriële poort om de gegevens die worden verzonden naar xbee
ser seriële =. Serieel (SERIALPORT, BAUDRATE)
ser.Open()
terwijl juist:
# grijpen een pakket uit de xbee of time-out
Packet = xbee.find_packet(ser)
als pakket:
Xb = xbee(packet)
#print xb
# we zullen alleen opslaan n-1 monsters omdat het ene is meestal verknald
voltagedata = [-1] * (len(xb.analog_samples) - 1)
ampdata = [-1] * (len (xb.analog_samples) -1)
# Pak 1 thru n van de ADC-lezingen, verwijzen naar de ADC-constanten zijn
# en bewaar ze in mooie kleine matrices
voor ik in range(len(voltagedata)):
voltagedata [i] = xb.analog_samples[i+1][VOLTSENSE]
ampdata [i] = xb.analog_samples[i+1][CURRENTSENSE]
Afgedrukt van voltagedata
Afgedrukt van ampdata
Onze gegevens is nu makkelijker om te zien:
Voltage: [672, 801, 864, 860, 755, 607, 419, 242, 143, 108, 143, 253, 433, 623, 760, 848, 871, 811]
Stroom: [492, 492, 510, 491, 492, 491, 491, 491, 492, 480, 492, 492, 492, 492, 492, 492, 497, 492]
Merk op dat de spanning schommels van ongeveer 100 tot 900, sinusoidally.
Normaliseren van de gegevens
Volgende zal tot we 'normaliseren' de gegevens. De spanning moet van-170 naar +170 die de werkelijke spanning op de lijn, in plaats van 100 tot 900 die is net wat de ADC leest gaan. Om dat te doen zullen we krijgen van de gemiddelde waarde van de grootste en kleinste lezing en het aftrekken van alle monsters. Na dat, zullen we de huidige metingen alsmede, om de nummers op de huidige loting in Amperes gelijke normaliseren.
#! / usr/bin/env python
seriële importeren
importeren van xbee xbee
SERIALPORT = "COM4" # de com/seriële poort de XBee is aangesloten op
BAUDRATE = 9600 # de baud-rate, we met de xbee praten
CURRENTSENSE = 4 # XBee ADC heeft stroom trekken gegevens
VOLTSENSE = 0 # welke XBee ADC heeft lichtnet spanning gegevens
# open te stellen de FTDI seriële poort om de gegevens die worden verzonden naar xbee
ser seriële =. Serieel (SERIALPORT, BAUDRATE)
ser.Open()
terwijl juist:
# grijpen een pakket uit de xbee of time-out
Packet = xbee.find_packet(ser)
als pakket:
Xb = xbee(packet)
#print xb
# we zullen alleen opslaan n-1 monsters omdat het ene is meestal verknald
voltagedata = [-1] * (len(xb.analog_samples) - 1)
ampdata = [-1] * (len (xb.analog_samples) -1)
# Pak 1 thru n van de ADC-lezingen, verwijzen naar de ADC-constanten zijn
# en bewaar ze in mooie kleine matrices
voor ik in range(len(voltagedata)):
voltagedata [i] = xb.analog_samples[i+1][VOLTSENSE]
ampdata [i] = xb.analog_samples[i+1][CURRENTSENSE]
# krijgen van max en min spanning en normaliseren van de curve op '0'
# te maken van de grafiek 'AC combinatie' / ondertekend
min_v = 1024 # XBee ADC is 10 bits, dus max waarde 1023 is
max_v = 0
voor ik in range(len(voltagedata)):
Als (min_v > voltagedata[i]):
min_v = voltagedata [i]
Als (max_v < voltagedata[i]):
max_v = voltagedata [i]
# erachter te komen de 'gemiddelde' van de max en min lezingen
avgv = (max_v + min_v) / 2
# ook berekenen de piek tot piek-metingen
VPP = max_v-min_v
voor ik in range(len(voltagedata)):
#remove 'dc bias', die wij het gemiddelde noemen lezen
voltagedata [i]-= avgv
# Wij weten dat de netspanning 120Vrms = +-170Vpp
voltagedata [i] = (voltagedata [i] * MAINSVPP) / vpp
# normaliseren huidige lezingen aan ampère
voor ik in range(len(ampdata)):
# VREF is de hardcoded 'DC bias' waarde, zijn
# ongeveer 492 maar zou mooi zijn als we een of andere manier konden
# krijgen deze gegevens één keer in de zoveel tijd misschien met behulp van xbeeAPI
ampdata [i]-= VREF
# de CURRENTNORM is onze normaliserend constante
# dat converteert de ADC lezen van Ampère
ampdata [i] / = CURRENTNORM
afdrukken "spanning, in volt:", voltagedata
afdrukken "huidige, in ampère:", ampdata
We zullen dit lopen nu deze gegevens wilt ophalen, die ziet er vrij goed, er is de sinusvormige spanning die wij verwachten en de huidige is meestal bij 0 en vervolgens pieken op en neer eens in een tijdje. Opmerking dat de huidige is soms negatief maar dat is OK omdat we vermenigvuldigen met de spanning en als beide negatieve zijn het nog komt uit als een positieve kracht-draw
Spanning, in volt: [-125,-164,-170,-128,-64, 11, 93, 148, 170, 161, 114, 46,-39,-115,-157,-170,-150,-99]
Huidige, in ampère: [0.064516129032258063,-1.096774193548387, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.096774193548387,]
0,0 0,0 0,0,-0.064516129032258063, 0.0, 0.0,-0.70967741935483875, 0.0, 0.0]
Basisgegevens graphing
Tot slot, ik ga een hele hoop meer code waarmee de numpy graphing modules wilt maken van een mooie grafiek van onze gegevens toevoegen. Merk op dat u wilt installeren van de wxpython en numpy, alsmede matplotlib!
Op dit punt, de code krijgt waaay te groot om te plakken hier dus grijpen "wattcher.py Mains grafiek" vanaf de downloadpagina!
Stormloop op en u moeten zien een graph-venster pop omhooggaand met een mooie sinusvormige spanning grafiek en verschillende gegevens van de stroomsterkte. Deze eerste grafiek is een voorbeeld van een laptop aangesloten. U ziet dat het een switch levering, en alleen macht tijdens de piek van de curve van de spanning trekt.
Laat nu proberen aan te sluiten in een 40W gloeilamp. U zult merken dat in tegenstelling tot de switch levering, de huidige de spanning bijna perfect volgt. Dat is omdat een gloeilamp alleen een weerstand is!
Tot slot laat proberen de meter op een dimbare switch steken. U zult zien dat de spanning '', niet langer sinusvormige gehakt is. En hoewel de huidige de spanning volgt, zijn nog steeds vrij goed bijpassende.
Graphing vermogen!
OK netjes, zijn allemaal leuk om te kijken golfvormen maar wat wij-echt willen - is de watt gebruikt. Vergeet niet, P = VI, ook wel bekend als watt = Voltage * huidige. We kunnen berekenen totale watt gebruikt door te vermenigvuldigen met de spanningen en stromen op elk punt van de steekproef, dan hen Samenvattend over een cyclus & om het energieverbruik per cyclus gemiddeld. Als we eenmaal Watts, zijn gemakkelijk om gewoon vermenigvuldig dat met 'tijd' om watturen!
Downloaden en stormloop naar de wattcher.py - watt grapher script van de downloadpagina
Nu kunt u kijken naar het afgelopen uur waarde van watt geschiedenis (3600 seconden gedeeld door 2 seconden per monster = 1800 monsters) In de bovenstaande afbeelding u zien kunt als ik een 40-watt gloeilamp dim. De gegevens zijn zeer 'verspreide' op zoek omdat we niet hebben gedaan low-pass filter. Als we een betere analoge sampling rate hadden, dit wellicht niet zo groot een deal, maar met slechts 17 monsters om mee te werken, precisie is een beetje moeilijk
Gedaan!
OK geweldig! Het is gelukt om gegevens lezen en parseren uit de analoge sensor-nettolading verwerken op een manier die ons zinvolle grafieken geeft. Natuurlijk, dit is geweldig voor ogenblikkelijke kennis maar -- lijkt het me leuk als we konden langere termijn opslag hebben, en ook bijhouden van meerdere sensoren. In de volgende stap zullen we dat doen door gebruik te maken van enkele gratis 'cloud computing' diensten!