Kandidatuppsats i elektronik
Institutionen för systemteknik, Linköpings universitet, 2018
Raspberry Pi-baserad
lågeffektsmodul för
dataloggning av olika
miljöparametrar
Raspberry Pi-baserad lågeffektsmodul för dataloggning av olika miljöparametrar
Jonathan Strandberg LiTH-ISY-EX--18/0476--SE Handledare: Jacob Wikner
isy, Linköpings universitet Examinator: Jacob Wikner
isy, Linköpings universitet
Avdelningen för Elektroniska Kretsar och System Institutionen för systemteknik
Linköping University 581 83 Linköping
Sammanfattning
I detta projekt har en Raspberry pi 3 B+ konstruerats till att logga ett antal miljö-data från anslutna sensorer. De sensorer som kan anslutas innefattar:
• Regnsensor • Temperatursensor • Gassensor • Vindsensor • Ljudsensor • Kamera
Samtliga sensorer känner enheten av vid start om de är närvarande och om så kan mätdatan loggas i valfria intervall och sparas lokalt i ett .csv-kalkylark och för kameran en .jpg-fil. All loggdata säkerhetskopieras intervallsvis till ett anslu-tet USB-minne. Loggdatan är även tillgänglig för överföring via Bluetooth och Wifi. Diverse energibesparande metoder har även implementerats i form av på och avstängning för vissa hårdvarukomponenter.
Systemet är utvecklat med energikonsumption i tanken då det kommer att slås samman med ett annat projekt vars mål är att driva detta system med ett bat-teri och solceller vars energiflöden en Arduino Uno kontrollerar. Detta gör även en anslutning till Arduinon möjlig där information om soltimmar, batteriladd-ning och effektförbrukbatteriladd-ning kan överföras för utökad loggbatteriladd-ning.
Abstract
In this project a Raspberry Pi 3 B+ has been constructed to log a number of envi-ronmental data from connected sensors. The connectable sensors include:
• Rain sensor • Temperature sensor • Gas sensor • Anemometer • Sound sensor • Camera
These sensors availability are sensed at device start and the present ones are logged in settable intervals, then saved locally in a .csv-file and for the camera a .jpg-file. All log data is backed up periodically to a connected USB Flash drive. The log data is also available for transfer through Bluetooth and Wifi. A number of energy saving procedures have also been implemented in the form of powering off and on a couple of hardware components.
The system is created with energy consumption in mind as it will be merged with another system which has the goal of supporting this system with a battery and solar panels whose energy flows an Arduino Uno is controlling. This does a connection to the Arduino possible for transfer of information regarding total sun hours, battery charge and power consumption for extended logging.
Vanligt förekommande förkortningar
Förkortning Betydelse
ADC Analog/Digital Converter. Konverterar en analog spän-ningssignal till en representativ digital sådan.
I²C 2-kanals, seriellt dataöverföringsprotokoll.
SPI Serial Peripheral Interface. (4+)kanals, seriellt, fullt-duplex dataöverföringsprotokoll.
MISO Master In Slave Out. En av två unidirektionella seriella da-takanaler som används vid överföring i SPI-gränssnitt. MOSI Master Out Slave In. Den andra av de två
unidirektionel-la serielunidirektionel-la datakanaler som används vid överföring i SPI-gränssnitt.
SS, CS Slave Select, Chip Select. Signal som instruerar vilken slav som ska vara aktiv på databussen i SPI-protokoll.
CLK, SCL, SCLK, SCK
Serial Clock. En kanal i SPI- och I²C-protokoll som synkro-niserar överföringen och bestämmer hastigheten.
SDA Serial Data Line. Den bidirektionella datakanalen i I²C-protokoll
TVOC Total Volatile Organic Compounds. En samling allmänna föroreningar i luften
MSB Most Significant Bit. Biten i en serie bitar med högst vikt LSB Least Significant Bit. Biten i en serie bitar med minst vikt API Application Programming Interface. Definerar ett antal
subrutiner för kommunikation mellan olika mjukvaru-komponenter
Tabeller
2.1 Parameterflaggor och deras betydelser för funktionen bb_i2c_zip()
av biblioteket pigpio . . . 6
2.2 CCS811’s, för projektet relevanta, olika minnesregister . . . 9
2.3 CCS811’s olika körlägen för mätning . . . 9
2.4 Dataregister i AT30TSE752A . . . 13
2.5 För projektet signifikanta kamerainställningar hos Raspberry Pi Camera Module V2.1 . . . 15
2.6 De olika stödda kameraupplösningarna för Raspberry Pi Camera Module V2.1 med motsvarande inställningsvärde . . . 16
2.7 hostapd.conf inställningsmöjligheter och förklaringar . . . 18
2.8 Kommandon för hciconfig samt innebörd . . . 19
3.1 Projektets komponentlista . . . 21
Figurer
2.1 Raspberry Pi 3 GPIO-pins . . . 3
2.2 Illustrativ I²C-dataöverföring . . . 4
2.3 SPI exemplifierande kopplingsschema . . . 5
2.4 Illustrativt tidsdiagram för SPI-dataöverföring . . . 6
2.5 Grove Water sensor V1.1 och dess anslutningspins . . . 7
2.6 CCS811 gassensor och dess anslutningspins . . . 8
2.7 CCS811’s statusregisters byte-form . . . 10
2.8 CCS811’s bytearray-form för mätdata . . . 10
2.9 CCS811’s Environment Data register-utformning . . . 11
2.10 Mikrofonkretsen Pmod MIC3 av Digilent och dess anslutningspin-nar . . . 11
2.11 Temperatursensorn AT30TSE752A’s anslutningar . . . 12
2.12 MCP3202’s Anslutningar . . . 14
2.13 Raspberry Pi Camera module V2.1 . . . 15
3.1 Kopplingsschema för temperatursensorn AT30TSE752A . . . 23
3.2 Kopplingsschema för gassensorn CCS811 . . . 24
3.3 Kopplingsschema för A/D-omvandlaren MCP3202 . . . 28
3.4 Kopplingsschema för mikrofonen Digilent PmodMIC3 . . . 29
3.5 Flödesschema för periodvis loggning av miljödata . . . 36
4.1 Det färdiga systemet . . . 37
4.2 Tre testfall av olika miljösimuleringar, i den vänstra bilden simu-lerades oljud, den mittersta regn, och den högra koldioxidhaltsök-ning. Enheten för TVOC’s är här felaktigt angiven som ppm istället för ppb. . . 38
4.3 Den 3D-skrivna anemometern, ihopskruvad till vänster . . . 39
4.4 Testfall av olika vindhastigheter för anemometern . . . 39
4.5 USB-minnets innehåll efter en lyckad överföring . . . 40
4.6 Bluetoothmottagarens perspektiv vid överföring av mätdatan . . . 41
4.7 Mätdatan överförd via html över wifi . . . 41
Tabeller viii Figurer ix 1 Introduktion 1 1.1 Bakgrund . . . 1 1.2 Syfte . . . 1 1.3 Frågeställning . . . 2 1.4 Avgränsningar . . . 2 1.5 Arbetsmiljö . . . 2 2 Teori 3 2.1 Raspberry Pi . . . 3 2.2 I²C . . . 4 2.3 SPI . . . 4 2.4 PIGPIO . . . 5 2.5 Regnsensor . . . 7 2.6 Gassensor . . . 8 2.7 Mikrofon . . . 10 2.8 Temperatursensor . . . 12 2.9 Anemometer . . . 13 2.10 Analog/Digital Converter . . . 14 2.11 Kamera . . . 14 2.12 Minneshantering . . . 16 2.13 Wifi . . . 17 2.14 Bluetooth . . . 19 3 Metod 21 3.1 Komma igång med Raspberry Pi . . . 22
3.2 De digitala sensorerna . . . 22
3.2.1 Kommunikation med AT30TSE752A . . . 22
3.2.2 Kommunikation med CCS811 . . . 24
3.2.3 Kommunikation med MCP3202 . . . 27 x
3.2.4 Läsning av Digilent PmodMIC3 . . . 28 3.2.5 Bildtagning . . . 29 3.3 Anemometerkonstruktion . . . 30 3.4 Trådlös nätverkspunkt . . . 30 3.5 Blåtandsöverföring . . . 32 3.6 Dataloggning . . . 33 3.6.1 Funktionen initiate() . . . 34
3.6.2 Funktionen update_sensors(Bool Log, Bool backup) . . . . 34
3.6.3 Funktionen append_log() . . . 35
3.6.4 Skriptet Logger.py i sin helhet . . . 35
4 Resultat 37 4.1 Mätvärden . . . 38
4.2 Skrift till USB-minne . . . 40
4.3 Överföring via Bluetooth . . . 40
4.4 Aktivering via Bluetooth och överföring via wifi . . . 41
5 Diskussion 43 5.1 Arbetets gång . . . 43
5.2 Resultat och slutsatser . . . 44
5.3 Arbetet i vidare sammanhang . . . 45
Litteraturförteckning 47 A Appendix 51 A.1 Kopplingsschema . . . 52 A.2 camera.sh . . . 53 A.3 cp_to_usb.sh . . . 53 A.4 hub-off.sh . . . 53 A.5 hub-on.sh . . . 53 A.6 applauncher.sh . . . 53 A.7 i2c_bb_devices.py . . . 54 A.8 i2c_devices.py . . . 57 A.9 logger.py . . . 61 A.10 spi_devices.py . . . 67 A.11 webappl.py . . . 69 A.12 wireless_handler.py . . . 69
A.13 Android Bluetooth-applikation för test . . . 72
A.13.1 MainActivity.java . . . 72
A.13.2 activity_main.xml . . . 76
1
Introduktion
1.1
Bakgrund
I samband med ett globalt förändrande klimat till stor grund utav koldioxidut-släpp blir miljöfrågor i samhället mer och mer aktuella. CitiSense är ett projekt LiU är delaktigt i som siktar på att utveckla ett ’Participatory Risk Management System’ som handlar om att samla plats-specifik miljödata för att öka klimatbe-redskapen hos medborgare och myndigheter. Att logga olika data om miljöpara-metrar gör det möjligt att se och förutspå nuvarande samt framtida lokala klimat-förändringar som i värsta fall kan utgöra ett hot för befolkningen.
Mer information om projektet CitiSense och dess olika mål återfinns på hem-sidan https://citizensensing.itn.liu.se/.
Det finns idag redan ett antal olika nod-baserade färdiga produkter som kan utföra ungefär samma uppgift men de är relativt dyra och innehar inte den nivå av flexibilitet som behövs. Därför söker CitiSense att utveckla en egen komplett enhet för att lösa detta.
1.2
Syfte
Syftet med arbetet är att ta fram en billig och energisnål Raspberry Pi-baserad en-het för projektet CitiSense som sedan kan användas för att mäta och logga olika data relaterade till miljön. Dessa data ska även vara tillgängligt för trådlös upp-hämtning via Wifi samt Bluetooth för lokala användare. Datan ska även lagras på ett externt USB-minne kopplat till raspberryn för manuell direkt upphämtning.
1.3
Frågeställning
Uppgiften i arbetet är att konstruera en Raspberry Pi-baserad enhet för datalogg-ning av ett antal miljöparametrar, nedan listade frågor siktar projektet att efter arbetet kunna svara på.
• Hur kan ett system för loggning av miljödata realiseras så att datan kan användas för att upptäcka trender?
• Går mätdatan att göras tillgänglig för användare på flera olika och energief-fektiva sätt?
• Är mätdatan som fås av systemet tillräckligt noggrann för att upptäcka tren-der?
Utifrån dessa frågor kan en metod utvecklas för konstruktion av en enhet som uppfyller syftet med arbetet.
1.4
Avgränsningar
Framställningen av en enhet som kan logga miljödata ifrån de olika
delkompo-nenterna är i huvudfokus, därav kommer inga utförliga tester kring nivå av nog-grannhet att i projektet utforskas.
Systemets delkomponenter med deras funktionaliteter kommer inte att be-skrivas utöver vad som är absolut relevant för projektet då det annars hade varit för omfattande ur ett tidsperspektiv.
De två minimala applikationer som utformats enbart för att testa överföring av loggdatan trådlöst ifrån mottagarens perspektiv kommer inte heller att bearbe-tas i rapporten. Deras källkod refereras till istället och finns tillgänglig i appendix A.11 och A.12
1.5
Arbetsmiljö
Arbetets konstruktion har utförts i en labbsal på Linköpings Universitet. Där har med Windows-mjukvara för fjärrstyrning raspberryn kontrollerats trådlöst av en laptop. All kod har utvecklats på samma laptop i mjukvaran Atom och sedan versionshanterats med hjälp av Github som den även igenom har laddats ner till raspberryn. Till raspberryn har under projektets utförande även en I²C-display adderats för att i realtid presentera mätdata och felmeddelanden, men displayen är inte en del av den slutgiltiga produkten i sig.
2
Teori
Kapitlet behandlar teori kring de delkomponenter projektet är uppbyggt utav och de kommunikationsprotokoll som används.
2.1
Raspberry Pi
Raspberry Pi 3 B+ är i skrivande stund den senaste modellen av ett antal enkorts-datorer skapade av företaget Raspberry Pi Foundation och håller ungefär samma storlek som en smartphone[16]. Detta gör den väldigt praktisk för projekt där mobilitet och storlek spelar stor roll.
Figur 2.1: Raspberry Pi 3 GPIO-pins Ombord på Raspberryn finns många integrerade
komponenter som enkelt kan användas genom förpro-grammerade bibliotek. De för projektet relevanta kom-ponenterna behandlas senare i teorikapitlet. Precis som med andra datorer kan en Raspberry’s hårdvara kontrol-leras utav ett operativsystem. Det finns ett antal olika OS skrivna för just Raspberry Pi’s och som alla har olika för- och nackdelar. I detta arbete valdes OS’et Raspbi-an Stretch då det är ett funktionsrikt och populärt OS som många andra projekt utförts på vilket innebär att det finns många tips och exempel på internet tillgäng-ligt för underlättad problemlösning.
Raspberryn har en port om 40st pinnar man kan ansluta komponenter till. Dessa kallas GPIO-pins och går igenom raspberryn att kontrollera för olika ändamål. Några sådana beskrivs fortsättningsvis.
2.2
I²C
I²C är ett seriellt kommunikationsprotokoll tillverkat av Philips som används för informationsöverföring mellan
hårdvarukomponenter. Protokollet stödjer hastigheter i upp emot 3.4 Mbit/s om alla komponenter i det hela systemet också stödjer det[15].
Kommunikationen sker igenom två ledare - SDA (Serial Data Line) och SCL (Serial Clock) som snabbt switchar mellan +5 eller +3.3 volt, och 0 volt. Des-sa ledare finns lokaliserade på Raspberryns pins GPIO2 respektive GPIO3 (se figur 2.1). SCL är en klockpulssignal som håller systemet synkront och avgör hastigheten för överföringen. SDA är databussen där all data som överförs måste vara 8 bitar lång och följs alltid av en Acknowledge (ACK) eller Not Acknowledge (NACK) vilket signalerar sändaren att byten mottogs korrekt.
Figur 2.2:Illustrativ I²C-dataöverföring
I²C använder sig av ett Master/Slave förhållande där det med 7-bitars adres-sering ger möjligheten för 128 stycken slav-enheter. Överföring av en byte ser ut som i Figur 2.2.
Mastern börjar med att skicka en startbit, följt av adressen för slaven den vill kommunicera med på 7 bitar, direkt följt av en Read/Write bit som säger om Mas-tern vill skriva till eller läsa ifrån slaven. Därefter svarar slaven ACK genom att dra SDA-bussen låg under den 9:e klockpulsen. Om slaven inte direkt kan svara efter att ha blivit adresserad kan den hålla SCL låg tills det att den är. Detta kal-las Clock Stretching och stödjs inte av alla I²C-enheter, varav Raspberry Pi är en av dem.
Efter att adressen och R/W-biten mottagits av slaven kan den beroende på vilken operation som valdes antingen svara med en byte eller ta emot en byte, följt av en ACK ifrån mottagaren och en Stop-signal ifrån Mastern.
2.3
SPI
Serial Peripheral Interface, SPI, är också ett kommunikationsprotokoll som an-vänder sig utav ett Master/Slave förhållande. Till skillnad ifrån I²C har här mas-tern och samlingen slavar var sin dedikerad databus MOSI (Master Out Slave In) och MISO (Master In Slave Out). Det innebär att kommunikationen kan ske i full-duplex, data kan flöda i båda riktningarna samtidigt.[21]
För att slavarna ska veta vilken av dem mastern vill kommunicera med an-vänds istället för adressering på databussen en signal SS (Slave Select). Denna
2.4. PIGPIO 5 signal går låg för den slav som ska lyssna under transaktionen och hålls hög för de andra enheterna i slingan.
Figur 2.3:SPI exemplifierande kopplingsschema
Figur 2.3 exemplifierar hur en master kan kopplas ihop med 3 stycken slavar. SS1-3 väljer vilken av slavarna som ska använda databussarna för tillfället.
Precis som i I²C använder Mastern här klocksignalen SCLK för att bestämma hastigheten på överföringarna och precicera när en bit ska samplas. Det som skil-jer sig är att avläsningen istället sker på stigande eller fallande flank hos SCK, vilket bestäms av konstanten CPHA. Ytterligare bestämmer CPOL om klocksig-nalen ska börja hög eller låg.[23] Detta illustreras i Figur 2.4.
2.4
PIGPIO
För att använda gränssnitten SPI och I²C används python-biblioteket pigpio på raspberryn. Biblioteket anländer med OS’et Raspbian-stretch när det installeras. Ett minimalt python-script för att ta emot en byte från en I²C-slav med adressen 0x3c kan med användandes av pigpio se ut som i följande kodstycke:
import pigpio # Importera biblioteket
pi = pigpio.pi() # Skapa pigpio-instans för att hantera GPIO-portarna
port = 1 # Specifera vilken i I²C-port som skall användas bus = pi.i2c_open(port, 0x3c) # Öppna anslutning till slaven byte = pi.i2c_read_byte(bus) # Läs en byte ifrån slaven, placera
i ’byte’
Figur 2.4:Illustrativt tidsdiagram för SPI-dataöverföring
Biblioteket förenklar arbetet markant då användaren slipper tänka på vad som händer på hårdvarunivå.
Ett kompatibilitetsproblem mellan vissa I²C-enheter och Raspberry Pi existe-rar tyvärr. Funktionen clock-stretching som illustrerades i figur 2.2 stöds inte på Raspberry Pi. Då måste man istället vända sig till så kallad bit-banging, som inne-bär att man styr en seriell kommunikation med mjukvara istället för den dedike-rade hårdvaran. Pigpio’s bibliotek innehåller även funktioner för detta, vilket gör att för användaren blir det endast en marginell skillnad kod- och kopplingsvis[9]. Funktionenbb_i2c_zip() används i detta fall istället för både i2c_read_byte()
ochi2c_write_byte(). Detta görs genom att man ger funktionen en array
innehål-landes vad som ska överföras ochhur. Man måste här vara medveten om hur
I²C-överföringar fungerar på hårdvarunivå och matar därefter arrayen med ett antal parametrar i logisk ordning. Dessa parametrar baseras på innehållet i tabell 2.1
Parameter Betydelse
0 End, inga fler kommandon
1 Escape, nästa parameter är två bytes stor
2 Start
3 Stop
4 Address, nästa parameter är slavens adress 5 Flags, nästa två bitar är I²C-flaggor
6 Read, nästa parameter specificerar antalet bytes som ska läsas 7 Write, nästa parameter specificerar antalet bytes som ska skrivas Tabell 2.1: Parameterflaggor och deras betydelser för funktionen bb_i2c_zip() av biblioteket pigpio
2.5. REGNSENSOR 7 Utefter det kan en array för dataöverföring konstrueras och sedan matas till funktionen.
Nedan kodexempel illustrerar ett minimalt python-script för läsning av en byte ifrån en slav med bit-banging i pigpio:
import pigpio # Importera biblioteket
SDA = 22 # Specificera vilken GPIO-pin SDA ska bit-bangas på SCL = 27 # Specificera vilken GPIO-pin SCL ska bit-bangas på SPEED = 300000 # Specificera dataöverföringshastighet i hertz pi = pigpio.pi() # Skapa pigpio-instans för att hantera
GPIO-portarna
bus = pi.bb_i2c_open(SDA, SCL, SPEED) # Öppna specificerad I²C-port
addr = 0x3c # Slavens adress count = 1 # Antal bytes att läsa
# Läs en byte ifrån slaven, placera i ’byte’, felmeddelande om sådant i s
(s,byte) = pi.bb_i2c_zip(SDA,[4, addr, 2, 6, count, 3, 0]) pi.i2c_close(bus) # Stäng anslutningen
Kodstycket öppnar en I2C-anslutning till en enhet på de angivna SDA och
SCL-pinnarna i hastigheten 300KHz varefter den försöker läsacount stycken bytes
ifrån en enhet med adressen0x3c.
2.5
Regnsensor
Med ett förändrande klimat är inte bara temperaturen och koldioxidnivåerna in-tressanta. Ett klimatsystem som förändras på ett håll tenderar att ge konsekven-ser på andra håll också. Enligt SMHI har under de senaster trettio åren en tendens till mer nederbörd uppstått, som lett till att en uppseendeväckande mängd över-svämningsproblem uppstått [19]. Därav valdes det att addera en regnsensor till projektet.
Figur 2.5:Grove Water sensor V1.1 och dess anslutningspins
Regnsensorn består av 11 st ledningar på en platta (se Figur 2.5) som har en viss resistans mellan sig. När plattan blir blöt så förändrar vattnet plattans
resi-stans, och på så sätt kan man uppskatta hur blött det är. En helt torr platta ger en analog utsignal som motsvarar inspänningen, medan en helt vattentäckt platta ger en utsignal nära 0 Volt.
Plattan har 4 anslutningsnoder. GND, VCC, NC och SIG. GND ansluts till systemets GND och VCC till referensspänningen man vill använda. Utsignalen man mäter finns på SIG. NC står för Not Connected och används ej.[11]
2.6
Gassensor
Den mest aktuella miljöparametern är idag koldioxhidhalten i atmosfären. Hal-ten påverkas lokalt mycket mer dramatiskt än medeln i atmosfären då bilar och människor ger upphov till mycket utsläpp. Detta kan leda till att vissa platser har markant högre koldioxidhalt än andra, vilket gör det en intressant parameter för detta projekt.
Sensorn CCS811 valdes för att den har möjligheten att ge en noggrann mät-ning till ett ekonomiskt pris. Sensorn ger ett mätvärde inom omfånget 400 - 8192 ppm (parts per million)[22]. Detta är ett tillräckligt omfång då enligt SMHI me-delvärdet för koldioxidhalten i atmosfären över ett år övergick 400ppm redan 2015[20].
Figur 2.6:CCS811 gassensor och dess anslutningspins
I figur 2.6 kan gassensorns totalt 8 anslutningar ses. RST är en aktivt låg in-gång som ger användaren möjligheten att återställa enheten. I N T är en aktivt låg utgång som kan användas för att meddela att en mätning är klar förutsatt att funktionen aktiverats internt. W AK är ytterligare en aktivt låg ingång som ska dras och hållas låg för att väcka enheten inför en I²C-transaktion. SCL och SDA är
2.6. GASSENSOR 9 I²C-portarna som används för kommunikation med enheten. 3.3V och GND till-för tillsammans strömtill-försörjning och NTC är en port som ger användaren möjlig-heten att ansluta en termoresistor för enkel temperaturmätning igenom enmöjlig-heten.
För att läsa eller skriva till sensorn så måste man först specificera vilket av registren på enheten som ska manipuleras. Detta görs genom att först skriva re-gistrets adress, direkt följt utav kommandot läs eller skriv. Väljs läs så svarar enheten direkt med en eller flera bytes som motsvarar värdet i registret som val-des. Väljer man skriv så skickar man istället en eller flera bytes med värden som man vill ha i registret. De för projektet relevanta registren som finns i sensorn och vilka operationer de tillåter visas i tabell 2.2.
Adress Tillåten operation
Beskrivning
0 R Status
1 R/W Measurement mode
2 R Algorithm result, mätvärden för koldioxid samt TVOC
5 W Environment data, temperatur och luftfuktighet kan skrivas hit för att sensorn ska kompensera sitt mätvärde efter dessa
6 R NTC, spänning över sensorns referensresistor samt spänning över en adderbar termoresistor över NTC-portarna
224 R Error ID, om ett fel rapporterats i statusregistret kan ID’t för detta läsas härifrån
244 W App start, för att boota sensorn till ’Application Mo-de’ och påbörja mätningar skrivs hit en nolla Tabell 2.2:CCS811’s, för projektet relevanta, olika minnesregister
Sensorn har möjligheten till 5 olika körlägen. Dessa skrivs till registret 1, Mea-surement mode, hos enheten och specificerar hur ofta ett mätvärde ska tas. Körlä-gena och deras motsvarande registervärde listas i tabell 2.3.
Värde Mätintervall 0 Idle 16 1 sekund 32 10 sekunder 48 60 sekunder 64 250 millisekunder
Tabell 2.3:CCS811’s olika körlägen för mätning
leder till högst strömförbrukning av alternativen. I 32 och 48 pulserar istället vär-maren för att spara energi vilket kan vara mycket användbart för energikritiska system.
För att ta reda på när ett mätvärde finns färdigt att läsa så läser man av sen-sorns statusregister. I statusregistret finns även annan information om sensen-sorns status i form av en bitvis format byte som i figur 2.7.
7 6:5 4 3 2:1 0
Firmware mode - App valid Data ready - Error Figur 2.7:CCS811’s statusregisters byte-form
Firmware mode är 0 om enheten precis startat och är i boot mode. Den ett-sätts när man skickar startkommandot (App start) och gått in iApplication Mode.
App valid blir också ettsatt efter App start kommandot om en intakt och valid firmware finns installerad på sensorn. Data ready ettsätts när ett nytt mätvärde finns redo för läsning, och nollsätts så fort värdet lästs. Error ettsätts om ett fel uppstått på enheten. Felet kan sedan läsas ifrån felregistret Error ID.
Om statusregistret rapporterat att ett mätvärde finns redo att läsas så kan det hämtas genom att läsa 4 bytes från Algorithm result-registret. Datan kommer då i en bytearray uppdelad i ett format som i figur 2.8.
Byte 0 Byte 1 Byte 2 Byte 3
CO2High CO2Low TVOC High TVOC Low
Figur 2.8:CCS811’s bytearray-form för mätdata
För att återställa datan i bytearrayen till läsbara värden vänsterskiftas High-byten 8 steg och adderas sedan med Low-High-byten. Detta görs för båda mätvärden.
CCS811 lovar exaktare mätresultat om man matar den med två miljöparamet-rar, temperatur och humiditet. Detta görs genom att skriva 4 bytes till Environ-ment data-registret. Temperaturen angivs med en offset 25 vilket medför att det lägsta värdet som kan angivas är 0, vilket motsvarar -25 grader celcius. Vidare delas de båda parametrarna upp i två bytes med 7 bitar heltal + 1 fraktal i den högre vilket ger dess MSB en vikt på 127 och LSB 1/2. Samt 8 fraktaler i den lägre där dess LSB motsvarar en vikt på 1/512, och MSB 1/4. Detta illustreras i figur 2.9
2.7
Mikrofon
Ljud kan avslöja mycket om omvärlden. Ett användningsområde är att mäta oljud, buller. Juan Emilio Noriega-Linares och Juan Miguel Navarro Ruiz beskriver i sin artikel On the Application of the Raspberry Pi as an advanced Acoustic Sensor
2.7. MIKROFON 11 Byte 0 (7 heltal + 1 fraktal) 1 (8 fraktaler)
Bit 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
Vikt 64 32 16 8 4 2 1 12 14 18 161 321 641 1281 2561 5121
Figur 2.9:CCS811’s Environment Data register-utformning
Network for Noise Monitoring [14] hur en Raspberry Pi och en USB-mikrofon kan
användas för att mäta just buller både utomhus och inomhus samt utvecklingen över en längre tid. Mätdatan presenterades sedan för grannskapet där det mättes och kunde indikera vilka oljudsnivåer de var utsatta för.
Mer analytiska applikationer är också möjliga. I en transaktionEnvironmental Sound Recognition With Time–Frequency Audio Features berättar Selina Chu,
Shri-kanth Narayanan och C.-C. Jay Kuo om hur de igen om att analysera en ljudsignal kan känna igen ett flertal olika händelser i omgivningen av mikrofonen. Dessa innefattar saker som förbipasserande tåg, regn, vågor, ambulansljud[5]. Detta på-stås ha gjorts i liknande träffsäkerhet som ett mänskligt öra.
Mikrofonen Pmod MIC3 av Digilent genererar ett ljudsample på 12 bitar i som högst 106 gånger per sekund[7] över SPI-gränssnittet. Detta tillsammans med sitt låga pris gör mikrofonen passande för projektet.
Figur 2.10: Mikrofonkretsen Pmod MIC3 av Digilent och dess anslut-ningspinnar
På mikrofonkretsen som återfinns i figur 2.10 syns dess anslutningspinnar. Dessa innefattar Vcc och GND som tillsammans utgör kretsens strömförsörjning, samt SS, MISO och SCK som utgör SPI-gränssnittet. Vref kan anslutas till både 5 och 3.3 Volt, vilket gör den smidigt kopplingsbar till Raspberryns GPIO. Ombord finns även en potentiometer GAIN där känsligheten för mikrofonen kan justeras genom att skruva på den.
För att läsa av ett ljudsample drar man SS låg och genererar klockpulser på SCK. Enheten svarar då med två bytes som representerar mätvärdet. Den första byten är den övre och inleds alltid med 4 nollor följt av 4 databitar. Direkt efter
sänds de resterande 8 databitarna.
För att rekonstruera de två mottagna byten till ett ljudsample vänsterskiftas den övre byten 8 steg och adderas sedan med den undre byten. Värdet som anlänt har en offset på 2048. Detta är för att negativa tal ska kunna representeras. Tal under 2048 översätts då som negativa, och över offsetten positiva.
Efter att ha kompenserat för ofsetten kan talet översättas till decibel enligt funktionen
dB = 20 ∗ log10(|raw
Vref
|) (2.1)
därraw utgör absolutbeloppet av ljudsamplet, och Vref referensspänningen.
2.8
Temperatursensor
April år 2018 markerade den 400e månaden i rad vår planets temperatur upp-mätts som över medel[18], en oroväckande trend. Temperatur mäts redan på glo-bal skala men inte lika plats-specifikt som projektet CitiSense siktar på. För att logga även den lokala temperaturen, och inte bara medeln för en stad, adderas en temperaturgivare till projektet. Sensorn AT30TSE752A av Atmel valdes då den till ett billigt pris ger ett mycket högupplöst temperaturvärde, 12 bitar ger 4096 olika möjliga värden, med en känslighet på ±0.5 grader celcius. Mätvärdet över-förs via I²C och anländer i form av ett uppdelat tvåkomplementstal om två bytes med den övre delen först.[4].
Ytterligare en funktion temperaturgivaren tillför är att CCS811, gassensorn, kan använda dess mätvärde för att kompensera fram en ännu exaktare koldixid-haltsapproximation.
Figur 2.11:Temperatursensorn AT30TSE752A’s anslutningar
Figur 2.11 visar de olika anslutningarna som finns på sensorn. Dessa innefat-tar Vcc och GND som tillsammans står för strömförsörjningen, SDA och SCL som utgör I²C-gränssnittet, ALERT som ger en signal om temperaturen går utanför ett fördefinierat område, och A0-2som bestämmer sensorns I²C-adress.
De tre adresspinnarna utgör sensorns 7-bitiga adress minst signifikanta bitar. De fyra övre är permanent satta till1001. Detta betyder att om man till exempel
2.9. ANEMOMETER 13 matar pinne A0med Vref och jordar de två andra till 0 Volt får sensorn adressen
1001001.
Adress Register
0 Temperaturregister. Härifrån läses mätdatan
1 Konfigurationsregister. Hit läses eller skrivs inställningar Tabell 2.4:Dataregister i AT30TSE752A
Till sensorns register kan man både skriva och läsa inställningar samt läsa mätdatan. Detta görs genom att man först skriver adressen för registret man vill manipulera hos enheten, sedan utför operationen på det önskade registret. De för arbetet relevanta register hos temperatursensorn beskrivs i tabell 2.4.
För att ändra mätupplösning mellan 9, 10, 11 ,12 bit skrivs därav värdena 0, 32, 64, 96 respektive till temperatursensorns konfigurationsregister. Detta på-verkar hur många bitar som sedan finns att hämta i temperaturregistret. Tempe-raturregistret består av två bytes varav den övre, som anländer först, motsvarar mätvärdet i heltal, och den undre byten decimaldelen av det. När man då justerar mätupplösningen så ökar eller minskar man antalet decimaler i den undre byten innehåller.
2.9
Anemometer
Ytterligare en klimatparameter som är intressant att mäta är vindhastighet. Li-kaså för vind så mäts den redan på olika platser och väderprognoser baseras på dem. Det som saknas är plats-specifik vindhastighet som på grund av bebyggnad, träd och slätter kan skilja sig markant ifrån vad medeln över en stor region visar. Därför ska även denna uppmätas i projektet.
Eftersom projektet har som mål att upptäcka trender är inte noggrannhet pri-oriterat över pris. Därav lämnas liten budget åt att mäta vindhastigheten och eftersom färdiga anemometrar kostar relativt mycket kommer en egen lösning att testas. Tanken är att 3D-moddelera en mindre slags vindsnurra för att sedan montera på en DC-motor. DC-motorn som valdes var en MM28 på 6 Volt av Mi-niatyr Motors. Dess drivstång är 2mm i diameter och när vindsnurran snurrar på DC-motorn till följd av vind kommer den att generera en spänning över sina poler. Denna spänning kan uppmätas med en ADC.
Spänningen som genereras uppskattas vara väldigt låg då DC-motorn sägs nå 9600 rpm när man applicerar 3 Volt på dess poler[13], vilket anemometern inte kan tänkas nå ens vid storm-vindar. Detta antas dock inte utgöra ett problem då känsligheten på ADC’n som beskrivs i ovan kapitel och som kommer att använ-das för att mäta är hög nog för att upptäcka trender i vindhastighet, vilket är målet.
2.10
Analog/Digital Converter
Då mätningar behöver göras på de analoga signalerna ifrån regnsensorn och ane-mometern behöver en analog till digital signalkonverterare adderas till projektet. MCP3202 är en billig sådan med hög (12-bit) upplösning i 5 Volts-området och som sedan kan överföra mätvärdena via SPI[12].
Figur 2.12:MCP3202’s Anslutningar
I figuren 2.12 syns de anslutningar som finns hos adc’n. Dessa innefattar refe-rensspänningen Vref, bus-klockan CLK och CS tillsammans med datakanalerna Dout och Din som ihop används för SPI, de analoga ingångarna CH0 och CH1, och tillsist Vss, referensjordningen. Dout och Din motsvarar MISO och MOSI re-spektive för SPI-kommunikation.
De analoga ingångarna channel 0 och 1 jämförs internt med referensspänning-en. Ett värde som motsvarar hur ’nära’ referensen de är produceras sedan som ett värde mellan 0 och 4095 (212- 1) där det sistnämnda innebär att signalspänning-en på dsignalspänning-en mätta kanalsignalspänning-en är exakt samma som refersignalspänning-ensspänningsignalspänning-en.
Vidare kan därför, om referensspänningen är känd, råvärdet returnerat från enheten kalkyleras om till ett spänningsvärde enligt ekvationen
Vmeas=
raw ∗ Vref
212−1 (2.2)
därraw motsvarar det returnerade råvärdet och Vref referensspänningen.
2.11
Kamera
Bilder på omgivningen är ett användbart instrument då det kan indikera flera olika miljöelement. Några av dessa inkluderar mönster i trafiktäthet om enheten är placerad nära en väg, även vilken typ av trafik som generellt befinner sig just där. Om placerad nära grönska kan det även dokumenteras när exakt på året växtligheterna börjar visa sig och om det skiljer sig ifrån resten av omvärlden eller per år.
2.11. KAMERA 15
Figur 2.13:Raspberry Pi Camera module V2.1
Kameran i sig är en utvecklad specifikt för Raspberry Pi, heter Raspberry Pi Camera Module V2.1 och syns i figur 2.13. Den kommunicerar igenom en egen dedikerad port som återfinns på raspberryn och används genom ett inbyggt API vilket gör att användaren inte behöver tänka på vad som sker på hårdvarunivå. Istället kan användaren med ett fåtal funktioner fullt kontrollera kameran[17].
Funktionen som är relevant för arbetet ärraspistill. Den returnerar en bildfil
baserad på vilka olika inparametrar man skickar med funktionskallet.
De för projektet signifikanta inparametrarna vars inställningsvärde skrivs till höger om parametern listas i tabell 2.5.
Parameter Betydelse
--mode Definierar bildupplösning (0-7)
--timeout Definierar tiden i sekunder tills bilden ska tas
--exposure Definierar exponeringsinställning (auto, night, snow, antisha-ke mm.)
--awb Automatic white balance. Definierar färgtemperaturinställ-ning (auto, sun, cloud, shade mm.)
-vf Vertical flip. Speglar bilden vertikalt -hf Horizontal flip. Speglar bilden horizontalt
-o Specifierar hur och var bilden ska sparas --nopreview Visa inte förhandsvisningsfönstret
Tabell 2.5:För projektet signifikanta kamerainställningar hos Raspberry Pi Camera Module V2.1
De upplösningar som stöds och deras motsvarande parametervärde för--mode
återfinns i tabell 2.6:
Ett typiskt raspistill-funktionskall kan därav se ut som $ raspistill --mode 2 -t 1 -o /home/pi/test.jpg
och leder till att en bild vid namn test.jpg sparas efter 1 sekund med upplösnings-inställningen 2 (3280x2464 pixlar) i mappen /home/pi/.
Mode Upplösning 0 Automatiskt val 1 1920x1080 2, 3 3280x2464 4 1640x1232 5 1640x922 6 1280x720 7 640x480
Tabell 2.6: De olika stödda kameraupplösningarna för Raspberry Pi Camera Module V2.1 med motsva-rande inställningsvärde
2.12
Minneshantering
All mätadata inklusive bilder ska inte bara sparas lokalt utan även periodvis ko-pieras till ett USB-minne. För projektet valdes ett billigt USB-minne från Kingston 16 GB stort, men vilket USB-minne som helst går att använda utan skillnad. När minnet kopplas in i en av raspberryns lediga USB-portar så monteras det auto-matiskt under katalogen/media/pi/enhetsnamn/. Enhetsnamn motsvarar namnet
USB-minnet givits vid formattering, vilket för minnet som valts för detta projekt per default är KINGSTON.
Mappen som monterats går att skriva och läsa ifrån precis som andra mappar på systemet, med skillnaden att datan existerar på USB-minnet istället för system-minnet. Exempelvis för att kopiera innehållet i en lokal mapp/home/pi/logs/ till
USB-minnet kan kommandot
$ sudo cp /home/pi/logs/* /media/pi/KINGSTON/
kallas i en konsoll på raspberryn. (*)-operatorn indikerar här att allt innehåll i mappen ska kopieras[24].
Vidare kan USB-portarna på raspberryn, tillsammans med Ethernetporten, stängas av och på för energibesparing när de inte används. Detta görs med kom-mandona
# Avstänging
$ echo ’1-1’ | sudo tee /sys/bus/usb/drivers/usb/unbind och
# Påsättning
$ echo ’1-1’ | sudo tee /sys/bus/usb/drivers/usb/bind [8].
2.13. WIFI 17
2.13
Wifi
Raspberry Pi 3 B+ har ombord en wifi-modul som stödjer banden 2.4GHz och 5GHz över protokollen IEEE 802.11.b/g/n/ac. Denna kan användas för överfö-ring av loggdata till enheter i samma nätverk. Raspberryn kan antingen ansluta till en befintlig access-punkt, eller vara värd för en som klienter kan ansluta till.
Wifi-kretsen går att stänga av med kommandot $ sudo ifconfig wlan0 down
och starta igen med
$ sudo ifconfig wlan0 up
vilket kan användas för energibesparing, en central egenskap för projektet[6].
Hostapd är ett mjukvarupaket som kan användas för att vara värd till en wifi access-punkt. Denna konfigureras genom att skapa en .conf fil programmet kan läsa vid start.
De för projektet relevanta inställningarna som kan göras här innefattar nam-net för det trådlösa nätverket (ssid), vilket band som ska användas (2.4 eller 5.0 GHz), kanalnummer i bandet (channel), vilka protokoll som ska tillåtas (IEEE 802.11.b/g/n/ac), vilken ansluten wifi-modul som ska användas, vilka auktorise-ringsmetoder som ska användas tillsammans med vilket lösenord, samt huruvida enheten ska sända sitt namn för upptäckt. Dessa inställningar skrivs på var sin rad i inställningsfilen på formatet inställning= Värde och tillsammans med
Inställning Värden Innebörd
interface wlan[index] Val av wifi-modul
driver [namn] Väljer vilken drivrutin som ska användas för kontroll av wifi-modulen, nl80211 är i skrivan-de stund skrivan-den aktuella för Raspberry pi 3 B+ med raspbian-stretch
hw_mode a, g ’a’ för att använda 5 GHz-bandet, ’g’ för 2.4 ssid [namn] Namnet på det trådlösa nätverket
channel [heltal] Wifi-kanal som önskas, värdet 0 aktiverar auto-matiskt val
ieee80211n 0, 1 1 tillåter n-protokollet, 0 inte ieee80211ac 0, 1 1 tillåter ac-protokollet, 0 inte
ignore_broadc-ast_ssid
0, 1 0 gör det trådlösa nätverket upptäckbart och 1 osynligt
auth_algs 1, 2, 3 Auktoriseringsmetod. 1 - WPA, 2 - WEP, 3 - båda wpa 0, 1, 2, 3 0 gör nätverket öppet så att inget lösenord krävs för anslutning, 1 aktiverar WPA1-auktorisering, 2 WPA2-auktorisering och 3 aktiverar båda två
wpa_passphra-se
[lösenord] Väljer lösenord för WPA-auktorisering wpa_key_mgmt WPA-PSK,
WPA-EAP
Väljer vilken nyckelhanteringsalgoritm som kli-enter kan autentisera med
wpa_pairwise TKIP, CCMP
Väljer vilken datakrypteringsmetod WPA ska an-vända sig utav
rsn_pairwise CCMP Väljer vilken datakrypteringsmetod WPA2 ska använda sig utav
Tabell 2.7:hostapd.conf inställningsmöjligheter och förklaringar
För att anslutna enheter ska tilldelas en adress behövs en ytterligare service, dnsmasq. Dess konfigurationsfil är lokaliserad i/etc/dnsmasq.conf och innehåller
innehåller initiellt väldigt många inställningsparametrar på samma format som för hostapd. Men för projektet behövs endast två:interface och dhcp-range.
För att dnsmasq ska arbeta ihop med hostapd sätts de bådas interface-inställni-ng till samma wlan-modul. dhcp-range beskriver sedan omfånget för vilka
ip-adresser anslutna klienter kan tilldelas, samt hur länge får adressen. Den undre och den övre adressen för omfånget separeras med ett komma, följt av tidspara-metern.
Exempelvis skrivsdhcp-range = 192.168.4.2,192.168.4.22,24h på en rad i
in-ställningsfilen för att tillåta 20 klienter få ip-adresserna 192.168.4.[2-22] i 24 timmar.[3]
2.14. BLUETOOTH 19
2.14
Bluetooth
Ett annat sätt att trådlöst överföra loggdata är via Bluetooth. Raspberry Pi 3 B+ är utrustad med Bluetooth 4.2/BLE som fullt ut kan kontrolleras igenom operativsy-stemet med paketet hciconfig och python-biblioteket BlueZ [16]. Dessa kommer förinstallerade med raspian-stretch.
Genom att kalla på hciconfig kan ett antal inställningar för bluetoothmodulen ändras. Några sådana är visningsnamnet, upptäcksbarhet och parbarhet. Detta görs på formatethciconfig hciX [kommando] [kommandoparameter] där X indikerar
indexet för vilken tillgänglig blåtandsmodul som ska manipuleras [10]. De för projektet relevanta kommandona beskrivs i tabell 2.8.
Kommando Beskrivning
name Om följd av en sträng bytes visningsnamnet till strängen piscan Gör enheten upptäckbar
noauth Stänger av autentiseringsmetoden vilket gör det möjligt för en-heter att para utan verifikation på raspberryn
Tabell 2.8:Kommandon för hciconfig samt innebörd
I python med biblioteket BlueZ kan man öppna en Bluetoothport för seriell dataöverföring. Detta görs genom att skapa en ’socket’ genom funktionen Blue-toothSocket(). För att överföra data seriellt används protokollet RFCOMM, vil-ket man specificerar som inparameter till funktionen när man öppnar socvil-keten. Funktionen returnerar då ett objekt i form av en socket som sedan kan användas för att ansluta till en klients socket. När anslutningen är gjord kan överföring-ar med funktionerna send() och recv() göras [1]. Nedan är ett minimalt python-script som exemplifierar funktionaliteten genom att ta emot en byte och sedan skicka tillbaka samma byte till en klient:
# Importera bluetoothbiblioteket
from bluetooth import *
# Skapa en bluetoothsocket med protokollet RFCOMM för seriell dataöverföring
localsocket = BluetoothSocket( RFCOMM ) # Associera socketen med en dataport localsocket.bind(("", PORT_ANY)) # Lyssna efter 1 enhet
localsocket.listen(1)
# Vänta på, och acceptera en anslutning clientsocket, address = localsocket.accept() # Ta emot 1 byte
byte = clientsocket.recv(1) # Skicka tillbaka samma byte clientsocket.send(byte) # Stäng anslutningen clientsocket.close()
# Stäng socketen localsocket.close()
3
Metod
Detta kapitel beskriver hur systemet har konstruerats och vilka metoder som används för att kommunicera med de olika komponenterna samt användaren. Komponenterna som används listas nedan tillsammans med pris vid inköp.
Namn Beskrivning Pris
Raspberry Pi 3 B+ Senaste versionen av Raspberry Pi-enkortsdatorer
300kr Kingston 16GB microSDHC
UHS-I
Högpresterande minneskort för Raspberryns OS att köras ifrån
123kr Kingston DataTraveler 100 G3
16GB USB 3.0
USB-minne 79kr
SparkFun Air Quality Break-out - CCS811
Koldioxid och TVOC-gassensor 174kr
Digilent PmodMIC3 Mikrofon 113kr
Raspberry Pi Camera V2.1 Kamera 214kr
MM28 Miniatyr DC-motor 6V DC-motor för anemometer 21kr
Atmel AT30TSE752A-SS8M-B Temperaturgivare 23kr
Microchip MCP3202-BI/SN Analog/Digital-omvandlare 12 bit 25kr Grove Water sensor, seeed
stu-dio
Regnsensor 27kr
Summa 1099kr
Tabell 3.1:Projektets komponentlista
3.1
Komma igång med Raspberry Pi
Till att börja med laddades den senaste versionen av OS’et Raspbian Stretch ner från Raspberry Pi Foundation’s hemsida. Denna brändes sedan på micro-SD kor-tet med hjälp av ett open-source program vid namn Etcher som finns att hämta på dess hemsida, etcher.io. Efter det pluggas SD-kortet in i dess port på raspber-ryn och den kan nu boota OS’et. För att styra raspberraspber-ryn behövs till att börja med en mus, ett tangentbord och en hdmi-skärm. Men väl inne i OS’et installerades fjärrstyrningsmjukvaran xrdp vilket gjorde att en laptop på samma nätverk som raspberryn räckte för full kontroll.
För att kunna använda I2C, SPI och kameran måste dessa en första gång ak-tiveras i Raspberry Pi Software Configuration Tool, vilket görs genom att i en konsoll skriva
$ sudo raspi-config
och aktivera dessa i menyn som dyker upp.
Vissa applikationer vill också köras automatiskt vid systemstart. Detta görs genom att utforma ett startscript, applauncher.sh, i projektmappen och sedan i
systemets startscript/etc/rc.local köra detta script genom att addera följande rad
i slutet:
sudo sh /home/pi/citisense/applauncher.sh
Alla kommandon som står iapplauncher.sh kommer då att köras vid varje
system-start.
3.2
De digitala sensorerna
Vidare ansluts de olika komponenterna utefter kopplingsschemat i appendix A.1. Detta kapitel beskriver metodiken bakom hur kommunikation med de olika di-gitala sensorkomponenterna etablerats.
3.2.1
Kommunikation med AT30TSE752A
Temperatursensorn har 8 pins som beskrivs i kapitel 2.8 Temperatursensor och figur 2.11. Dess pinnar SDA och SCL ansluts till raspberryns GPIO-pins för I²C-kommunikation (GPIO2 och GPIO3 respektive). Vcc ansluts till 5V och GND till GND. Vidare ansluts alla dess adresspinnar A0-2till 5V vilket ger enheten
I²C-adressen 0x4F, vilken kombination som helst kan dock väljas på adresspinnarna den ändå inte skulle korsa adress med någon annan I²C-enhet i systemet. Kopp-lingsschemat i figur 3.1 förtydligar hur komponenten anslutits.
För att sedan kommunicera med sensorn används pigpio’s bibliotek för I²C-kommunikation som beskrivs i kapitel 2.4 PIGPIO. Dessa innefattari2c_open(unit,
3.2. DE DIGITALA SENSORERNA 23
Figur 3.1:Kopplingsschema för temperatursensorn AT30TSE752A
addr) som med inparameter unit = 1 och addr = 0x4F returnerar ett objekt som
motsvarar databussen,i2c_read_device(bus, count) som med inparameter bus =
databuss-objektet och count = mängd bytes som ska läsas returnerar en bytear-ray av mottagen data,i2c_write_byte(bus, data) och i2c_write_byte_data(bus, mode, data) som med inparameter bus, -mode = registeradressen dit datan ska skrivas
och data = datan som ska skrivas.
send(bus, mode data) och recieve(bus, mode, count = 1) är två funktioner som
för-enklar användningen av enheten genom användning av ovan beskrivna funktio-ner. Deras definitioner samt hur de används vid initiation och temperaturhämt-ning visas i kodstycket nedan.
import pigpio
temp_val_addr = 0x4F pi=pigpio.pi()
# Open bus on i2c-unit 1, and address 0x4F temp_val_bus = pi.i2c_open(1, temp_val_addr)
def send(bus, mode, data):
pi.i2c_write_byte_data(bus, mode, data)
def recieve(bus, mode, count=1): # if no count given, assume 1 # Tell device which register to read
pi.i2c_write_byte(bus, mode) # Read told register
(cnt,bytearr) = pi.i2c_read_device(bus,count)
return bytearr
def temp_init():
try:
# set 12 bit res, normal op mode, rest defaults = 0b01100000 = 0x60 to registry-addr 0x01 send(temp_val_bus, 0x01, 0x60) return 1 except i2cerror: return 0 def get_temperature():
arr = recieve(temp_val_bus, 0x00, 2)
# First byte integer part, last byte fractional part temperature = int(arr[0]) + (int(arr[1] >> 4)*0.0625)
# Data arrives in two’s-complement form, convert if sign bit is set
if (int(arr[0]) & 0x80):
temperature = 256 - temperature
return temperature
Som kodstycket ovan visar initieras enheten till att använda 12-bitars upplös-ning genom att skicka det hexadecimala värdet 0x60 till enhetens konfigurations-register 0x01. Sedan hämtas temperaturen ifrån registret 0x00 från vilket datan anländer på uppdelad form och måste kompletteras. Detta görs genom att höger-skifta den sistanlända bytenarr[1] 4 steg och multiplicera med vikten för dess
LSB, sedan adderas resultatet med den förstanlända heltals-bytenarr[0]. Sist
kol-las om tecken-biten är satt, vilket indikerar att temperaturen är negativ. Om så är fallet måste talet konverteras då det är på tvåkomplementtals-form vilket görs genom att subtrahera temperaturvärdet ifrån maxvärdet 256.
3.2.2
Kommunikation med CCS811
Som beskrivet i kapitel 2.6 använder sig gassensorn utav clock-stretching varför den inte korrekt kan kommunicera med raspberryns integrerade I²C-gränsnitt, utan pigpio’s bibliotek för bit-banging måste användas. Därav väljs två lediga GPIO-pinnar ut för mjukvarukontrollerad I²C. Här valdes GPIO22 för SDA, och GPIO27 för SCL.
Sensorns 3.3V-ingång ansluts till raspberryns 3V3-utgång, och GND till GND för strömförsörjning. W AK ansluts också till GND då enhetens I²C-gränssnitt vill hållas igång konstant. Kopplingsschemat i figur 3.2 förtydligar hur komponenten anslutits.
Figur 3.2:Kopplingsschema för gassensorn CCS811
För att kommunicera med enheten öppnas först en bussanslutning på de val-da GPIO-pinnarna med hastigheten 300KHz genom pigpio’s funktionbb_i2c_open( SDA, SCL, SPEED). Sedan kan information överföras med funktionerna send(addr,
3.2. DE DIGITALA SENSORERNA 25
mode, data) samt recieve(addr, mode, count) som använder sig av pigpio’s funktion bb_i2c_zip(SDA, [arr]). Nedan stycke illustrerar funktionernas definitioner samt
hur I²C-gränssnittet initieras SDA = 22
SCL = 27
pi = pigpio.pi()
bus = pi.bb_i2c_open(SDA, SCL, 300000)
def send(addr,mode,data):
(s, buf) = pi.bb_i2c_zip(SDA,[4, addr, 2, 7, 2, mode, data, 3, 0])
def recieve(addr,mode,count):
(s, buf) = pi.bb_i2c_zip(SDA,[4, addr, 2, 7, 1, mode, 3, 0]) (s, buf) = pi.bb_i2c_zip(SDA,[4, addr, 2, 6, count, 3, 0])
return buf
För att använda sensorn måste den först initieras. Detta görs genom att kal-la på funktioneninit_ccs811(meas_mode) med inparametern 0x10 för att ge ett
mätvärde per sekund. Funktionens definition är som nedan: CCS811_BOOTLOADER_APP_START = 0xF4 CCS811_ADDRESS = 0x5B CCS811_MEAS_MODE_ADR = 0x01 def init_ccs811(meas_mode): try: if not dataready(): # Boot command
(s, buf) = pi.bb_i2c_zip(SDA,[4, CCS811_ADDRESS, 2, 7, 1, CCS811_BOOTLOADER_APP_START, 3, 0])
sleep(0.1) # Let device boot for 0.1s # Set measuring mode
send(CCS811_ADDRESS, CCS811_MEAS_MODE_ADR, meas_mode)
return 2 # Return 2 to indicate newly booted device
return 1 # Return 1 to indicate device already booted
except:
return 0 # Return 0 to indicate device not responding
Enheten mäter nu CO2och TVOc och ger ett mätvärde en gång i sekunden.
In-nan hämtning av mätvärden kollas om ett mätvärde finns att hämta. Detta görs med funktionendataready() som returnerar True eller False beroende på om
en-hetens statusregister rapporterar att ett mätvärde finns. Funktionens definition ser ut som nedan
CCS811_STATUS = 0x00 CCS811_ADDRESS = 0x5B
def dataready():
status = recieve(CCS811_ADDRESS, CCS811_STATUS,1) # Is data ready bit set?
if (int(status[0]) & 0x08) == 0x08:
return True
else:
return False
och vad som görs är att biten som representerar om datan är redo i statusre-gistret maskas ut ifrån resten och jämförs med ett värde som bitvis motsvarar vad resultatet hade sett ut som om den var ettsatt.
Vidare omdataready() returnerar True läses mätvärdena ifrån register 2,
Al-gorithm result. Mätvärdenas övre del skiftas sedan 8 steg åt vänster och adderas med sin undre del enligt funktionensread_gas() definition nedan.
CCS811_ADDRESS = 0x5B
CCS811_ALG_RESULT_DATA = 0x02
def read_gas():
buf = recieve(CCS811_ADDRESS, CCS811_ALG_RESULT_DATA,4) co = (buf[0] << 8) | buf[1]
tvc = (buf[2] << 8) | buf[3]
return [co,tvc]
Datan returneras som en tupel av koldioxidhalten och TVOC-halten.
Emellanåt kollas även om något fel uppstått på sensorn. Detta görs med funk-tionen checkerror() likt dataready()-funktionen läser statusregistret men istället
jämför om error-biten är satt. Om den är det läses error-registret vars innehåll returneras från funktionen som en sträng enligt sin definition nedan.
CCS811_STATUS = 0x00 CCS811_ERROR_ID = 0xE0
def checkerror():
buf = recieve(CCS811_ADDRESS, CCS811_STATUS,1)
if (int(buf[0]) & 0x01) == 0x01: # Is error reported by sensor # Read ERROR_ID register
buf = recieve(CCS811_ADDRESS, CCS811_ERROR_ID, 1) # Print error to console
print("Error is: " + str(buf)) # Return error-string
return str(buf)
Varje gång ett nytt temperaturvärde finns tillgängligt skrivs detta till gas-sensorn. Detta görs med funktionenset_environment(temperature, humidity = 50)
vars definition syns nedan. CCS811_ADDRESS = 0x5B CCS811_ENV_DATA = 0x05
3.2. DE DIGITALA SENSORERNA 27
# Minimum enterable temperature
if temperature < -25.0: temperature = -25.0 # Check humidity bounds
if humidity < 0 or humidity > 100.0: humidity = 50
# LSB is worth 0.5C and so on
hum_perc = int(round(humidity)) << 1 # Split fractionals and integers parts = math.modf(temperature)
# Remove sign bit from fractional part fractional = math.fabs(parts[0]) temp_int = int(parts[1])
# Add offset and shift 9
temp_high = ((temp_int + 25) << 9)
# LSB of fractional is worth 1/512, but must be sent as integer
temp_low = (int(fractional / 0.001953125) & 0x1FF) # Merge result
temp_conv = (temp_high | temp_low) # Complete bytearray with humidity
buf = [hum_perc, 0x00,((temp_conv >> 8) & 0xFF), (temp_conv & 0xFF)]
# Custom send larger bytearray
(s, buffy) = pi.bb_i2c_zip(SDA,[4, CCS811_ADDRESS, 2, 7, 5, CCS811_ENV_DATA, buf[0], buf[1], buf[2], buf[3], 3, 0])
Först kollas så inga felaktiga klimatvärden angetts. Sedan konverteras datan till 7 bitar heltal och 9 bitar fraktaler enligt illustrationen i figur 2.9. Därefter skickas bytearrayen och sensorn kan nu använda dem för att kompensera fram noggrannare mätresultat.
3.2.3
Kommunikation med MCP3202
Mätningarna av regnsensorn och anemometern görs med ADC’n MCP3202 ge-nom att koppla deras utsignaler till omvandlarens inportar CH0och CH1
respek-tive. Omvandlarens övriga pins, som syns i figur 2.12, kopplas såsom Vref till 3V3 då det ger en högre upplösning i avläsningen av anemometern än vad en refe-rensspänning på 5 Volt hade givit, GND till systemets GND och SPI-gränssnittets CLK, Dout, Din och CS till raspberryns SPI-gränssnitt på GPIO 11, 9, 10 samt 8 respektive enligt kopplingsschemat i Appendix A.1 vilket även gör enheten till slav 0. Figur 3.3 förtydligar hur komponenten anslutits tillsammans med anemo-metern och regnsensorn där M indikerar anemoanemo-meterns DC-motor.
För att överföra mätdatan används funktionenread_adc_raw(channel) som tar
kanalnumret som inparameter och vars definition visas tillsammans med initie-ringen i kodstycket nedan.
Figur 3.3:Kopplingsschema för A/D-omvandlaren MCP3202
pi = pigpio.pi()
# Create bus object specifying slave no 0, 1MHz speed and the raspberry SPI-unit 0
bus = pi.spi_open(0,1000000,0) # slave 0, 1MHz, spi unit 0 # Known reference voltage, can be used to calculate actual
measured voltage adcrefvoltage = 3.3
def read_adc_raw(channel):
# Transfer data, specify channel desired
(count,raw) = pi.spi_xfer(bus,[1,(2 + channel)<<6,0]) # Data arrives splitted, first byte empty, second is upper
byte and last is lower byte. ret = ((raw[1] << 8) + raw[2])
return ret
Då pigpio-funktionen spi_xfer() returnerar lika stor bytearray som den skic-kar anländer mätresultatet i en bytearray 3 stor där den första är tom.raw[1] är
därför den övre resultatbyten och vänsterskiftas därav 8 steg innan den adderas med sin undre resultatbyteraw[0].
3.2.4
Läsning av Digilent PmodMIC3
Mikrofonens Vcc ansluts till raspberryns 3V3 samt GND till GND. Resterande anslutningspinnar MISO, SCL och SS tillhör enhetens SPI-gränssnitt och ansluts
3.2. DE DIGITALA SENSORERNA 29 därav till raspberryns GPIO 9, 11 och 7 vilket gör den till SPI-slav 1. Kopplingar-na illustreras i figur 3.3
Figur 3.4:Kopplingsschema för mikrofonen Digilent PmodMIC3
Eftersom kommunikationen med denna enhet är envägs behövs det bara att göra en läsning ifrån enheten om 2 bytes för att överföra mätdatan. I övrigt är kommunikationen snarlik den för a/d-omvandlaren. Proceduren har förenklats med funktionenread_mic() vars definition syns i kodstycket nedan.
import pigpio pi = pigpio.pi()
# Open bus on slave 1, 48KHz, SPI-unit 0 mic = pi.spi_open(1,48000,0)
def read_mic():
# Read 2 bytes from databus (count,buf) = pi.spi_read(mic,2)
# Data returns as offset of half maximum value with MSByte first and LSByte last
sample = 2048.0 -((buf[0]<< 8) + buf[1])
return sample
Då mätdatan anländer uppdelad i form av 2 bytes som representerar en offset ifrån dess mittenvärde konverteras värdet genom att högerskiftabuf[0] 8 steg,
ad-dera medbuf[1] och sist subtrahera resultatet ifrån hälften av maxvärdet för 12
bitar 4096.
Ett enda ljudsample säger dock inte så mycket då lufttryck fluktuerar väldigt mycket. Istället tas en serie samples och ett medelvärde skapas utifrån deras ab-solutbelopp. Denna metod ger ett värde som motsvarar en ungefärlig enhetslös ljudnivå, men möjligheten finns att vidareutveckla denna funktion till att fånga in riktigt ljud för vidare analysering.
3.2.5
Bildtagning
Kameran Raspberry Pi Camera Module V2.1 kopplas in på raspberryns dedike-rade anslutningsport och bilder tas sedan genom att kalla på scriptet camera.sh vars innehåll ser ut som nedan.
DATE=$(date +"%Y-%m-%d_%H-%M-%S")
sudo raspistill --timeout 1 --mode 0 --nopreview -awb auto --exposure auto -o /home/pi/citisense/logs/$DATE.jpg
I scriptet kollas först datumet som OS’et rapporterar och sparar detta i en variabel på formatet år-månad-dag_timme-minut-sekund. Sedan tas bilden genom att kal-la påraspistill med inparametrar för automatisk vitbalans, exponering och
upp-lösning, 1 sekunds tidsutupp-lösning, inget förhandsvisningsfönster och sparplats /ho-me/pi/citisense/logs/ med ett filnamn som motsvarar dagens datum och tid.
3.3
Anemometerkonstruktion
En vindsnurra modellerades i 6 olika delar i programmet 3DS Max 2019 student. Den exporterades sedan till en utskrivbar .STL-fil som sedan användes för att skriva ut med Linköpings Universitets 3D-skrivare.
Modellen skruvades sedan ihop och limmades fast på DC-motorns motorpinne. Motorns positiva pol kopplas sedan till kanal 1 på a/d-omvandlaren, och den negativa polen till systemets ground.
För att utsignalen ifrån motorn ska få en jämnare och mätbar signal lades en parallell kapacitans på 1µF till. Ytterligare en 1kΩ resistor lades till i serie mellan DC-motorn och a/d-omvandlaren för att skydda mot överspänningar.
3.4
Trådlös nätverkspunkt
För att raspberryn ska agera som värd för en trådlös nätverkspunkt används två tjänster, dnsmasq och hostapd.
Tjänsterna installeras först på enheten, detta görs med kommandot $ sudo apt-get install dnsmasq hostapd
vilket använder raspberryns pakethanterare för att självmant installera de två paketen.
Vidare modifieras inställningsfilerna för tjänsterna.
Till att börja med blockeras OS’et ifrån att använda internetmodulerna. Detta görs genom att i filen/etc/dhcpcd.conf lägga till följande rad i slutet:
denyinterfaces eth0 denyinterfaces wlan0
Efter det modifieras filen/etc/dnsmasq.conf till att enbart innehålla raderna
interface=wlan0
3.4. TRÅDLÖS NÄTVERKSPUNKT 31 vilket gör att klienter som ansluter till nätverket tilldelas ip-adresser i omfång-et 192.168.0.(2-22) under 24 timmar, vilkomfång-et motsvarar 20 anslutna enhomfång-eter som maximum.
Sedan skapas en inställningsfil för hostapd. Dess innehåll lyder interface=wlan0 # the interface used by the AP
driver = nl80211 # Use this driver hw_mode=g # 2.4GHz-band
channel=7 # Channel 7 of the 2.4GHz spectrum ieee80211n=1 # 802.11n support
ssid=Citisense # the name of the AP auth_algs=1 # 1=wpa, 2=wep, 3=both wpa=0 # No password
ignore_broadcast_ssid = 0 # Make wifi discoverable
och valdes för att stödja fler enheter till kostnad av prestanda då datan som ska överföras är relativt liten. Filen sparas i/etc/hostapd/hostapd.conf och för att
tjäns-ten ska hitta konfigurationsfilen läggs sökvägen till i filen/etc/default/hostapd
ef-ter raden#DAMON_CONF så dess rad istället ser ut som DAEMON_CONF="/etc/hostapd/hostapd.conf".
Sista inställningarna som görs är i filen /etc/network/interfaces där följande
stycke adderas i slutet av filen: allow-hotplug wlan0 iface wlan inet static address 192.168.0.1 netmask 255.255.255.0 network 192.168.0.0 broadcast 192.168.0.255
Detta ser till att en statisk ip-adress för raspberryn kopplad till det trådlösa nät-verket sätts och tillåter att servicen hostapd tillåts åtkomst till wifi-modulen.
Efter det startas systemet om och det trådlösa nätverket Citisense finns att
ansluta till. För att när som helst stänga av eller på det trådlösa nätverket används metodiken i kodstycket nedan.
# Turn off ap
sudo service hostapd stop sleep(1)
# Turn off wifi entirely sudo ifdown wlan0
# Turn on wifi sudo ifup wlan0 # Turn on ap
sudo service hostapd start # Let module boot for 4s sleep(4)
# Restart ap-service twice sudo service hostapd restart sleep(2)
sudo service hostapd restart
Denna funktionalitet används tillsammans med Bluetooth för att spara energi. Att överföra mätdatan testas sedan med en minimal flask-applikation vars källkod återfinns i appendix A.11. När denna körs kan en enhet ansluten till det trådlösa nätverket skriva adressen 192.168.0.1 i i adressfältet i en vanlig webblä-sare och all mätdata dyker upp formaterat.
3.5
Blåtandsöverföring
Bluetooth har i projektet flera användningar. Att överföra loggdatan på ett smi-digare och energieffektivare vis, men den kan också användas för att starta och stänga av den mer energikonsumerande trådlösa-nätverkspunkten. Först görs ett antal konfigurationer på modulen. Dessa konfigurationer måste göras varje gång raspberryn startar så de läggs in i startscriptetapplauncher.sh som sådan:
# Name
sudo hciconfig hci0 name ’Citisense’ # No verification
sudo hciconfig hci0 noauth # Add Serial Profile sudo sdptool add SP # Make discoverable
sudo hciconfig hci0 piscan
Konfigurationerna ger enheten Bluetoothnamnet Citisense, gör den upptäckbar
och parbar utan verifikation på raspberryn, samt lägger till en profil för seriell överföring.
För att den seriella profilen ska kunna användas måste även Bluetooth-service-n startas i kompatibilitetsläge. Detta görs geBluetooth-service-nom att addera flaggaBluetooth-service-n -C efter radeBluetooth-service-n
ExecStart=/usr/lib/bluetooth/bluetoothd i servicens konfigurationsfil som återfinns
i/etc/systemd/system/dbus-org.bluez.service. Filen borde således innehålla raden
ExecStart=/usr/lib/bluetooth/bluetoothd -C
för att Bluetooth-servicen ska köras i kompitabilitetsläge och tillåta en seriell da-taöverföringsprofil.
För att sedan överföra information seriellt via Bluetooth initieras först en Blue-toothSocket att utföra kommunikationsoperationer på. Denna sätts sedan till att lystna efter och acceptera en anslutning ifrån en annan enhet. Detta görs med följande kodstycke:
3.6. DATALOGGNING 33
# Import the BT library
from bluetooth import *
# Create a socket using the RFCOMM protocoll for transfers pisocket = BluetoothSocket( RFCOMM )
# Associate socket with a dataport pisocket.bind(("", PORT_ANY)) # Listen for 1 client
pisocket.listen(1)
# Await, and accept 1 client connection client_socket,adr = pisocket.accept()
Efter etablerad anslutning inväntas en instruktion ifrån den anslutna enheten och tas emot som en enda byte. Vad som kan göras är att stänga av/på den trådlö-sa nätverkspunkten, överföra sensordatan eller överföra en bild. Det förstnämnda kallar på de ovan beskrivna funktionerna att stänga av det trådlösa nätverket ige-nom pythonssubprocess.call()-funktionalitet. Men om en fil eller bild önskats så
överförs denna med funktionensend_file(s,dir) som tar inparametrarna s = objekt
av klientens anslutningssocket och dir = sökväg för filen som ska överföras. Dess definition lyder såsom kodstycket nedan
def send_file(s,dir):
# Open file from dir in read-only, binary mode
file = open(dir,’rb’)
# Send dir for reciever to know filename s.send(dir)
s.send(’\n’) packet = 1
while(packet):
# Read 1kB from file and send, repeat until empty packet = file.read(1024)
try:
s.send(packet)
except BluetoothError:
# If client disconnects leave loop packet = None
file.close()
och löser problemet med Bluetoothbibliotekets funktionsend() samt
OS-bibliotek-etsopen() och read() genom att skicka filen i paket om 1024 bytes till
bluetoothk-lienten.
Programmet körs hela tiden i bakgrunden på raspberryn och återfinns i sin helhet i appendix A.2. En enhet som ansluter kan skicka en byte med ASCII-motsvarande bokstaven ’S’ för att motta all mätdata. Datan anländer i form av en .csv-fil.
3.6
Dataloggning
För att logga all mätdata ifrån de olika komponenterna används python-scriptet
ge-nom att importera de olika underprogrammen för hämtning av mätdata såsom
read_adc_raw() och read_gas() som bearbetats i ovan kapitel. Dessa kan då
använ-das för att initiera alla enheter samt periodvis hämta, spara eller säkerhetskopie-ra all mätdata till USB-minnet. Detta görs i funktionernainitiate(), append_log()
samtupdate_sensors(Bool log, Bool backup) vars definitioner bearbetas i
komman-de unkomman-derkapitel.
3.6.1
Funktionen initiate()
För att systemet ska hålla koll på vilka sensorer som är anslutna försöker i denna funktion programmet att kommunicera med dem en efter en. De som svarar på ett korrekt sätt sätts då till status närvarande.
De olika komponenterna svarar dock på olika sätt när de inte är anslutna, där-av har en funktioninit() skapats för varje digital sensorkomponent.
Vid kommunikation med en onärvarande CCS811, AT30TSE752A eller Ardu-ino så kastar biblioteket pigpio ett felmeddelande som kan fångas. Sker detta vid initiationen så sätter programmet enheterna som onärvarande.
Om däremot en SPI-enhet (mikrofonen eller ADC:n) inte är närvarande så kastas inget felmeddelande, utan funktionerna returnerar istället mätvärdet 0 konstant vilket gör det svårare att veta om enheterna är närvarande eller inte. Men eftersom ingen av enheterna någonsin borde ge ett mätvärde som alltid är noll om de faktiskt är närvarande och inkopplade så kan programmet istället an-ta att de inte är det.
För att undvika fel antagande vid de fåtal fall när ett mätvärde faktiskt är 0 så tas en multitud av mätvärden som alla jämförs mot 0 och om enheten inte avvi-ker en endaste gång så är det högst otroligt att enheten är närvarande och därav sätter programmet den som icke sådan.
En annan metod för detta är att låta användaren manuellt sätta enhet för en-het som närvarande eller icke vilket görs genom att sätta dess booleanska närva-rovariabel som True istället för False i början av logger.py-skriptet.
3.6.2
Funktionen update_sensors(Bool Log, Bool backup)
När denna funktion kallas på hämtar programmet först nya mätvärden från alla komponenter som satts som närvarande. Efter det kollas om inparameternLog är
True vilket betyder att mätvärdena som just togs ska sparas lokalt.
Detta görs genom att kalla på funktionenappend_log() som beskrivs i nästa
delkapitel. Vidare kollas nästa inparameterbackup vilken om satt True indikerar
att all loggdata ska säkerhetkopieras till USB-minnet samt att en bild ska tas. För att göra detta kallas skripten camera.sh (från kapitel 3.2.5 Bildtagning)