• No results found

Raspberry Pi-baserad lågeffektsmodul för dataloggning av olika miljöparametrar

N/A
N/A
Protected

Academic year: 2021

Share "Raspberry Pi-baserad lågeffektsmodul för dataloggning av olika miljöparametrar"

Copied!
91
0
0

Loading.... (view fulltext now)

Full text

(1)

Kandidatuppsats i elektronik

Institutionen för systemteknik, Linköpings universitet, 2018

Raspberry Pi-baserad

lågeffektsmodul för

dataloggning av olika

miljöparametrar

(2)

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

(3)

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.

(4)
(5)

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.

(6)
(7)

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

(8)

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

(9)

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

(10)

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

(11)

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

(12)
(13)

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.

(14)

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.

(15)

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.

(16)

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

(17)

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’

(18)

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

(19)

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

(20)

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

(21)

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

(22)

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

(23)

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

(24)

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

(25)

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.

(26)

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.

(27)

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/.

(28)

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].

(29)

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

(30)

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]

(31)

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()

(32)

# Stäng socketen localsocket.close()

(33)

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

(34)

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,

(35)

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():

(36)

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,

(37)

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():

(38)

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

(39)

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.

(40)

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

(41)

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.

(42)

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

(43)

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)

(44)

# 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:

(45)

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

(46)

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)

References

Related documents

In the analysis of the distribution of the number of followers for users at the time of posting their tweet there was a trend for both years that users that tweet using Bitly has

In the fast experiment with the tennis ball the camera mount speed was clearly an issue. As seen in Figure 19 the controller couldn’t manage the speed in this case and the ball

 Once the motors and the hardware has been chosen, make the prototype have as high of a centre of gravity as possible, by putting all heavy parts of the hardware as high as

The right picture in figure 3.3 demonstrates a stable and low power consumption in the stack.. Figure 3.3: The figure demonstrate the current in

Programmet ¨ar uppbyggt med hj¨alp av tre olika agenter, RPAgent, ArduinoAgent och Observer. Varje Raspberry Pi har en ArduinoAgent och en RPAgent. RPAgent representerar var en last

Liksom f6r Martianus (Ferrer 1988) verkar ur- sikterna fcir Cynaeus anpassning till svenska bio- toper vara relativt goda... Trickvingarnas yttre strimmellanrum

Trombidios iir vanligcn till si pass ringa besvlr och till tiden se bcgrdnsad att den inte fijranleder bes&lt;ik hos liikare och diirf&lt;ir kan tankas forbli

De pi bron funna getingarna miste som regel ha avlegsnat sig en bra bit frin sina dvervintringsplat- ser respektive bon.. I maj och juni forolyckas ovcrvintradc