Go Down

Topic: Help With DS18B20 Values (Read 1 time) previous topic - next topic

Nov 19, 2013, 02:16 pm Last Edit: Nov 19, 2013, 02:17 pm by skitzo2000 Reason: 1
Hey Everyone, I've been working on a beer automation project.  I realize theres a lot of solutions to this idea, but I really wanted to build mine from scratch seeing that I have a lot of extra parts lying around, and in the end I'll understand the relationships from the electronics to the code much better.

I've created a simple temperature logger using an arduino deci.  and a really old laptop running debian.  Everything seems to work smoothly, I'm logging the data using python and the pyserial library, and storing values into MySql.  However pretty often I'm getting a 0.00 temp in my data stream.  The weird thing, is that if I use Screen to output the data(no gui just cl), I never see 0.00 on the screen, so I think theres something wrong with the timing between my sensor/arduino and python.  I was hoping someone could look at my code and tell me what I'm doing wrong.  I'm extremely new to python in general, but I've been toying with the arduino for a while now.  This is the first project I've ever done data logging with.

Arduino Code:
Code: [Select]

#include <OneWire.h>
#include <DallasTemperature.h>

// Data wire is plugged into port 10 on the Arduino
#define ONE_WIRE_BUS 10

// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);

// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);

// arrays to hold device address
DeviceAddress insideThermometer;

void setup(void)
{
 // start serial port
 Serial.begin(9600);
 // locate devices on the bus
 sensors.begin();
 if (!sensors.getAddress(insideThermometer, 0)) Serial.println("Unable to find address for Device 0");

 // set the resolution to 9 bit (Each Dallas/Maxim device is capable of several different resolutions)
 sensors.setResolution(insideThermometer, 9);
}

// function to print the temperature for a device
void printTemperature(DeviceAddress deviceAddress)
{
 float tempC = sensors.getTempC(deviceAddress);
 Serial.println(DallasTemperature::toFahrenheit(tempC)); // Converts tempC to Fahrenheit
}

void loop(void)
{
 // call sensors.requestTemperatures() to issue a global temperature
 // request to all devices on the bus
 sensors.requestTemperatures(); // Send the command to get temperatures
 
 // It responds almost immediately. Let's print out the data
 printTemperature(insideThermometer); // Use a simple function to print out the data
 delay(1000);
}

// function to print a device address
void printAddress(DeviceAddress deviceAddress)
{
 for (uint8_t i = 0; i < 8; i++)
 {
   if (deviceAddress[i] < 16) Serial.print("0");
   Serial.print(deviceAddress[i], HEX);
 }



Python Script Running Every minute via Cron:
Code: [Select]

#!/usr/bin/python

import serial
import MySQLdb
#establish connection to MySQL. You'll have to change this for your database.
dbConn = MySQLdb.connect("localhost","myUser","MyPassword","MyDB") or die ("could not connect to database")
#open a cursor to the database
cursor = dbConn.cursor()

device = '/dev/ttyUSB0' #this will have to be changed to the serial port you are using
try:
 #print "Trying...",device
 arduino = serial.Serial(device, 9600, timeout = 1)
except:
 print "Failed to connect on",device    

try:
 data = arduino.readline()  #read the data from the arduino
 #print data
 pieces = data          #.split("\t")  #split the data by the tab
 #Here we are going to insert the data into the Database
 try:
   cursor.execute("INSERT INTO arduinoTemp (tempF) VALUES (%s)", (pieces))
   #print "Inserting:",data
   dbConn.commit() #commit the insert
   cursor.close()  #close the cursor
 except MySQLdb.IntegrityError:
   print "failed to insert data"
 finally:
   cursor.close()  #close just incase it failed
except:
 print "Failed to get data from Arduino!"


Thanks for taking the time to read.

Nick_Pyner

It all seems incredibly complicated.  Why don't you just use a standard arduino programme and send the data to a terminal or maybe even straight to Excel?

The long term goal is an HTML/PHP/Mysql based dashboard.

There is no gui on this laptop, it is not windows its debian, so no excel.

I'm confused by the statement standard arduino code,  The top section of code is standard arduino code?

wildbill

What do you get from your debugging prints in python, once you uncomment them?

Nick_Pyner


The long term goal is an HTML/PHP/Mysql based dashboard.

OK, you actually have a goal so I probably shouldn't have asked the question.
Quote
There is no gui on this laptop, it is not windows its debian, so no excel.

I assume debian is an operating system so I guess there is an excel equivalent that runs under it, and so it's fair to assume that there would be a macro for that which allows an Arduino to feed data directly to it.
Quote
I'm confused by the statement standard arduino code,  The top section of code is standard arduino code?

It doesn't look too non-standard. It's the subsequent python stuff which made me query it. I guess the python is only required  because of the abovementioned goal.

WildBill, When I uncomment the debug lines, and run this from command line, I get the expected results so:
trying...And then the hex id for the device
inserting... 64.40  <--Current temp for the probe.

I've run it a ton of times from command line and always get an expected result.

It only seem to pull the null values when its running via cron every minute.  The default value for null is 0.00

Since the arduino is spitting out the current temp value via serial every second I assumed I would always get a value back, but maybe I need to go to a more push pull type of setup for the return value to get more consistent results?

Nick_Pyner
Debian is a FreeBSD/linux variant and its extremely flexible and stable. 
When I said old laptop, I mean really friggin old like circa 1996.  It was lying around doing nothing and Debian manages to work pretty well on it.

Everything is command line operated(I don't even go to the laptop to access it I use SSH over the network), so the best options for data logging are either a CSV file or a database like MySql.  I prefer MySql because I'm extremely familiar with its inter workings, and already have a stock library to build out the website with.

MySql is essentially Excel in this situation, and Python is the most convenient Macro language to perform the inserts to MySql.

wildbill

I'd want to see what the cron version is working with. Can you push that debug data to a log file?

I haven't done that yet, but I will if it continues to throw strange errors.  I currently have a log file that catches the errors, but it doesn't write a timedate stamp, so I'll need to add that in to make the data a little more verbose.

I realized that the python readline function will automatically shut off once an new line is sent.  So I upped it to a two second timeout and things seem to be more stable so far.  From my reading around the web, I noted that the Temp sensor library can get bogged down at times and take a little longer than normal to respond. So even though I have a 1 second delay the read function may be taking as much as .75 seconds to respond, meaning that an actual cycle can take as long a 1.75 seconds.

I'll have to let it run for another few hours to know for sure if that is a true fix.  I still imagine there's an opportunity for it to accidentally jump in during the middle of the serial data write function giving me half data, but so far its working much better than before.

Nick_Pyner


I noted that the Temp sensor library can get bogged down at times and take a little longer than normal to respond. So even though I have a 1 second delay the read function may be taking as much as .75 seconds to respond, meaning that an actual cycle can take as long a 1.75 seconds.


I don't think that is the cause of your problem. The DS18B20 needs a delay of about .75 secs but I understand that is to enable it to flush itself between readings. It is therefore entirely practical, indeed commonplace, to have a loop cycle of one second. I use a delay 850 in the loop, which I imagine would be typical. 

I believe it is common practice to insert some short delays into the setup section just give it time to settle down. I see that you don't have any but, if that was a problem. I guess you wouldn't be left in any doubt about it. 

If MySQL is an equivalent of Excel there should me a macro around somewhere that takes a live feed off the COMport, which would save you a lot of trouble

el_supremo

Quote
but I understand that is to enable it to flush itself between readings

Eh? It requires a delay because it takes time for it to do the temperature conversion depending upon the number of bits of resolution. The OP has set it to 9 bits so according to the datasheet (page 8) it requires 93.75ms to do the conversion.

Pete

Nick_Pyner


it requires 93.75ms to do the conversion.



Well, I guess that is some of the delay.
And it only leaves about  656.25 ms to be accounted for.

el_supremo

I don't know if the DallasTemperature library does the delay for you but just in case it doesn't, after this statement in loop():
Code: [Select]
  sensors.requestTemperatures(); // Send the command to get temperatures

add
Code: [Select]
  delay(100);
just to be sure.

Pete

Nick_Pyner


I don't know if the DallasTemperature library does the delay


I believe it does, but it's not relevant to the problem.

Hey Guys,  Glad to see all the discussion from last night.  Sorry I was away from the computer, and not able to participate more.

Well the good news is that I only had 2 outliers over the course of the evening, so adding the delay on the python side did seem to help pretty significantly.  Prior to that I was getting bad reads every 5-10 minutes.  But obviously something is still amiss, given that I have a few bad reads.

Pete,  Adding the delay after the read but before the print is an interesting idea.  I may toy with that later tonight.  But from what I read over here http://forum.arduino.cc/index.php?topic=14395.0, there are delays built into the library, so I don't think thats the answer, but again I'm in way over my head at this point.  I know just enough to be dangerous.  I'm really much more of a programmer than a hardware guy  ;)

Nick, Python is the macro language in this instance.  It is reading directly from the serial port just like Processing would do if your using a GUI based setup.  It may seem a little more complicated than a c based macro, but really its pretty similar just a different programming language.  :P

Either Way thanks for all the input guys, I'm probably going to need to scrap this bit of code and change over to a more push pull method for the data.  Then I can set delimiters and read between them as I pull the data in.  I really want to expand this out to four separate temp sensors, and in order for that to work, I really need it to be more reliable overall.  I greatly appreciate the help and I'm sure you'll see more posts as I dive in deeper.



wildbill

One more thing to consider is that the arduino resets when the IDE's serial monitor is opened. I suspect that the same thing may happen when your python script opens the serial port too.

Go Up