Arduino som övervakar båtmotorn
Re: Arduino som övervakar båtmotorn
Tack för svaret. När det regnar nästa gång ska jag göra en testuppkoppling hemma i köket. Sedan gäller det att göra samma sak i båten, måste ha någon bra plats för dispalyen t.ex. Just nu när det är sommarväder är det båt-åka som gäller (utan motorövervakning).
Re: Arduino som övervakar båtmotorn
Nu har jag gjort en första testinkoppling. Allt fungerar som det ska, även om displayen har en lite snäv betraktningsvinkel. Lite finjustering av koden och några apparatlådor och kopplingsplintar så är det dags att montera den i båten.
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Re: Arduino som övervakar båtmotorn
Det funkar fint. Men, när jag kopplade ihop allt med lödningar och skruvplintar i stället för experimentkort fick jag bara konstiga mätvärden (+20 grader blev -125 grader). Dags att labba igen.
Re: Arduino som övervakar båtmotorn
Färdiglabbat och fungerar som det ska.
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Re: Arduino som övervakar båtmotorn
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Re: Arduino som övervakar båtmotorn
Mycket intressant!!
Då skulle man kunna lägga till en givare för hur mycket motorn är trim/tilt i %
Få nog börja testa lite också
Då skulle man kunna lägga till en givare för hur mycket motorn är trim/tilt i %
Få nog börja testa lite också
Re: Arduino som övervakar båtmotorn
Nu är den på plats. Tre temperatursensorer och en hallelementsensor på motorn.
Sensorn för kylvattnet placerades på röret ut från motorn till värmeväxlaren. Sensorn för avgaserna placerades på utsidan av utloppet från limpan. Jag hittade inte någon bra plats att mäta oljetemperaturenmpå så jag fäste den tredje sensorn invid insprutarna på toppen.
Efter en misslyckad montering av magneten på svänghjulet (magneten lossnade av centrifugalkraften och bara försvann), monterade jag en annan magnet tätt intill mittmuttern på svänghjulet där den inte påverkas av så stora krafter.
Sensorkablarna samlas ihop i en låda i motorrummet och en 4-ledare leder signalerna till Arduinon som sitter i en större låda vid styrplatsen. En tredje låda på instrumentpanelen innehåller displayen.
Allt fungerar som det ska förutom att varvtalsvisningen någon gång då och då visar 6000 rpm eller ett stort värde (10 siffror). Jag tror inte det beror på störningar utan något jag missat i koden.
Kan någon av er se varför?
Sensorn för kylvattnet placerades på röret ut från motorn till värmeväxlaren. Sensorn för avgaserna placerades på utsidan av utloppet från limpan. Jag hittade inte någon bra plats att mäta oljetemperaturenmpå så jag fäste den tredje sensorn invid insprutarna på toppen.
Efter en misslyckad montering av magneten på svänghjulet (magneten lossnade av centrifugalkraften och bara försvann), monterade jag en annan magnet tätt intill mittmuttern på svänghjulet där den inte påverkas av så stora krafter.
Sensorkablarna samlas ihop i en låda i motorrummet och en 4-ledare leder signalerna till Arduinon som sitter i en större låda vid styrplatsen. En tredje låda på instrumentpanelen innehåller displayen.
Allt fungerar som det ska förutom att varvtalsvisningen någon gång då och då visar 6000 rpm eller ett stort värde (10 siffror). Jag tror inte det beror på störningar utan något jag missat i koden.
Kan någon av er se varför?
Kod: Markera allt
#include <DallasTemperature.h>
#include <OneWire.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
OneWire sensorBus(4); //sensors connected to digital pin 4
DallasTemperature sensors(&sensorBus);
// Connect the LCD with SDA to analog pin 4 and SCL to analog pin 5
// set the LCD address to 0x27 (check the address)
// Set the pins on the I2C chip used for LCD connections:
// addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
unsigned long result = 0;
DeviceAddress Oiltemp =
{
0x28, 0xFF, 0x18, 0x53, 0x02, 0x15, 0x04, 0x67
};
DeviceAddress Watertemp =
{
0x28, 0xFF, 0x58, 0x54, 0x02, 0x15, 0x04, 0x08
};
DeviceAddress Exhausttemp =
{
0x28, 0xFF, 0x07, 0x9F, 0x02, 0x15, 0x03, 0xDC
};
int alarm = 7; //the pin number of the alarm 7
void setup()
{
// Read and display sensor addresses
delay(1000);
Serial.begin(9600);
sensors.begin();
lcd.begin(16, 2); // initialize the lcd for 16 chars 2 lines, turn on backlight
// ------- Quick 3 blinks of backlight -------------
for(int i = 0; i < 3; i++)
{
lcd.backlight();
delay(250);
lcd.noBacklight();
delay(250);
}
lcd.backlight(); // finish with backlight on
// 3 beeps with alarm
pinMode(alarm, OUTPUT);
for(int i = 0; i < 3; i++)
{
digitalWrite(alarm, HIGH);
delay(250);
digitalWrite(alarm, LOW);
delay(250);
}
// NOTE: Cursor Position: (CHAR, LINE) start at 0
lcd.setCursor(0, 0); //Start at character 0 on line 0
lcd.print("Varvtal"); //rad 1
lcd.setCursor(0, 1);
lcd.print("Temperatur"); //rad 2
delay(5000);
attachInterrupt (0, inputPulse, RISING); //pulse imput from rev sensor (digital pin 2)
sensors.setResolution(Oiltemp, 10);
sensors.setResolution(Watertemp, 10);
sensors.setResolution(Exhausttemp, 10);
}
void loop()
{
sensors.requestTemperatures(); // Send the command to get temperatures
Serial.print(sensors.getTempCByIndex(0)); //print temp on screen
Serial.println(" Degrees C");
Serial.print(60000 / result); //print rpm on Screen
Serial.println(" rpm");
lcd.clear();
lcd.setCursor(4, 0);
lcd.print(60000 / result); //print rpm on display
lcd.print(" rpm ");
if (6000 / result > 2500) //alarm on high rpm
{
digitalWrite(alarm, HIGH); //alarm signal output
lcd.setCursor(0, 1);
lcd.print("WARNING HIGH rpm");
delay(2000);
}
else
digitalWrite(alarm, LOW);
sensors.requestTemperatures();
lcd.setCursor(0, 1); //print temp on display
lcd.print("Water: ");
printTemperature(Watertemp);
delay (2000);
lcd.clear();
lcd.setCursor(4, 0);
lcd.print(60000 / result); //print rpm on display
lcd.print(" rpm ");
lcd.setCursor(0, 1);
lcd.print("Oil: ");
printTemperature(Oiltemp);
delay (2000);
lcd.clear();
lcd.setCursor(4, 0);
lcd.print(60000 / result); //print rpm on display
lcd.print(" rpm ");
lcd.setCursor(0, 1);
lcd.print("Exhaust: ");
printTemperature(Exhausttemp);
delay (2000);
}
void printTemperature(DeviceAddress deviceAddress) //read sensors
{
float tempC = sensors.getTempC(deviceAddress);
lcd.print(tempC);
lcd.print(" C ");
if (tempC > 90.0) //alarm on high temp.
{
digitalWrite(alarm, HIGH); //alarm signal output
lcd.setCursor(0, 0);
lcd.print(" WARNING TEMP. ");
delay(2000);
}
else
digitalWrite(alarm, LOW);
}// End printTemperature
void inputPulse() //interrupt - pulse input digital pin 2
{
currentMillis = millis(); //read millis
result = currentMillis - previousMillis; //rpm
previousMillis = currentMillis; //prepare for next pulse
}
Du har inte behörighet att öppna de filer som bifogats till detta inlägg.
Re: Arduino som övervakar båtmotorn
Lite ändringar i koden:
Kod: Markera allt
#include <DallasTemperature.h>
#include <OneWire.h>
#include <LiquidCrystal_I2C.h>
#include <Wire.h>
OneWire sensorBus(4); //sensors connected to digital pin 4
DallasTemperature sensors(&sensorBus);
// Connect the LCD with SDA to analog pin 4 and SCL to analog pin 5
// set the LCD address to 0x27 (check the address)
// Set the pins on the I2C chip used for LCD connections:
// addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Set the LCD I2C address
unsigned long previousMillis = 0;
unsigned long currentMillis = 0;
unsigned long result = 0;
unsigned long rpm = 0;
DeviceAddress Oiltemp =
{
0x28, 0xFF, 0x18, 0x53, 0x02, 0x15, 0x04, 0x67
};
DeviceAddress Watertemp =
{
0x28, 0xFF, 0x58, 0x54, 0x02, 0x15, 0x04, 0x08
};
DeviceAddress Exhausttemp =
{
0x28, 0xFF, 0x07, 0x9F, 0x02, 0x15, 0x03, 0xDC
};
int alarm = 7; //the pin number of the alarm
float tempC;
void setup()
{
// Read and display sensor addresses
delay(1000);
Serial.begin(9600);
sensors.begin();
lcd.begin(16, 2); // initialize the lcd for 16 chars 2 lines, turn on backlight
// ------- Quick 3 blinks of backlight -------------
for(int i = 0; i < 3; i++)
{
lcd.backlight();
delay(250);
lcd.noBacklight();
delay(250);
}
lcd.backlight(); // finish with backlight on
// 3 beeps with alarm
pinMode(alarm, OUTPUT);
for(int i = 0; i < 3; i++)
{
digitalWrite(alarm, HIGH);
delay(250);
digitalWrite(alarm, LOW);
delay(250);
}
// NOTE: Cursor Position: (CHAR, LINE) start at 0
lcd.setCursor(0, 0); //Start at character 0 on line 0
lcd.print("Varvtal"); //rad 1
lcd.setCursor(0, 1);
lcd.print("Temperatur"); //rad 2
delay(5000);
attachInterrupt (0, inputPulse, RISING); //pulse imput from rev sensor (digital pin 2)
sensors.setResolution(Oiltemp, 10);
sensors.setResolution(Watertemp, 10);
sensors.setResolution(Exhausttemp, 10);
lcd.clear();
}
void loop()
{
sensors.requestTemperatures();
lcd.setCursor(0, 1); //print temp on display
lcd.print("Water: ");
printTemperature(Watertemp);
if (tempC > 70) //alarm on high temp.
{
digitalWrite(alarm, HIGH); //alarm signal output
lcd.setCursor(0, 0);
lcd.print(" WARNING TEMP. ");
delay(1000);
}
else
digitalWrite(alarm, LOW);
lcd.setCursor(0, 1);
lcd.print("Oil: ");
printTemperature(Oiltemp);
if (tempC > 100) //alarm on high temp.
{
digitalWrite(alarm, HIGH); //alarm signal output
lcd.setCursor(0, 0);
lcd.print(" WARNING TEMP. ");
delay(1000);
}
else
digitalWrite(alarm, LOW);
lcd.setCursor(0, 1);
lcd.print("Exhaust: ");
printTemperature(Exhausttemp);
if (tempC > 70) //alarm on high temp.
{
digitalWrite(alarm, HIGH); //alarm signal output
lcd.setCursor(0, 0);
lcd.print(" WARNING TEMP. ");
delay(1000);
}
else
digitalWrite(alarm, LOW);
}
void printTemperature(DeviceAddress deviceAddress) //read sensors and print result
{
// Read temp
float tempC = sensors.getTempC(deviceAddress);
// Print temp
lcd.print(tempC);
lcd.print(" C ");
// Print RPM
rpm = 60000 / result;
if (rpm < 4000) //filter out invalid readings
{
lcd.setCursor(4, 0);
lcd.print(rpm); //print rpm on display
lcd.print(" rpm ");
if (rpm > 2500) //alarm on high rpm
{
digitalWrite(alarm, HIGH); //alarm signal output
lcd.setCursor(0, 1);
lcd.print("WARNING HIGH rpm");
delay(1000);
}
else
digitalWrite(alarm, LOW);
delay(1000);
}
}// End printTemperature
void inputPulse() //interrupt - pulse input digital pin 2
{
currentMillis = millis(); //read millis
result = currentMillis - previousMillis; //rpm
previousMillis = currentMillis; //prepare for next pulse
}
Re: Arduino som övervakar båtmotorn
Det gick inte alls. Den visar ibland brara två temperaturer och ibland bara en. Dessutom blir det felaktigt övervarvslarm oftare än tidigare. Jag skulle uppskatta ett tips.
Jag får justera koden och försöka igen. Tyvärr kan jag inte ta med datorn till båten, är tvungen att ta hem Arduinon och justera koden och någon dag senare testa.
Jag får justera koden och försöka igen. Tyvärr kan jag inte ta med datorn till båten, är tvungen att ta hem Arduinon och justera koden och någon dag senare testa.
- Jan Almqvist
- Inlägg: 1580
- Blev medlem: 1 oktober 2013, 20:48:26
- Ort: Orust
Re: Arduino som övervakar båtmotorn
Är det OK att anropa funktionen millis() från interruptet som du gör?
Edit: Om interruptet inkl. anrop till millis() tar lång kan du få ett nytt interrupt innan du är klar med det första dvs du kanske har ett reentrancy-problem?
Ett alternativ vore annars att bara räkna upp en räknare för antal pulser där. Anrop av millis(), nollställning av räknare och uträkning skulle isf. kunna göras i funktionen loop() med ett visst tidsintervall t.ex var 100:e eller 1000:e ms.
(Anar att denna metod skulle nog behöva någon slags glidande medelvärdesberäkning för att bli stabil, ffa på låga varv.)
Edit: Om interruptet inkl. anrop till millis() tar lång kan du få ett nytt interrupt innan du är klar med det första dvs du kanske har ett reentrancy-problem?
Ett alternativ vore annars att bara räkna upp en räknare för antal pulser där. Anrop av millis(), nollställning av räknare och uträkning skulle isf. kunna göras i funktionen loop() med ett visst tidsintervall t.ex var 100:e eller 1000:e ms.
(Anar att denna metod skulle nog behöva någon slags glidande medelvärdesberäkning för att bli stabil, ffa på låga varv.)
Re: Arduino som övervakar båtmotorn
Tidsintervallet mellan interrupt är alltid mer än 20 ms. Jag trodde att dessa kommandon skulle hinnas med. Egentligen sparar jag ju bara millis-värdet:
Jag förstår inte riktigt hur jag ska göra för att få till det du föreslår.
Kod: Markera allt
void inputPulse()
{
currentMillis = millis();
result = currentMillis - previousMillis;
previousMillis = currentMillis;
}
- Jan Almqvist
- Inlägg: 1580
- Blev medlem: 1 oktober 2013, 20:48:26
- Ort: Orust
Re: Arduino som övervakar båtmotorn
Jag var förmodligen på fel spår men såg kanske en annan sak när jag googlade. Kan det behövas ett 'volatile' i din kod?
https://www.arduino.cc/en/Reference/Volatile
Kod: Markera allt
volatile unsigned long result = 0;
Arduino som övervakar båtmotorn
Jag ska ta bort övervarvslarmet och lägga in "volatile". Testar i helgen.
Kanske Metro library eller Timer library skulle vara en annan lösning. Då kan interrupten bara räkna pulser.
Kanske Metro library eller Timer library skulle vara en annan lösning. Då kan interrupten bara räkna pulser.
Re: Arduino som övervakar båtmotorn
Jag skulle nog deklarerat variablerna globalt (dvs utanför funktionen), då överlever de ju garanterat, fast risken är ju att man råkar använda dem på fel ställe.
Jag har inte orkat kolla på din kod, men jag har som nån labb tidigare skrivit en 'frekvensmätar'-kod som mäter tiden på övre och undre flanken på inkommande signal på en digitalingång, interruptstyrt, och det verkade funka riktigt bra utan "fladder". Jag är rätt säker på att jag använde micros och inte millis. Micros verkar wrappa efter 70 minuter, se till att det blir rätt med aritmetiken både kring detta och signed/unsigned.
P.S. en vanlig funktionsgenerator, gärna med TTL-utgång, är rätt bra att ha för att testa den här typen av grejer. När jag labbade använde jag en funktionsgenerator som dessutom har ställbar asymetri på fyrkantvåg. Jag körde dessutom med en extern frekvensmätare parallellt (fast på "vanliga" utgången) och enligt den så mätte min kod förhållandevis rätt.
För en varvräknare så kan det kanske vara en bra idé att lagra ett antal mätningar i en ringbuffert och visa medelvärde på de senaste mätningarna om de senaste är tillräckligt nära varandra, för att slippa fladder i visningen. När varvtalet ändras snabbare så är det däremot vettigt att visa senaste utan medelvärdesbildning för att få så snabb visning som möjligt, antar jag.
Jag har inte orkat kolla på din kod, men jag har som nån labb tidigare skrivit en 'frekvensmätar'-kod som mäter tiden på övre och undre flanken på inkommande signal på en digitalingång, interruptstyrt, och det verkade funka riktigt bra utan "fladder". Jag är rätt säker på att jag använde micros och inte millis. Micros verkar wrappa efter 70 minuter, se till att det blir rätt med aritmetiken både kring detta och signed/unsigned.
P.S. en vanlig funktionsgenerator, gärna med TTL-utgång, är rätt bra att ha för att testa den här typen av grejer. När jag labbade använde jag en funktionsgenerator som dessutom har ställbar asymetri på fyrkantvåg. Jag körde dessutom med en extern frekvensmätare parallellt (fast på "vanliga" utgången) och enligt den så mätte min kod förhållandevis rätt.
För en varvräknare så kan det kanske vara en bra idé att lagra ett antal mätningar i en ringbuffert och visa medelvärde på de senaste mätningarna om de senaste är tillräckligt nära varandra, för att slippa fladder i visningen. När varvtalet ändras snabbare så är det däremot vettigt att visa senaste utan medelvärdesbildning för att få så snabb visning som möjligt, antar jag.