In-Situ RDO PRO-X topic

Classes for the InSitue Optical RDO PRO-X process optical dissolved oxygen probe

Introduction

The RDO PRO-X Dissolved Oxygen Probe uses optical technology (EPA-approved RDO technology for Clean Water Act programs) to measure dissolved oxygen and temperature in demanding process environments.

The RDO PRO-X requires a 9.6 - 16 VDC power supply when operating in SDI-12 mode, which is what this library uses. The maximum power consumption is 50 mA at 12 VDC. Measurement current is 6 mA typical at 24 VDC and idle current is 160 µA typical at 24 VDC.

The In-Situ RDO PRO-X sensor is implemented as a sub-classes of the SDI12Sensors class. While the sensor can also communicate over Modbus/RS485 or a 4-20 mA loop, in this case I've chosen to use SDI-12 to minimize the number of pins required for communication and because most Arduino style processors have very few possible COM ports available for RS485.

Setup with Win-Situ

The RDO PRO-X arrives from the factory ready to take measurements. It is NOT necessary to connect it to a computer or use the Win-Situ software to do any additional setup. If you are able to, however, I recommend using Win-Situ to change some of the default settings on the sensor.

To connect the sensor to Win-Situ, you can use any form of RS485 to USB interface. In-Situ sells one that specifially works with their cables, but any inexpensive converter adapter with automatic flow control should work. The sensor must be powered at a minimum of 12V (12-36V) to use the RS485/modbus interface. This is different than the 9.6V - 16V required for the SDI-12 interface.

These are the two settings I recommend changing with Win-Situ:

  1. Disable caching:
    • By default, the RDO PRO-X "caches" readings for 5000ms (5s) and will not take a new measurement until the 5s cache expires. If you want to take measurements at faster than 5s intervals (ie, to average multiple measurements), I strongly recommend setting the cache value to 0ms using the Win-Situ software. The cache value can be changed in the "Diagnostics" menu found on the "Device Setup" tab of Win-Situ.
  2. Enable O2 partial pressure output:
    • By default, the partial pressure of oxygen is not returned over the SDI-12 interface. It can be enabled by way of the "SDI-12 Setup..." menu found on the "Device Setup" tab of Win-Situ.

Calibration

This library DOES NOT support calibrating the DO probe. Per the manufacturer:

This durable probe requires no calibration or conditioning prior to deployment and does not use membranes. The replaceable RDO Smart Sensor Cap stores calibration coefficients for automatic, error-free setup.

The optical Rugged Dissolved Oxygen sensor is very stable. The factory calibration should produce readings within 3% accuracy. If you require readings with greater accuracy we recommend that you perform a 1-point, 100% water-saturated air calibration.

We recommend that you perform the [two-point 100% and] 0% oxygen calibration only if you intend to measure dissolved oxygen at a concentration of less than 4mg/L.

If you do wish to re-calibrate the probe, that must be done using Win-Situ 5 software, the VuSitu mobile app or using the raw Modbus/RS485 commands. Using the Win-Situ software is by far the easiest way. With the Win-Situ software and the calibration "chamber" shipped with the sensor, performing a 1-point 100% water-saturated air calibration is fairly simple and straight forward.

Sensor Cap Maintenance

The sensor cap has an estimated lifetime of 2 years from the time of first reading. To preserve its lifespan, the sensor cap should not be opened or removed from its packaging until the sensor is ready to be deployed.

To clean the sensor cap:

1. The cap and nose cone must remain on the probe.

  1. Rinse the sensor with clean water from a squirt bottle or spray bottle.
  2. Gently wipe with a soft-bristled brush or soft cloth if biofouling is present. Use Alconox to remove grease.
  3. If extensive fouling or mineral build-up is present, soak the cap end in vinegar for 15 minutes, then soak in deionized (DI) water for 15 minutes.

The optical window should only be cleaned when the sensor cap is changed.

InSitu recommends using an antifouling guard or airblast adapter to extend deployments and protect your data.

Deployment Notes and Warnings

Sensor Datasheet

The manual for this sensor is available at: https://in-situ.com/pub/media/support/documents/RDO_Pro-X_Manual.pdf

The spec sheet is here: https://in-situ.com/pub/media/support/documents/RDO-PRO-X_SS.pdf

Build flags

Sensor Constructor

InSituRDO::InSituRDO(char SDI12address, int8_t powerPin, int8_t dataPin, uint8_t measurementsToAverage = 1)

Construct a new In-Situ RDO object.

Parameters
SDI12address The SDI-12 address of the RDO; can be a char, char*, or int.
powerPin

The pin on the mcu controlling power to the RDO PRO-X Use -1 if it is continuously powered.

  • The RDO PRO-X requires a 8-12V power supply, which can be turned off between measurements
dataPin The pin on the mcu connected to the data line of the SDI-12 circuit.
measurementsToAverage The number of measurements to take and average before giving a "final" result from the sensor; optional with a default value of 1.

The SDI-12 address of the sensor, the Arduino pin controlling power on/off, and the Arduino pin sending and receiving data are required for the sensor constructor. Optionally, you can include a number of distinct readings to average. The data pin must be a pin that supports pin-change interrupts.



Example Code

The In-Situ RDO PRO-X is used in the menu a la carte example.

1#include <sensors/InSituRDO.h>
2
3// NOTE: Use -1 for any pins that don't apply or aren't being used.
4const char* RDOSDI12address = "5"; // The SDI-12 Address of the RDO PRO-X
5const int8_t RDOPower = sensorPowerPin; // Power pin
6const int8_t RDOData = 7; // The SDI-12 data pin
7const uint8_t RDONumberReadings = 3;
8
9// Create an In-Situ RDO PRO-X dissolved oxygen sensor object
10InSituRDO insituRDO(*RDOSDI12address, RDOPower, RDOData, RDONumberReadings);
11
12// Create dissolved oxygen percent, dissolved oxygen concentration, temperature,
13// and oxygen partial pressure variable pointers for the RDO PRO-X
14Variable* rdoDOpct =
15 new InSituRDO_DOpct(&insituRDO, "12345678-abcd-1234-ef00-1234567890ab");
16Variable* rdoDOmgL =
17 new InSituRDO_DOmgL(&insituRDO, "12345678-abcd-1234-ef00-1234567890ab");
18Variable* rdoTemp = new InSituRDO_Temp(&insituRDO,
19 "12345678-abcd-1234-ef00-1234567890ab");
20Variable* rdoO2pp =
21 new InSituRDO_Pressure(&insituRDO, "12345678-abcd-1234-ef00-1234567890ab");

Classes

class InSituRDO
The Sensor sub-class for the In-Situ RDO PRO-X dissolved oxygen sensor.
class InSituRDO_DOmgL
The Variable sub-class used for the dissolved oxygen concentration output from a In-Situ RDO PRO-X dissolved oxygen sensor.
class InSituRDO_DOpct
The Variable sub-class used for the dissolved oxygen percent saturation output from a In-Situ RDO PRO-X dissolved oxygen sensor.
class InSituRDO_Temp
The Variable sub-class used for the temperature output from a In-Situ RDO PRO-X dissolved oxygen sensor.
class InSituRDO_Pressure
The Variable sub-class used for the oxygen partial pressure output from a In-Situ RDO PRO-X dissolved oxygen sensor.

Sensor Variable Counts

The number of variables that can be returned by the RDO PRO-X

#define INSITU_RDO_NUM_VARIABLES = 4
Sensor::_numReturnedValues; the RDO PRO-X can report 4 values.
#define INSITU_RDO_INC_CALC_VARIABLES = 0
Sensor::_incCalcValues; we don't calculate any additional values.

Sensor Timing

The sensor timing for an In-Situ RDO PRO-X.

None of these values are specified in the documentation for the sensor; this is all based on SRGD's testing.

#define INSITU_RDO_WARM_UP_TIME_MS = 125
Sensor::_warmUpTime_ms; ~125ms in SRGD tests.
#define INSITU_RDO_STABILIZATION_TIME_MS = 0
Sensor::_stabilizationTime_ms; the sensor is stable as soon as it can take a measurement.
#define INSITU_RDO_MEASUREMENT_TIME_MS = 850
Sensor::_measurementTime_ms; ~775 minimum.
#define INSITU_RDO_EXTRA_WAKE_TIME_MS = 0
Extra wake time required for an SDI-12 sensor between the "break" and the time the command is sent. We give the RDO an extra 10ms.

Dissolved Oxygen Concentration

The DO concentration variable from an In-Situ RDO PRO-X

  • Range is 0 to 50 mg/L concentration
  • Accuracy:
    • ± 0.1 mg/L from 0 to 8 mg/L
    • ± 0.2 mg/L of reading from 8-20 mg/L
    • ± 10% of reading from 20-50 mg/L

InSituRDO_DOmgL::InSituRDO_DOmgL(InSituRDO* parentSense, const char* uuid = "", const char* varCode = "RDOppm") explicit

Construct a new InSituRDO_DOmgL object.

Parameters
parentSense The parent InSituRDO providing the result values.
uuid A universally unique identifier (UUID or GUID) for the variable; optional with the default value of an empty string.
varCode A short code to help identify the variable in files; optional with a default value of "RDOppm".

#define INSITU_RDO_DOMGL_RESOLUTION = 2
Decimals places in string representation; dissolved oxygen concentration should have 2 - resolution is 0.01 mg/L.
#define INSITU_RDO_DOMGL_VAR_NUM = 0
Variable number; dissolved oxygen concentration is stored in sensorValues[0].
#define INSITU_RDO_DOMGL_VAR_NAME = "oxygenDissolved"
Variable name in ODM2 controlled vocabulary; "oxygenDissolved".
#define INSITU_RDO_DOMGL_UNIT_NAME = "milligramPerLiter"
Variable unit name in ODM2 controlled vocabulary; "milligramPerLiter" (mg/L)
#define INSITU_RDO_DOMGL_DEFAULT_CODE = "RDOppm"
Default variable short code; "RDOppm".

Dissolved Oxygen Percent Saturation

The percent saturation variable from an In-Situ RDO PRO-X

  • Range is 0 to 50 mg/L concentration
  • Accuracy:
    • ± 0.1 mg/L from 0 to 8 mg/L
    • ± 0.2 mg/L of reading from 8-20 mg/L
    • ± 10% of reading from 20-50 mg/L

      InSituRDO_DOpct::InSituRDO_DOpct(InSituRDO* parentSense, const char* uuid = "", const char* varCode = "RDOpercent") explicit

      Construct a new InSituRDO_DOpct object.

      Parameters
      parentSense The parent InSituRDO providing the result values.
      uuid A universally unique identifier (UUID or GUID) for the variable; optional with the default value of an empty string.
      varCode A short code to help identify the variable in files; optional with a default value of "RDOpercent".

#define INSITU_RDO_DOPCT_RESOLUTION = 2
Decimals places in string representation; dissolved oxygen percent saturation should have 1.
#define INSITU_RDO_DOPCT_VAR_NUM = 1
Variable number; dissolved oxygen percent is stored in sensorValues[1].
#define INSITU_RDO_DOPCT_VAR_NAME = "oxygenDissolvedPercentOfSaturation"
Variable name in ODM2 controlled vocabulary; "oxygenDissolvedPercentOfSaturation".
#define INSITU_RDO_DOPCT_UNIT_NAME = "percent"
Variable unit name in ODM2 controlled vocabulary; "percent" (% saturation)
#define INSITU_RDO_DOPCT_DEFAULT_CODE = "RDOpercent"
Default variable short code; "RDOpercent".

Temperature

The temperature variable from an In-Situ RDO PRO-X

  • Range is 0° to 50°C (32° to 122°F)
  • Accuracy is ± 0.1°C typical

InSituRDO_Temp::InSituRDO_Temp(InSituRDO* parentSense, const char* uuid = "", const char* varCode = "RDOtempC") explicit

Construct a new InSituRDO_Temp object.

Parameters
parentSense The parent InSituRDO providing the result values.
uuid A universally unique identifier (UUID or GUID) for the variable; optional with the default value of an empty string.
varCode A short code to help identify the variable in files; optional with a default value of "RDOtempC".

#define INSITU_RDO_TEMP_RESOLUTION = 2
Decimals places in string representation; temperature should have 2 - resolution is 0.01°C.
#define INSITU_RDO_TEMP_VAR_NUM = 2
Variable number; temperature is stored in sensorValues[2].
#define INSITU_RDO_TEMP_VAR_NAME = "temperature"
Variable name in ODM2 controlled vocabulary; "temperature".
#define INSITU_RDO_TEMP_UNIT_NAME = "degreeCelsius"
Variable unit name in ODM2 controlled vocabulary; "degreeCelsius" (°C)
#define INSITU_RDO_TEMP_DEFAULT_CODE = "RDOtempC"
Default variable short code; "RDOtempC".

Oxygen Partial Pressure

The oxygen partial pressure variable from an In-Situ RDO PRO-X

InSituRDO_Pressure::InSituRDO_Pressure(InSituRDO* parentSense, const char* uuid = "", const char* varCode = "RDOppO2") explicit

Construct a new InSituRDO_Pressure object.

Parameters
parentSense The parent InSituRDO providing the result values.
uuid A universally unique identifier (UUID or GUID) for the variable; optional with the default value of an empty string.
varCode A short code to help identify the variable in files; optional with a default value of "RDOppO2".

#define INSITU_RDO_PRESSURE_RESOLUTION = 2
Decimals places in string representation; pressure should have 3.
#define INSITU_RDO_PRESSURE_VAR_NUM = 3
Variable number; temperature is stored in sensorValues[3].
#define INSITU_RDO_PRESSURE_VAR_NAME = "vaporPressure"
Variable name in ODM2 controlled vocabulary; "vaporPressure".
#define INSITU_RDO_PRESSURE_UNIT_NAME = "torr"
Variable unit name in ODM2 controlled vocabulary; "torr".
#define INSITU_RDO_PRESSURE_DEFAULT_CODE = "RDOppO2"
Default variable short code; "RDOppO2".

Define documentation

#define INSITU_RDO_NUM_VARIABLES = 4

Sensor::_numReturnedValues; the RDO PRO-X can report 4 values.

It reports 3 values (DO concentration, DO % saturation, and temperature) by default. Partial pressure of oxygen can be added to the output using Win-Situ software.


#define INSITU_RDO_INC_CALC_VARIABLES = 0

Sensor::_incCalcValues; we don't calculate any additional values.


#define INSITU_RDO_WARM_UP_TIME_MS = 125

Sensor::_warmUpTime_ms; ~125ms in SRGD tests.


#define INSITU_RDO_STABILIZATION_TIME_MS = 0

Sensor::_stabilizationTime_ms; the sensor is stable as soon as it can take a measurement.


#define INSITU_RDO_EXTRA_WAKE_TIME_MS = 0

Extra wake time required for an SDI-12 sensor between the "break" and the time the command is sent. We give the RDO an extra 10ms.


#define INSITU_RDO_DOMGL_RESOLUTION = 2

Decimals places in string representation; dissolved oxygen concentration should have 2 - resolution is 0.01 mg/L.

Contrary to the spec sheet, the actual resolution returned by the sensor in SDI-12 mode is 0.000001 mg/L. Since the accuracy is only 0.1 mg/L at best, we will keep only the two digits suggested by the spec sheet.


#define INSITU_RDO_DOMGL_VAR_NUM = 0

Variable number; dissolved oxygen concentration is stored in sensorValues[0].


#define INSITU_RDO_DOMGL_VAR_NAME = "oxygenDissolved"

Variable name in ODM2 controlled vocabulary; "oxygenDissolved".


#define INSITU_RDO_DOMGL_UNIT_NAME = "milligramPerLiter"

Variable unit name in ODM2 controlled vocabulary; "milligramPerLiter" (mg/L)


#define INSITU_RDO_DOMGL_DEFAULT_CODE = "RDOppm"

Default variable short code; "RDOppm".


#define INSITU_RDO_DOPCT_RESOLUTION = 2

Decimals places in string representation; dissolved oxygen percent saturation should have 1.

The actual resolution returned by the sensor in SDI-12 mode is 0.00001 %. Since the accuracy is much less than that, we'll ignore the not-significant figures.


#define INSITU_RDO_DOPCT_VAR_NUM = 1

Variable number; dissolved oxygen percent is stored in sensorValues[1].


#define INSITU_RDO_DOPCT_VAR_NAME = "oxygenDissolvedPercentOfSaturation"

Variable name in ODM2 controlled vocabulary; "oxygenDissolvedPercentOfSaturation".


#define INSITU_RDO_DOPCT_UNIT_NAME = "percent"

Variable unit name in ODM2 controlled vocabulary; "percent" (% saturation)


#define INSITU_RDO_DOPCT_DEFAULT_CODE = "RDOpercent"

Default variable short code; "RDOpercent".


#define INSITU_RDO_TEMP_RESOLUTION = 2

Decimals places in string representation; temperature should have 2 - resolution is 0.01°C.

The spec sheet lists 2 decimal resolution, but the returned value has 5. Since the accuracy is less than either, we keep the two mentioned on the spec sheet.


#define INSITU_RDO_TEMP_VAR_NUM = 2

Variable number; temperature is stored in sensorValues[2].


#define INSITU_RDO_TEMP_VAR_NAME = "temperature"

Variable name in ODM2 controlled vocabulary; "temperature".


#define INSITU_RDO_TEMP_UNIT_NAME = "degreeCelsius"

Variable unit name in ODM2 controlled vocabulary; "degreeCelsius" (°C)


#define INSITU_RDO_TEMP_DEFAULT_CODE = "RDOtempC"

Default variable short code; "RDOtempC".


#define INSITU_RDO_PRESSURE_RESOLUTION = 2

Decimals places in string representation; pressure should have 3.


#define INSITU_RDO_PRESSURE_VAR_NUM = 3

Variable number; temperature is stored in sensorValues[3].


#define INSITU_RDO_PRESSURE_VAR_NAME = "vaporPressure"

Variable name in ODM2 controlled vocabulary; "vaporPressure".


#define INSITU_RDO_PRESSURE_DEFAULT_CODE = "RDOppO2"

Default variable short code; "RDOppO2".