The purpose of this project is to log the battery current and voltage of a Diver Propulsion Vehicle (DPV) in order to get insight in the power usage during the dive at various speeds. The data is logged on a micro-SD card, providing a virtually unlimited amount of logging, and easy read-out.
Key features are:
- Low weight in order to minimize influence on the buoyancy of the DPV
- Easy to install
- Minimal impact on the reliability of the DPV - Due to the magnetic current sensor no wires need to be interrupted
Components
1×
Hobbytronics Ardulog
Arduino-compatible logger with micro-SD card
1×
Honeywell CSNR161
feed-back magnetic current sensor
1×
RECOM R-78C5.0-1.0
Switching regulator 8-42V to 5V
The logger is built on proto-board according to the following schematic:
The following images show the locations of the components and the layout of the 'tracks':
2
Step 2
Program the Ardulog using the Arduino software
/*
Ardulog voltage/current logger
Copyright (c) 2015, Rob Reilink
All rights reserved.
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its contributors may
be used to endorse or promote products derived from this software without
specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
OF THE POSSIBILITY OF SUCH DAMAGE.
*/#include <SPI.h>#include <SD.h>constint chipSelect = 10;
constint ledGreen = 5;
constint ledOrange = 13; // shares pin with SD card sck -- only used in fatal()constint cardDetect = 6;
constfloat calibration0 = 0.04271698113207547; // gain for AD channel 0constfloat calibration1 = 0.026728723404255316; // gain for AD channel 1char * logdir = "/log";
String filename;
unsignedlong prevmillis = 0;
voidfatal(char *message){
Serial.println(message);
for(;;) {
digitalWrite(ledGreen, HIGH);
pinMode(ledOrange, OUTPUT);
SPI.end();
digitalWrite(ledOrange, HIGH);
delay(100);
digitalWrite(ledOrange, LOW);
delay(100);
digitalWrite(ledOrange, HIGH);
delay(100);
digitalWrite(ledOrange, LOW);
delay(100);
digitalWrite(ledOrange, HIGH);
delay(100);
digitalWrite(ledOrange, LOW);
delay(400);
}
}
boolean cardDetected(){
return !digitalRead(cardDetect);
}
voidsetup(){
// Open serial communications and wait for port to open:
Serial.begin(57600);
pinMode(ledGreen, OUTPUT);
pinMode(ledOrange, OUTPUT);
pinMode(2, OUTPUT);
Serial.println("Reset");
if (!cardDetected()) {
fatal("No card present");
}
Serial.print("Initializing SD card...");
// see if the card is present and can be initialized:if (!SD.begin(chipSelect)) {
fatal("Card failed, or not present");
}
if (!SD.mkdir(logdir)) {
fatal("Could not create log dir");
}
Serial.println("ok");
//writeline("==================");// find new filenameint number = 1;
while(1) {
filename = "0000" + String(number);
filename = String(logdir) + String("/") + filename.substring(filename.length()-5) + ".txt";
if (!SD.exists((char*)filename.c_str())) {
break;
}
number+=1;
if (number==10000) {
fatal("Maximum number of log files exceeded");
}
}
prevmillis = millis();
// setup timer 1 for 10Hz measurements
cli();
TCCR1A = 0;
TCCR1B = 0;
TCNT1 = 0;
OCR1A = 6250 - 1;
TCCR1B = _BV(WGM12) | _BV(CS12) ; // 16MHz :256
TIMSK1 |= _BV(OCIE1A);
sei();
}
byte toggle;
long filterAD0 = 0;
long filterAD1 = 0;
int numAD = 0;
ISR(TIMER1_COMPA_vect) {
toggle = !toggle;
digitalWrite(2, toggle);
analogRead(0); // dummy read reduces crosstalk
filterAD0 += (analogRead(0) - filterAD0 / 10);
analogRead(1); // dummy read reduces crosstalk
filterAD1 += (analogRead(1) - filterAD1 / 10);
numAD += 1;
}
voidwriteline(String line){
File logFile;
byte written = 0;
if (!cardDetected()) {
fatal("SD card removed");
}
logFile = SD.open(filename.c_str(), FILE_WRITE);
if (logFile) {
written = logFile.println(line);
if (written) {
Serial.println(line);
digitalWrite(ledGreen, HIGH);
delay(100);
digitalWrite(ledGreen, LOW);
}
}
logFile.close();
// in case of error abort to prevent writing on a newly inserted sd cardif (!written) {
fatal("Error writing to the SD card");
}
}
voidloop(){
// make a string for assembling the data to log:
String dataString = "";
long ad0, ad1;
do {
cli();
if (numAD<10) {
sei();
continue;
}
} while(0);
// interrupts are disabled and we have enough samples;
ad0 = filterAD0 / 10;
ad1 = filterAD1 / 10;
numAD = 0;
sei();
dataString += String(calibration0 * ad0, 3);
dataString += ",";
dataString += String(calibration1 * ad1, 3);
writeline(dataString);
while (millis() - prevmillis < 1000);
prevmillis += 1000;
}
3
Step 3
Installing:
- Build the electronics into a casing
- Remove the red battery cable terminal from its connector. Pass it through the current sensor in its positive current direction (indicated by an arrow on the case). Connect the positive supply lead of the logger to the connector terminal and insert the terminal back into the connector
- Remove the black battery cable terminal, connect the negative supply lead of the logger, and re-insirt the terminal into the connector