Arduino Färddator, problem...

C, C++, Pascal, Assembly, Raspberry, Java, Matlab, Python, BASIC, SQL, PHP, etc.
PooShooter
Inlägg: 4
Blev medlem: 10 december 2018, 13:34:23

Arduino Färddator, problem...

Inlägg av PooShooter »

Hej
Har försökt mig på att göra en färddator till båten
Jag använder mig av en flödesmätare som ger 2500 pulser/Liter
En Gps som lämnar RMC
En Arduino uno

Har lyckats få in och presentera farten (knots)
Får in och kan presentera flödet per timme
Problemet är att jag vill kunna visa förbrukningen per Nautiskmil alltså dela flödet per
timme med farten. Nån vänlig själ som kan hjälpa mig i rätt riktning?
Har markerat i koden med rött i de delar jag tror problemet ligger.


/*Delar av kod lånad från http://www.lawicel.se/kod/arduino/GpsLcd1.ino

Exempel På RMC från GPS "$GPRMC,094510.000,A,5609.6095,N,01335.7731,E,0.03,88.49,120913,,,,A*57"

Flödesmätaren ger 2500 pulser per liter */
#include <FreqMeasure.h>
#include <LiquidCrystal.h>

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);


char buffer[120];
//
byte CommaPos[20];
//
byte bufferPos = 0;
byte bufferStat = 0;

char datavalid[2];

char knots[8];
byte CountCommas(void) {

byte tmp;
byte NoOfCommas = 0;

for (tmp = 0; tmp < bufferPos; tmp++) {
if (buffer[tmp] == ',') {
CommaPos[NoOfCommas++] = tmp;
}
}
return NoOfCommas;
}

void extract(char *buf1, char *buf2, byte item) {
byte tmp;

for (tmp = 1; tmp < (CommaPos[item + 1] - CommaPos[item]); tmp++) {
buf1[tmp - 1] = buf2[CommaPos[item] + tmp];
}

buf1[tmp] = 0;
}

byte parseNMEA(void)
{
byte comma = 0;
byte tmp = 0;
byte NoOfCommas;

NoOfCommas = CountCommas();


if (buffer[0] == 'G' && buffer[1] == 'P') {
if (buffer[2] == 'R' && buffer[3] == 'M' && buffer[4] == 'C' ) { // $GPRMC


if (NoOfCommas == 13) {
extract(datavalid, buffer, 1);
if (datavalid[0] == 'A') {
extract(knots, buffer, 6);
}
else {
return 0;
}
}

}
}
return 1;
}
void setup()
{
Serial.begin(9600);
lcd.begin(16, 2);
lcd.setCursor(7, 1);
lcd.print("L/Nm");
FreqMeasure.begin();
}
double sum = 0;
int count = 0;

void loop()

{
char c;
byte result;

if (bufferStat < 2) {
if (Serial.available()) {
c = Serial.read();
if (c == '$') {
bufferStat = 1;
bufferPos = 0;
}
else if (bufferStat == 1) {
if (c == '*') {
buffer[bufferPos] = 0;
bufferStat = 2;
Serial.println(buffer);
}
else if (bufferPos < 120) {
buffer[bufferPos++] = c;
}
else {
bufferPos = 0;
bufferStat = 0;
}
}
}
}
else {
result = parseNMEA();
lcd.setCursor(0, 1);
lcd.print("Kn");
lcd.print(knots);
bufferStat = 0;
}
{
delayMicroseconds(50);
if (FreqMeasure.available()) {
sum = sum +
FreqMeasure.read(); //2500 pp/l * 3600 =L/h
count = count + 1;
if (count > 30) {
float LNm = FreqMeasure.countToFrequency(sum / count / 3600 * 2500 ); // Egentligen ska det vara Freq*3600/2500 men det funkar inte att skriva så??
lcd.setCursor(11, 1); // vill Dividera detta med farten in (knots) för att få ut det som L/distans(Nm)
lcd.print(LNm);
Serial.println(LNm);
sum = 0;
count = 0;
}
}
}
}
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Arduino Färddator, problem...

Inlägg av Icecap »

Från att du börjar mäta de 30 pulser bränsle måste du även mäta sträckan du kommer då - eller ha ett medel av hastigheten under den tid.

Sedan är din timing inte stabil. Du har "delayMicroseconds(50);" med i loopen - men vad ska den göra?
Det kan vara jag som inte fattar Arduino-skiten men hur vet du hur lång tid enheten mäter över?

Jag anser att bränsle-pulserna ska trigga en hårdvara-interrupt och när tillräckligt lång tid (t.ex. 300-500ms) har gått & tillräckligt många pulser har kommit kan man räkna på det hela. Under hela tiden ska det finnas en hastighets-filter som säkra en ganska stabil hastighetsvisning.

Då kan man räkna på det.

Man ska såklart hålla koll på tiden det tar att hämta mätningarna (t.ex. systime() från start till slut), då kan man räkna ut frekvensen enkelt och sedan utföra resten av uträkningen enkelt.
PooShooter
Inlägg: 4
Blev medlem: 10 december 2018, 13:34:23

Re: Arduino Färddator, problem...

Inlägg av PooShooter »

Hej
Det där är finlir vi kan ta sen.
problemet är hur jag delar farten med antal pulser
på nått sätt måste char göras om till float. GPS "$GPRMC,094510.000,A,5609.6095,N,01335.7731,E,0.03,88.49,120913,,,,A*57"
För att sedan delas med L/h

float LNm = FreqMeasure.countToFrequency(sum / count / 3600 * 2500 ); // Efter 2500 vill jag dela med Knots (buffer 6) i exemplet ovan 0.03
Det är det som är problemet
bearing
Inlägg: 11232
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: Arduino Färddator, problem...

Inlägg av bearing »

Först måste du ta reda på förväntad frekvens från sensorn. Sen kan vi välja en lämplig metod.

Låt säga att motorn drar 10l per timme. Då blir det f = 2500 pulser per liter * 10 l/h / 3600 sekunder/h = 7 pulser per sekund.

FreqMeasure.read() returnerar en 32-bit (unsigned long) som innehåller antalet klockcykler sedan förra mätningen. Om vi antar 16Mhz och 8 pulser per sekund, blir ett typiskt värde 2 miljoner. Och detta är ok, efterom att en 32-bitare kan lagra ca 4 miljarder, d.v.s 2000ggr så stort. Men vid låga flöden kan det kanske bli problem. Min bil brukar dra 0.5-1l/timme på tomgång, d.v.s motsvarande 20-40 miljoner, så även vid tomgång borde du inte få problem med overflow, så allt verkar OK så långt.

För att få bättre upplösning, samt jämna ut värdena lite, har du valt att summera flera mätningar (i en double) och göra beräkningen efter 31 pulser. Detta verkar också OK. Men jag hade inte använt en double, utan en unsigned long. Det borde nämligen inte bli overflow även trots 32 summerade mätningar (32 * 40 miljoner < 4 miljarder). Och jag hade gjort beräkningen efter 32 pulser (eller valfri jämn 2-potens), eftersom att detta gör att du kan göra en mycket snabbare division om du vill. Men detta är inte så viktigt, det handlar bara om att koden går långsammare p.g.a omvandlingar mellan heltal och flyttal hela tiden.

Sen kommer vi till beräkningen. För det första borde konstanterna (2500 och 3600) ligga utanför funktionsanropet. För det andra har du skrivit fel i formeln. Om vi tittar på min beräkning ovan, ser vi att frekvensen ska multipliceras med 3600 och divideras med 2500 för att blir korrekt. (7 pps* 3600 s/h / 2500 ppl = 10l/h) (edit: detta visste du visst, och hade skrivit i en kommentar)

Kod: Markera allt

unsigned long sum = 0;
unsigned short count = 0;
...
if (count >= 32)
{
  float pulses_per_second= FreqMeasure.countToFrequency(sum / count);
  float liters_per_hour = pulses_per_second * 3600.0 / 2500.0;
  float liters_per_nm = liters_per_hour / speed_in_knots;
...
Som du ser blir det mycket enklare att läsa och förstå koden om man delar upp den på flera rader med några lämpligt namngivna variabler. Och det går inte långsammare på något sätt (om detta var anledningen till att du lagt allt på en rad).
PooShooter
Inlägg: 4
Blev medlem: 10 december 2018, 13:34:23

Re: Arduino Färddator, problem...

Inlägg av PooShooter »

Tack för ett utförligt svar.
Det löser dock inte problemet..
Hur deklarerar jag speed_in_knots?
Får felmeddelande
”invalid operands of types ’float’ and char ∞’ to binary ’operator/’ ”

Tror att speed_in_knots tolkas som char och går inte att räkna med.
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Arduino Färddator, problem...

Inlägg av Icecap »

Den ska deklareras som float (eller bättre double) men du måste leta upp hastighetsangivelsen i knop (text = "0.03") och köra en:
speed_in_knots = atof(Texten);

Jag har gjort det i den dekodning jag har gjort av NMEA-data vid att börja från början och sedan leta upp komma efter komma, texten som kommer omedelbart efter rätt komma blir då omgjort till ett värde via atof() eller atoi().
Senast redigerad av Icecap 11 december 2018, 15:08:12, redigerad totalt 1 gång.
Användarvisningsbild
Jan Almqvist
Inlägg: 1580
Blev medlem: 1 oktober 2013, 20:48:26
Ort: Orust

Re: Arduino Färddator, problem...

Inlägg av Jan Almqvist »

På Arduino Uno är float och double samma.

https://www.arduino.cc/reference/en/lan ... es/double/
PooShooter
Inlägg: 4
Blev medlem: 10 december 2018, 13:34:23

Re: Arduino Färddator, problem...

Inlägg av PooShooter »

Tack för hjälpen , atof löste problemet.

Trodde float var för få decimaler och double för många decimaler.
Har bara två så jag kör med float.

Åter igen Stort TACK!!!
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Arduino Färddator, problem...

Inlägg av Icecap »

Jo, float har begränsat upplösning och double "är bättre" - om alltså inte det var så att C-standarden medger att de kan vara det samma storlek och alltså i verkligheten "bara" float.

Själv måste jag ange att mina GCC-projekt kör C11, då får jag tillgång till "riktiga" double.
bearing
Inlägg: 11232
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: Arduino Färddator, problem...

Inlägg av bearing »

Har svårt att se en situation där ett 32-bit flyttal inte duger. Måste vara något väldigt specifikt. I detta fallet hade ett 16-bit flyttal dugit, om kompilatorn haft stöd för det.

Angående problemet handlar det väl som du säger mest om att flytta sig till rätt komma (',') i strängen. Och sedan konvertera till float.
Användarvisningsbild
Icecap
Inlägg: 26106
Blev medlem: 10 januari 2005, 14:52:15
Ort: Aabenraa, Danmark

Re: Arduino Färddator, problem...

Inlägg av Icecap »

Tja - hade det varit en 32-bit flyttal var det kanske en annan sak men double som fyllar 32 bytes består ju egentligen av 3 bytes (24 bits) som håller talet och en byte som håller mantissan. Javisst kan det vara "för många" så man ska ju fundera lite över vad som faktisk behövs i det givna projekt.
bearing
Inlägg: 11232
Blev medlem: 2 mars 2006, 01:01:45
Ort: Ängelholm

Re: Arduino Färddator, problem...

Inlägg av bearing »

På en 8-bitare kan det nog ta hundratals eller tusentals cykler att göra en flyttalsoperation i 64-bit flyttal. Så jag tror att det är klokt att begränsa sig till 32-bit.

Sen vet jag att på många mikrokontrollers med stöd för flyttalsoperationer gäller det bara 32-bit. 64-bit tar mycket längre tid, Även på sådana mikrokontrollers.

Men ok, det kanske inte spelar någon roll i detta fallet när det kan ta 30 sekunder mellan beräkningarna.

Angående upplösning har jag sällan stött på problem som i praktiken behöver större noggrannhet än 1 promille. Så 10-12bitar duger oftast. Då är ju 24-bitar långt mer än nödvändigt.
Skriv svar