mirror of
https://github.com/eclipse/upm.git
synced 2025-03-15 04:57:30 +03:00
otp538u: some fixes to get working on the Arduino 101 with Firmata
There are some issues using this device on the 101 with Firmata: 1. You cannot use any other ADC resolution than 1024. By default the driver would try to set 12b resolution for improved accuracy. Doing this on the 101 yielded nonsensical readings causing the driver to fail. Using 10b resolution will yield less accuracy, but at least the driver will function. 2. After the first ADC read, and for some time period after, the MRAA aio_read() calls will always return 0. This would cause an exception to be thrown by the driver since this is an invalid reading. Now, we do an analog read on each channel and sleep for .5 seconds in the ctor to get around this problem. It is a hack and should be properly fixed somewhere else (firmata? MRAA?). Some code was reworked/renamed to make it more clear what is actually going on. In addition a setDebug() method was added to enable some debugging output. Signed-off-by: Jon Trulson <jtrulson@ics.com>
This commit is contained in:
parent
19d1af6a48
commit
dc93fb11ff
@ -25,6 +25,7 @@
|
||||
#include <unistd.h>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
#include <signal.h>
|
||||
#include "otp538u.hpp"
|
||||
|
||||
@ -52,14 +53,24 @@ int main()
|
||||
// Object temperature.
|
||||
upm::OTP538U *temps = new upm::OTP538U(0, 1, OTP538U_AREF);
|
||||
|
||||
// enable debugging if you would like
|
||||
// temps->setDebug(true);
|
||||
|
||||
// Output ambient and object temperatures
|
||||
while (shouldRun)
|
||||
{
|
||||
cout << "Ambient temp: " << std::fixed << setprecision(2)
|
||||
<< temps->ambientTemperature()
|
||||
<< " C, Object temp: " << temps->objectTemperature()
|
||||
<< " C" << endl;
|
||||
|
||||
try {
|
||||
cout << "Ambient temp: " << std::fixed << setprecision(2)
|
||||
<< temps->ambientTemperature()
|
||||
<< " C, Object temp: " << temps->objectTemperature()
|
||||
<< " C" << endl;
|
||||
}
|
||||
catch (std::out_of_range& e) {
|
||||
cerr << "Temperature(s) are out of range: " << e.what()
|
||||
<< endl;
|
||||
}
|
||||
|
||||
cout << endl;
|
||||
sleep(1);
|
||||
}
|
||||
//! [Interesting]
|
||||
|
@ -36,9 +36,24 @@ using namespace std;
|
||||
|
||||
OTP538U::OTP538U(int pinA, int pinO, float aref)
|
||||
{
|
||||
const int adcHighRes = 4095;
|
||||
const int adcLowRes = 1023;
|
||||
|
||||
// for subplatforms like the Arduino 101, we need to limit ADC
|
||||
// resolution to 10b currently. For this sensor unfortunately, this
|
||||
// means readings will be less accurate. This sensor really does
|
||||
// need to measure with about 1mV accuracy.
|
||||
bool isSubplatform = false;
|
||||
|
||||
m_debug = false;
|
||||
|
||||
if (pinA >= 512 || pinO >= 512)
|
||||
isSubplatform = true;
|
||||
|
||||
// this is the internal voltage reference on the Grove IR temp
|
||||
// sensor module
|
||||
m_vref = 2.5;
|
||||
// sensor module for the thermistor.
|
||||
|
||||
m_internalVRef = 2.5;
|
||||
|
||||
// analog reference in use
|
||||
m_aref = aref;
|
||||
@ -51,29 +66,72 @@ OTP538U::OTP538U(int pinA, int pinO, float aref)
|
||||
// can adjust as neccessary depending on your calibration.
|
||||
m_offsetVoltage = 0.014;
|
||||
|
||||
// We need around 1mV resolution, so use 12 bit resolution (4096)
|
||||
// with a default aref of 5.0.
|
||||
m_adcResolution = 4096;
|
||||
// We need around 1mV resolution (preferred), so use 12 bit
|
||||
// resolution (4096) if we can.
|
||||
//
|
||||
// This logic is over complicated due to the fact that it is
|
||||
// currently difficult to determine exactly what the capabilities of
|
||||
// the platform (sub or otherwise) actually are. So for
|
||||
// subplatforms, we always limit to 1024. Otherwise, we try 12b if
|
||||
// the mraa_adc_raw_bits() says we can, though this isn't
|
||||
// particularly accurate either, as it reports that the G2 can do
|
||||
// 12b, when in reality it can not. We are just lucky that it works
|
||||
// anyway (ie: will give 12b resolution, though underneath it's just
|
||||
// scaling the real 10b value.). Sigh. But trying 12b resolution
|
||||
// on the 101 via firmata will definitely break things, so don't
|
||||
// even try until whatever the problem it has with 12b is fixed.
|
||||
if (isSubplatform)
|
||||
{
|
||||
m_adcResolution = adcLowRes; // 10b
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mraa_adc_raw_bits() == 12)
|
||||
m_adcResolution = adcHighRes; // 12b
|
||||
else
|
||||
m_adcResolution = adcLowRes; // 10b
|
||||
}
|
||||
|
||||
// notify the user
|
||||
if (m_adcResolution == adcLowRes)
|
||||
cerr << "Using 10 bit ADC resolution. Values will be less accurate."
|
||||
<< endl;
|
||||
|
||||
|
||||
if ( !(m_aioA = mraa_aio_init(pinA)) )
|
||||
{
|
||||
throw std::invalid_argument(std::string(__FUNCTION__) +
|
||||
": mraa_gpio_init(pinA) failed, invalid pin?");
|
||||
": mraa_gpio_init(pinA) failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// enable 12 bit resolution
|
||||
mraa_aio_set_bit(m_aioA, 12);
|
||||
// enable 12 bit resolution, if we can
|
||||
if (m_adcResolution == adcHighRes)
|
||||
mraa_aio_set_bit(m_aioA, 12);
|
||||
|
||||
if ( !(m_aioO = mraa_aio_init(pinO)) )
|
||||
{
|
||||
throw std::invalid_argument(std::string(__FUNCTION__) +
|
||||
": mraa_gpio_init(pinO) failed, invalid pin?");
|
||||
": mraa_gpio_init(pinO) failed");
|
||||
return;
|
||||
}
|
||||
|
||||
// enable 12 bit resolution
|
||||
mraa_aio_set_bit(m_aioO, 12);
|
||||
|
||||
// enable 12 bit resolution, if we can
|
||||
if (m_adcResolution == adcHighRes)
|
||||
mraa_aio_set_bit(m_aioO, 12);
|
||||
|
||||
if (isSubplatform)
|
||||
{
|
||||
// The first analog read always seems to return 0 on the 101
|
||||
// with firmata, so just do a couple of reads here and discard
|
||||
// them. Then sleep for half a second. THIS IS A HACK. The
|
||||
// real problem should be fixed elsewhere (Firmata?).
|
||||
mraa_aio_read(m_aioA);
|
||||
mraa_aio_read(m_aioO);
|
||||
|
||||
usleep(500000);
|
||||
}
|
||||
}
|
||||
|
||||
OTP538U::~OTP538U()
|
||||
@ -87,7 +145,7 @@ float OTP538U::ambientTemperature()
|
||||
const int samples = 5;
|
||||
int val = 0;
|
||||
float temp = 0;
|
||||
float res;
|
||||
float res = 0;
|
||||
|
||||
for (int i=0; i<samples; i++)
|
||||
{
|
||||
@ -96,15 +154,25 @@ float OTP538U::ambientTemperature()
|
||||
throw std::runtime_error(std::string(__FUNCTION__) +
|
||||
": failed to do aio read");
|
||||
}
|
||||
temp += val;
|
||||
temp += (float)val;
|
||||
usleep(10000);
|
||||
}
|
||||
|
||||
temp = temp / samples;
|
||||
temp = temp * m_aref / m_adcResolution;
|
||||
|
||||
float volts = temp * m_aref / m_adcResolution;
|
||||
if (m_debug)
|
||||
{
|
||||
cerr << "\tAMB sample " << temp << " m_aref " << m_aref
|
||||
<< " VOLTS " << volts << endl;
|
||||
}
|
||||
|
||||
// compute the resistance of the thermistor
|
||||
res = m_vResistance * temp / (m_vref - temp);
|
||||
res = m_vResistance * volts / (m_internalVRef - volts);
|
||||
|
||||
if (m_debug)
|
||||
{
|
||||
cerr << "\tAMB computed resistance: " << res << endl;
|
||||
}
|
||||
|
||||
// look it up in the thermistor (RT) resistence/temperature table
|
||||
int rawslot;
|
||||
@ -119,7 +187,7 @@ float OTP538U::ambientTemperature()
|
||||
if (j >= otp538u_rt_table_max)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__) +
|
||||
": ambient temperature out of range.");
|
||||
": ambient temperature out of range (high).");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -133,7 +201,7 @@ float OTP538U::ambientTemperature()
|
||||
if (slot < 0)
|
||||
{
|
||||
throw std::out_of_range(std::string(__FUNCTION__) +
|
||||
": ambient temperature out of range.");
|
||||
": ambient temperature out of range (low).");
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -168,9 +236,18 @@ float OTP538U::objectTemperature()
|
||||
|
||||
temp = temp / samples;
|
||||
|
||||
float temp1 = temp * m_aref / m_adcResolution;
|
||||
float sensorVolts = temp1 - (reference_vol + m_offsetVoltage);
|
||||
// cout << "Sensor Voltage: " << sensorVolts << endl;
|
||||
if (m_debug)
|
||||
cerr << "\tOBJ sample " << temp << " ";
|
||||
|
||||
float volts = temp * m_aref / m_adcResolution;
|
||||
|
||||
if (m_debug)
|
||||
cerr << "VOLTS: " << volts << " ";
|
||||
|
||||
float sensorVolts = volts - (reference_vol + m_offsetVoltage);
|
||||
|
||||
if (m_debug)
|
||||
cerr << "Sensor Voltage (computed): " << sensorVolts << endl;
|
||||
|
||||
// search the VT (voltage/temperature) table to find the object
|
||||
// temperature.
|
||||
@ -198,8 +275,11 @@ float OTP538U::objectTemperature()
|
||||
( otp538u_vt_table[slot + 1][voltOffset] -
|
||||
otp538u_vt_table[slot][voltOffset] );
|
||||
|
||||
// cout << "TABLE VALUE [" << slot << "][" <<
|
||||
// voltOffset << "] = " << otp538u_vt_table[slot][voltOffset] << endl;
|
||||
if (m_debug)
|
||||
{
|
||||
cerr << "\tVoltage (" << voltage << "): TABLE VALUE [" << slot << "][" <<
|
||||
voltOffset << "] = " << otp538u_vt_table[slot][voltOffset] << endl;
|
||||
}
|
||||
|
||||
return (ambTemp + objTemp);
|
||||
}
|
||||
|
@ -65,6 +65,10 @@ namespace upm {
|
||||
* These tables assume the object to be measured is 9 cm (3.54
|
||||
* inches) from the sensor.
|
||||
*
|
||||
* This sensor will not work at 3.3v on the Edsion or the Galileo 2.
|
||||
* It works fine on both systems at 5v. It will work at 3.3v on the
|
||||
* Arduino 101 (tested via firmata subplatform on edison).
|
||||
*
|
||||
* @image html otp538u.jpg
|
||||
* @snippet otp538u.cxx Interesting
|
||||
*/
|
||||
@ -135,13 +139,22 @@ namespace upm {
|
||||
* looking at the EAGLE files containing their schematics for this
|
||||
* device.
|
||||
*
|
||||
* @param vref Reference voltage of the internal sensor; default is 2.5 V
|
||||
* @param vref Reference voltage of the internal sensor; default
|
||||
* is 2.5
|
||||
*/
|
||||
void setVRef(float vref) { m_vref = vref; };
|
||||
void setVRef(float vref) { m_internalVRef = vref; };
|
||||
|
||||
/**
|
||||
* Enable debugging output.
|
||||
*
|
||||
* @param true to enable some debug output, false otherwise
|
||||
*/
|
||||
void setDebug(bool enable) { m_debug = enable; };
|
||||
|
||||
|
||||
private:
|
||||
float m_vref;
|
||||
bool m_debug;
|
||||
float m_internalVRef;
|
||||
float m_aref;
|
||||
int m_vResistance;
|
||||
float m_offsetVoltage;
|
||||
|
Loading…
x
Reference in New Issue
Block a user