← Kursens material Visa mätvärdet · område 4 Område 4

Område 4 · lektion 22

Visa mätvärdet

Ett mätvärde som bara finns inuti kortet är ingen mätning. Den här guiden handlar om det sista steget i kedjan sensor → styrenhet → aktuator: att göra talet läsbart för en människa. Tre vägar finns, och den tredje – en visare som rör sig – är den enda som gör bygget till ett mekatroniskt system. Den ställer också ett krav de två andra inte gör: skalan måste stämma, inte bara se proportionerlig ut.

Mål

Genomgång

Serial: utmärkt att felsöka med, dåligt som instrument

Seriemonitorn har varit ditt fönster in i bygget sedan område 2, och den förblir det bästa felsökningsverktyget du har. Men som instrument har den tre problem: den kräver en dator med sladd, den visar en rullande lista i stället för ett värde, och den är långsam.

Räkna på hastigheten, för den överraskar. Serial.begin(9600) betyder 9600 bitar i sekunden. Varje tecken skickas med en startbit och en stoppbit runt sina åtta databitar, alltså tio bitar per tecken:

9600 / 10 = 960 tecken i sekunden

En rad som 24.3 C 47 % med radbrytning är omkring sexton tecken, alltså

16 / 960 = 0,0167 s = 17 ms per rad

Fyra rader i sekunden kostar 4 · 17 = 68 ms av varje sekund, alltså knappt sju procent av tiden. Det märks inte. Men en utskrift varje loopvarv, med tusentals varv i sekunden, skulle kräva tiotusentals tecken i sekunden när bara 960 ryms. Kortet har en sändbuffert på 64 byte, och när den är full väntar Serial.print tills det finns plats. Utskriften blir då ett delay() i förklädnad, och hela området 3:s arbete med att inte blockera går förlorat på en rad som såg ofarlig ut.

Regeln är densamma som för allt annat i det här området: lägg utskriften i tidsstämpelmönstret och skriv fyra gånger i sekunden. Snabbare än så kan ingen läsa ändå.

LCD 16×2: ett instrument utan dator

Ett teckenfönster på två rader med sexton tecken gör bygget fristående. Modulerna i kitet har ett litet kort på baksidan som gör om displayens sexton anslutningar till fyra: matning, jord, SDA och SCL. De två sista är en databuss som heter I²C.

I²C tar två av dina analoga pinnar På ett Uno-kort ligger SDA på A4 och SCL på A5. Kopplar du in en I²C-display är alltså bara A0 till A3 kvar för analogRead. Det här är exakt samma sorts fälla som språkreferensen beskriver för Servo och Timer1: ett bibliotek tar hårdvara med sig, och det står inte i din kod. Planera pinnarna innan du kopplar, inte efter.

Varje I²C-enhet har en adress, och displaymodulerna kommer med olika. 0x27 och 0x3F är de två vanliga, men det finns fler, och vilken just din har går inte att se på den. Att ta reda på det är en del av arbetet: ladda upp en I²C-avsökare – de finns som exempel i Arduino-miljön – och läs adressen i seriemonitorn. Fungerar displayen inte alls, och du inte kört avsökaren, är det där du ska börja.

Displayen är också långsam på ett sätt som spelar roll. Varje tecken kräver flera överföringar på bussen, och en full omskrivning av båda raderna – trettiotvå tecken – landar i storleksordningen tio millisekunder. Fyra uppdateringar i sekunden kostar då

4 · 10 ms = 40 ms av varje sekund, alltså 4 %

vilket är oproblematiskt. En uppdatering varje loopvarv skulle däremot göra att loopen inte kan gå fortare än ungefär hundra varv i sekunden, och texten skulle dessutom flimra.

Två vanor gör displayen lugn att titta på:

Den mekaniska visaren

Ett servo med en arm är en visare. Det är den tredje visningsvägen och den enda som ger bygget en mekanisk struktur – utan den är bygget inget mekatroniskt system i kriteriernas mening, hur bra mätningen än är.

Visaren har egenskaper som varken serieporten eller displayen har. Den syns tvärs över rummet. Den visar riktning: att värdet är på väg upp ser du utan att läsa något. Och den visar avvikelse från det normala på en enda blick, förutsatt att skalan är ritad så. Priset är att den bara kan visa en enda storhet, och att den kräver att du gör två saker rätt som inte finns i de andra vägarna: ordningen på räkningen, och skalan.

Kalibrera först, mappa sedan

Det här är guidens viktigaste avsnitt, och det fel det beskriver är besvärligt just för att bygget ser rätt ut när man provar det.

Frestelsen är att göra det i ett steg: mappa råvärdet direkt till en vinkel.

vinkel = map(rå, rå_vid_0_grader, rå_vid_50_grader, 0, 180)

Det ger en visare som står rätt vid båda ändarna av skalan – och fel överallt däremellan. Skälet är att givaren inte är rätlinjig. Råvärdet ändrar sig inte lika mycket per grad överallt, och en rät mappning från råvärde till vinkel ärver den skevheten.

Räkna igenom det med NTC:n från kalibreringsguiden, en tavla graderad 0–50 °C över 180 grader. Rätt vinkel är

vinkel = 180 · T / 50 = 3,6 grader per grad Celsius

Verklig tempRåvärdeRätt vinkelVinkel om du mappar råvärdetVad tavlan då visarFel
0 °C7880,0°0,0°0,0 °C0,0
10 °C68436,0°36,1°10,0 °C+0,0
20 °C56972,0°76,1°21,1 °C+1,1
25 °C51290,0°95,9°26,6 °C+1,6
30 °C456108,0°115,4°32,1 °C+2,1
35 °C403126,0°133,8°37,2 °C+2,2
40 °C354144,0°150,8°41,9 °C+1,9
50 °C270180,0°180,0°50,0 °C0,0

Vinklarna står med en decimal, så att avläsningskolumnen går att räkna ur dem; servot tar förstås ett heltal, och den avrundningen är mindre än servots eget dödband.

Kolumnen längst till höger är hela poängen. Instrumentet är exakt rätt i båda ändarna och över två grader fel på mitten. Och de två ändarna är precis det man kontrollerar när man provar ett nybyggt instrument. Felet överlever därför provkörningen, hamnar i redovisningen, och upptäcks först av den som jämför med en termometer mitt i området.

Räkningen bakom en rad, så att du kan göra om den med dina egna tal. Vid 25 °C är råvärdet 512, och den direkta mappningen ger

(512 − 788) · 180 / (270 − 788) = (−276) · 180 / (−518) = 49 680 / 518 = 95,9°

På en tavla där 180 grader svarar mot 50 °C avläses den vinkeln som

95,9 / 180 · 50 = 26,6 °C

alltså 1,6 grader fel.

Rätt ordning är i två steg. Först råvärde till storhet med din kalibrering, sedan storhet till vinkel med en rät linje. Den andra omvandlingen får vara rätlinjig, för nu är storheten en riktig temperatur.

const float SKALA_MIN  = 0.0;    // grader vid visarens ena andlage
const float SKALA_MAX  = 50.0;   // grader vid det andra
const int   VINKEL_MIN = 10;     // servovinkel vid SKALA_MIN
const int   VINKEL_MAX = 170;    // servovinkel vid SKALA_MAX

int graderTillVinkel(float grader) {
  float begransad = constrain(grader, SKALA_MIN, SKALA_MAX);
  float andel = (begransad - SKALA_MIN) / (SKALA_MAX - SKALA_MIN);
  return VINKEL_MIN + (int)(andel * (VINKEL_MAX - VINKEL_MIN) + 0.5);
}

Kontrollräkna funktionen vid tre punkter, som du alltid ska göra med en egen omvandling. Vid 0,0 grader är andel lika med 0 och svaret blir 10 + 0 = 10. Vid 50,0 är andelen 1 och svaret 10 + 160 = 170. Vid 25,0 är andelen 0,5 och svaret

10 + (int)(0,5 · 160 + 0,5) = 10 + 80 = 90

Mitt emellan, som det ska vara. + 0.5 före omvandlingen till int är avrundning: utan den kapas decimalerna neråt, precis som map() gör.

Och constrain ligger före räkningen, så att ett värde utanför skalan parkerar visaren i ändläget i stället för att skicka servot mot ett stopp. Det var kalibreringsguidens andra halva av map-fällan.

Skalan ska ritas, inte gissas

En halvcirkelformad instrumenttavla. Längs bågen sitter sex streck jämnt fördelade. Vid vänstra änden står siffran 0, mitt uppe står 25 och vid högra änden 50. Från en punkt i halvcirkelns mitt pekar en visare rakt uppåt, mot strecket vid 25. 0 25 50 °C

Räkna ut var strecken ska sitta i stället för att uppskatta. Med servovinklarna 10 till 170 grader över 0 till 50 °C sveper visaren

170 − 10 = 160 grader för 50 °C, alltså 160 / 50 = 3,2 grader per grad Celsius

Ett streck var tionde grad Celsius sitter alltså

10 · 3,2 = 32 grader isär

Har din visare längden 60 mm blir avståndet mellan två streck, mätt längs bågen,

60 mm · 32 · π / 180 = 60 · 0,559 = 33,5 mm

och hela skalans båge

60 · 160 · π / 180 = 60 · 2,793 = 168 mm

Nu vet du hur stor tavlan blir innan du klipper ut den, och du kan rita strecken med gradskiva i stället för på ögonmått.

Hur fint det är meningsfullt att gradera

Tre saker begränsar upplösningen, och den grövsta av dem bestämmer.

Servot är alltså grövst, med god marginal. Ungefär en tredjedels grad Celsius är instrumentets verkliga upplösning, och att gradera tavlan finare än varannan grad vore att låtsas. Ett streck var femte grad, med siffra var tionde, är en ärlig tavla.

Varför 10 och 170 och inte 0 och 180 Ett SG90 är märkt 0–180 grader, men de verkliga ändlägena varierar mellan exemplar. Ett servo som beordras dit det inte kommer surrar mot sitt stopp, drar ström och blir varmt – och drar det tillräckligt mycket startar kortet om, precis som beskrivs i servoguidens avsnitt om strömbehov. Ta tio graders marginal i vardera änden och prova dig fram till dina egna gränser. Du förlorar inget: skalan ritar du ändå själv, efter de vinklar din visare faktiskt når.

Sista detaljen, från område 3: skriv bara till servot när vinkeln ändrats. En write() per loopvarv med samma värde ger ett servo som surrar och drar ström i onödan.

#include <Servo.h>

const int SERVO_PIN = 9;

Servo visare;
int forraVinkeln = -1;      // ett omojligt varde, sa forsta skrivningen alltid sker

void satVisare(int vinkel) {
  if (vinkel != forraVinkeln) {
    visare.write(vinkel);
    forraVinkeln = vinkel;
  }
}

void setup() {
  visare.attach(SERVO_PIN);
}

I industrin och i vardagen

I industrin: i ett ställverk eller ett kontrollrum sitter pekarinstrument kvar bredvid skärmarna, femtio år efter att siffrorna fanns tillgängliga. Skälet är att en visare visar avvikelse snabbare än en siffra gör. Nätfrekvensen ska hållas vid 50 Hz med små marginaler; ett instrument som spänner 49 till 51 Hz över 90 grader ger

90 grader / 2 Hz = 45 grader per hertz

så en avvikelse på 0,1 Hz blir

0,1 · 45 = 4,5 grader

tydligt synlig visarrörelse. En display som växlar mellan 49,9 och 50,1 kräver att du läser, minns och drar ifrån. Vanan att ställa in alla instrument i en rad så att visarna pekar rakt upp vid normalläge bygger på samma tanke: då är en avvikande visare det enda som inte är lodrätt, och den syns utan att ett enda tal läses.

I vardagen: bilens hastighetsmätare är ett instrument som med flit visar fel, och det står i regelverket. EU:s typgodkännanderegler säger att den visade hastigheten aldrig får vara lägre än den verkliga, men gärna högre – upp till tio procent plus fyra kilometer i timmen. Vid en verklig hastighet på 100 km/h får mätaren alltså visa ända upp till

100 + 0,10 · 100 + 4 = 114 km/h

men aldrig 99. Tillverkaren lägger sig medvetet en bit över, eftersom en mätare som visar för lite kan ge föraren fortkörningsböter medan en som visar för mycket bara är irriterande. Skalan är alltså inte konstruerad för att vara sann utan för att felet ska falla åt ett bestämt håll.

Det är precis motsatsen till kravet på ditt bygge, och kontrasten är poängen: ett instrument ska ha ett känt fel som pekar åt ett känt håll. Bilens har det, av ett skäl som går att skriva ned. Ett bygge där skalan är ritad på ögonmått har ett okänt fel åt okänt håll, och det är något helt annat.

Kravställ ditt bygge 3

De sista trettio minuterna av det här passet ägnas åt att bestämma vad ditt bygge 3 ska vara. Hela kravlistan står på byggsidan; det som ska bestämmas nu är de val som allt annat hänger på.

Sportlovet ligger mellan det här passet och arbetspasset Efter den här lektionen är det två veckor till arbetspasset, med kravlistan och kitet hemma hos dig och utan handledning emellan. Det är där bygget ska bli till. Kom till arbetspasset med något halvbyggt och en specifik fråga – "råvärdet står stilla på 1023 fast jag mätt att LDR:n ändrar sig" är en fråga som går att svara på under ett pass. Ett tomt kopplingsdäck är det inte.

Välj din givare

GivareMäterTalar förTalar emot
LDRljus Enklast att koppla och lättast att göra stora, tydliga ändringar med. Kalibrering mot en mobil ljusmätarapp går snabbt. Det finns ingen naturlig enhet du redan har en referens för, om du inte har en app du litar på.
NTCtemperatur Alla guidens exempel går att följa rakt av. En vanlig termometer duger som referens och alla har en. Trögheten gör kalibreringen långsam – räkna en minut per punkt.
Potentiometervinkel eller läge Rätlinjig, snabb och stabil. Referensen är en gradskiva eller en linjal. Ger mindre att skriva om felkällor, eftersom nästan ingenting stör den.
HC-SR04avstånd Ett tumstocksmått är en utmärkt referens och kalibreringen blir övertygande. Kräver pulseIn och en tidsgräns, och ekot uteblir ibland. Mer att felsöka.
DHT11 eller DHT22temperatur och fukt Ett bibliotek gör avläsningen enkel, och du får två storheter. Givaren är redan kalibrerad, så kalibreringskravet blir en kontroll i stället för en kalibrering. Diskutera vid samrådet hur du löser det.

Åtta frågor att svara på innan du bygger

  1. Vilken storhet ska instrumentet visa, och med vilken enhet? En mening. "Rumstemperaturen i grader Celsius."
  2. Vilket område ska tavlan täcka? Från vilket värde till vilket. Det är samma område som dina kalibreringspunkter ska ligga i ändarna av.
  3. Vilken referens ska du kalibrera mot, och hur bra är den? Namnge den. "Termometern i köket, som visar hela grader." Referensens noggrannhet är ett golv för hela ditt instrument.
  4. Vilka två punkter ska du mäta upp, och hur får du fram dem? Konkret: kranvatten och varmvatten, mörker och skrivbordslampa, 10 cm och 100 cm.
  5. Vilket fast motstånd, och varför just det? Räknat ur givarens uppmätta ytterlägen, inte hämtat ur en guide.
  6. Hur ser visaren och tavlan ut? Armens längd, var strecken sitter och hur ofta det står en siffra. Räknat med gradskiva.
  7. Vad händer utanför området? Visaren parkerar i ändläget – och vad mer? En lysdiod, en text, ingenting? Beslutet ska vara ditt och stå i dokumentationen.
  8. Vilka två exempel ska du beskriva ditt system mot? Ett ur industrin och ett ur vardagen. Den frågan är lättast att skjuta upp och dyrast att skjuta upp – den bär hela belägget för F4, och den ska med i redovisningen.

Ta med svaren, tillsammans med samrådsunderlaget, till arbetspasset.

Prova själv

  1. Skriv ut ett värde varje loopvarv i en halv minut och räkna hur många rader du får. Flytta sedan utskriften in i tidsstämpelmönstret med 250 ms intervall och räkna igen. Jämför med de 960 tecken i sekunden räkneexemplet gav.
  2. Koppla in en LCD och kör en I²C-avsökare. Skriv ned adressen din modul har. Kör sedan ett program som skriver ett räknande tal, först med clear() vid varje uppdatering och sedan utan. Titta på skillnaden.
  3. Sätt en arm på servot och skriv ett program som sveper från VINKEL_MIN till VINKEL_MAX och tillbaka. Markera med penna var armen står vid 10, 90 och 170 grader. Kontrollera att avståndet mellan 10 och 90 är lika stort som mellan 90 och 170.
  4. Prova write(0) och write(180) och lyssna. Hör du ett surr står armen mot sitt stopp. Krypa uppåt från 0 och nedåt från 180 tills surret upphör – där har du dina verkliga ändlägen.
  5. Rita tavlan på papper med gradskiva, enligt räkningen i guiden. Mät med linjal att strecken sitter jämnt utmed bågen.
  6. Bygg felet med flit: mappa råvärdet direkt till vinkeln, i ett steg. Kontrollera instrumentet vid båda ändarna – det stämmer. Kontrollera det sedan på mitten mot en termometer. Anteckna avvikelsen, och jämför med tabellen i guiden.

Kontrollfrågor

Varför får inte utskriften ligga direkt i loop() utan tidsstämpel?

Vid 9600 baud ryms 960 tecken i sekunden. En loop som går tusentals varv i sekunden skulle producera mångdubbelt fler, sändbufferten på 64 byte fylls, och Serial.print väntar tills det finns plats. Utskriften blir då en blockering, precis det som område 3 handlade om att bli av med.

Du kopplar in en I²C-display och plötsligt ger analogRead(A4) skräp. Varför?

På ett Uno-kort ligger I²C-bussen på A4 och A5. De två pinnarna används nu av displayen och kan inte längre läsas som analoga ingångar. Flytta givaren till A0 till A3.

Din visare står rätt vid 0 och vid 50 grader men visar 32 när termometern säger 30. Vad är felet?

Omvandlingen görs i ett steg, direkt från råvärde till vinkel. Givarens kurva är inte rät, och skevheten hamnar i vinkeln. Ändarna stämmer per konstruktion, mitten gör det inte. Rätta genom att först räkna om råvärdet till grader med din kalibrering och sedan grader till vinkel med en rät linje.

Din tavla ska visa 10 till 30 °C över servovinklarna 15 till 165. Hur många grader visarrörelse går det på en grad Celsius, och var sitter strecket för 20 °C?

Svepet är 165 − 15 = 150 grader över 30 − 10 = 20 °C, alltså 150 / 20 = 7,5 grader per grad Celsius. 20 °C ligger tio grader upp från skalans början, alltså vid 15 + 10 · 7,5 = 90 grader – rakt upp, mitt i svepet.

Varför skriver man bara till servot när vinkeln ändrats?

Loopen går tusentals varv i sekunden och skulle annars anropa write() lika ofta med samma värde. Servot försöker då hålla sitt läge aktivt hela tiden, surrar och drar ström. Det syns som ett instrument som brummar och ett kort som blir varmt, och i värsta fall startar om.

Varför är det ingen idé att gradera tavlan i tiondels grader Celsius?

Därför att servot inte kan ställa in sig finare än ungefär en grads vinkel, vilket med 3,2 grader per grad Celsius motsvarar ungefär 0,3 °C. En gradering finare än instrumentets upplösning påstår en precision som inte finns – samma fel som att skriva ut fyra decimaler ur en tiobitars omvandlare.

Vanliga fel

Vidare

Kapitlen Funktioner och Bibliotek i språkreferensen hör till den här guiden. Funktionen graderTillVinkel() är områdets andra egna funktion, och den finns av samma skäl som den första: samma tal ska användas på två ställen.

Nästa steg är bygge 3, som sätter ihop hela området till ett system och som redovisas muntligt. Det är kursens första redovisning, och byggsidan beskriver både bygget och hur du förbereder dig för att förklara det.