ArduSlave, environmental sensors for OpenROV


#1

Hello,

From some months I have been trying to develop a module of sensors to connect to OpenRov.

The idea is to have some sensors (www.atlas-scientific.com) connected to an arduino which is connected to the I2C bus of the OpenROV.

In order to do so, I've develop the following code:

-----------------------------------------------------------------------------------------------------------------------------

Code running in the auxiliary arduino:

------------------------------------------------------------------------------------------------------------------------------

#include <AltSoftSerial.h> //Include the software serial library
#include <Wire.h>
#include <SoftwareSerial.h>
#define rx 2
#define tx 3

SoftwareSerial myserial(rx, tx);

const byte i2c_address=0x77;
AltSoftSerial altSerial; //Name the software serial library altSerial (this cannot be omitted)

int s0 = 7; //Arduino pin 7 to control pin S0
int s1 = 6; //Arduino pin 6 to control pin S1

char sensordata[30]; //A 30 byte character array to hold incoming data from the sensors
byte sensor_bytes_received=0; //We need to know how many characters bytes have been received
byte received_from_sensor=0; //We need to know how many characters have been received from the temp sensor

char tmp_data[20]; //We make a 20 byte character array to hold incoming data from the ENV-TMP-D

byte string_received=0; //used to identify when we have received a string from the ENV-TMP-D.

struct data
{
struct {
float ec;
float tds;
float sal;
float sg;
}
conductivity;
float pH;
float DO;
float ORP;
float temperature;
};

const int data_size=sizeof(data);

const int waiting_time = 1000;

data data_from_sensors = {
{
0, 0, 0, 0 }
,
0,
0,
0,
0
};

void setup() {
pinMode(s1, OUTPUT); //Set the digital pin as output.
pinMode(s0, OUTPUT); //Set the digital pin as output.
pinMode(2, OUTPUT); //Set pin 2 as an output
Serial.begin(38400); //Set the hardware serial port to 38400
altSerial.begin(38400); //Set the soft serial port to 38400
myserial.begin(38400); //enable the hardware serial port
Wire.begin(i2c_address);
Wire.onRequest(requestEvent);
myserial.print("sc\r"); // send the "sc" command to set the tmp scale to Celsius
}

void loop(){

open_channel(0);
Serial.print("Conductivity==>");
altSerial.print("R\r");
leeBuffer();
const char *delimitador=",";
data_from_sensors.conductivity.ec=atof(strtok(sensordata,delimitador));
data_from_sensors.conductivity.tds=atof(strtok(NULL,delimitador));
data_from_sensors.conductivity.sal=atof(strtok(NULL,delimitador));
data_from_sensors.conductivity.sg=atof(strtok(NULL,delimitador));

open_channel(1);
// Serial.print("pH==>");
altSerial.print("R\r");
leeBuffer();
data_from_sensors.pH=atof(sensordata);

open_channel(2);
// Serial.print("DO==>");
altSerial.print("R\r");
leeBuffer();
data_from_sensors.DO=atof(sensordata);

open_channel(3);
// Serial.print("ORP==>");
altSerial.print("R\r");
leeBuffer();
data_from_sensors.ORP=atof(sensordata);

// Serial.print("Temperature==>");
myserial.print("R\r");
leeBuffer2();
if(string_received==1){
data_from_sensors.temperature = atof(tmp_data);
string_received=0;}

Serial.println();
Serial.println(" DATA IN STRUCTURE ");
Serial.println("-------------------");
Serial.print("Conductividad==> EC: ");
Serial.print(data_from_sensors.conductivity.ec);
Serial.print(", TDS: ");
Serial.print(data_from_sensors.conductivity.tds);
Serial.print(", SAL: ");
Serial.print(data_from_sensors.conductivity.sal);
Serial.print(", SG: ");
Serial.println(data_from_sensors.conductivity.sg);

Serial.print("pH==> ");
Serial.println(data_from_sensors.pH);
Serial.print("DO==> ");
Serial.println(data_from_sensors.DO);
Serial.print("ORP==> ");
Serial.println(data_from_sensors.ORP);

// resto de datos de la estructura
Serial.print("Temperatura==> ");
Serial.println(data_from_sensors.temperature);

Serial.println("-------------------");
Serial.println(" DATA IN STRUCTURE END ");
Serial.println();
delay(5000);
}

void leeBuffer(){
delay(waiting_time);
if(altSerial.available() > 0){ //If data has been transmitted from an Atlas Scientific device
sensor_bytes_received=altSerial.readBytesUntil(13,sensordata,30); //we read the data sent from the Atlas Scientific device until we see a <CR>. We also count how many character have been received
sensordata[sensor_bytes_received]=0; //we add a 0 to the spot in the array just after the last character we received. This will stop us from transmitting incorrect data that may have been left in the buffer
Serial.println(sensordata);
}
}

void leeBuffer2(){
delay(waiting_time);
if(myserial.available() > 0){ //If data has been transmitted from an Atlas Scientific device
received_from_sensor=myserial.readBytesUntil(13,tmp_data,20);
tmp_data[received_from_sensor]=0; //we add a 0 to the spot in the array just after the last character we received. This will stop us from transmitting incorrect data that may have been left in the buffer
string_received=1;
Serial.println(tmp_data);
}
}

void open_channel(int channel){ //This function controls what UART port is opened.

if (channel & 1){
digitalWrite(s0, HIGH);
}
else {
digitalWrite(s0,LOW);
}
if (channel & 2){
digitalWrite(s1, HIGH);
}
else {
digitalWrite(s1,LOW);
}
delay(100);
int bytesResiduo=altSerial.available();
if(bytesResiduo > 0){
sensor_bytes_received=altSerial.readBytes(sensordata, bytesResiduo);
sensordata[bytesResiduo]=0;
Serial.print("ATENCION: DATOS NO LEIDOS: ");
Serial.println(sensordata);
}
}


void requestEvent(){
byte *pDatos= (byte *) &data_from_sensors;
Wire.write(pDatos, data_size);
}

----------------------------------------------------------------------------------------------------------------------------------

Arduslave.h:

-----------------------------------------------------------------------------------------------------------------------------------

#ifndef __ArduSlave_H_
#define __ArduSlave_H_
#include <Arduino.h>
#include "Device.h"

struct data
{
struct {
float ec;
float tds;
float sal;
float sg;
}
conductivity;
float pH;
float DO;
float ORP;
float temperature;
};
const int data_size=sizeof(data);

const unsigned arduslave_timeout=100;

class ArduSlave : public Device {
public:
ArduSlave():Device(){};
void device_setup();
void device_loop(Command cmd);
};
#endif

-------------------------------------------------------------------------------------------------------------------------------------

arduslave.cpp:

--------------------------------------------------------------------------------------------------------------------------------------

#include "AConfig.h"
#if(HAS_ARDUSLAVE)

#include "ArduSlave.h"
// #include "Settings.h"
//#include "Timer.h"
#include <Wire.h>

/*
Sketch to read a MS5803-14BA pressure sensor, written from scratch.
Will output data to the serial console.

Written by Walt Holm
Initial revision 10 Oct 2013
Rev 1 12 Oct 2013 -- Implements 2nd order temperature compensation
*/



const int DevAddress = ARDUSLAVE_I2CADDRESS; // 7-bit I2C address of the MS5803

void ArduSlave::device_setup(){
//Settings::capability_bitarray |= (1 DEAPTH_CAPABLE);

Serial.println("ArduSlave setup.");
Wire.begin();
delay(10);
}

void ArduSlave::device_loop(Command command){
Wire.requestFrom(DevAddress, 32);
data data_from_arduslave;

unsigned int millis_start = millis();
byte *pBdata = (byte *) &data_from_arduslave;
for (int i=0; i<data_size; i++){
if (Wire.available()){
pBdata[i]=Wire.read();
}
else {
if (((unsigned int)millis() - millis_start) > arduslave_timeout) {
Serial.println("log:Failed to read ArduSlave from I2C");
return;
}
}
}
Serial.println();
Serial.println(" DATA IN ARDUSLAVE ");
Serial.println();
Serial.print("Conductividad==> EC: ");
Serial.print(data_from_arduslave.conductivity.ec);
Serial.print(", TDS: ");
Serial.print(data_from_arduslave.conductivity.tds);
Serial.print(", SAL: ");
Serial.print(data_from_arduslave.conductivity.sal);
Serial.print(", SG: ");
Serial.println(data_from_arduslave.conductivity.sg);

Serial.print("pH==> ");
Serial.println(data_from_arduslave.pH);
Serial.print("DO==> ");
Serial.println(data_from_arduslave.DO);
Serial.print("ORP==> ");
Serial.println(data_from_arduslave.ORP);

// resto de datos de la estructura
Serial.print("Temperatura==> ");
Serial.println(data_from_arduslave.temperature);

Serial.println();
Serial.println(" DATA IN ARDUSLAVE END ");
Serial.println();
}
#endif

---------------------------------------------------------------------------------------------------------------------------------

And here is what I've change in openrov.ino and Aconfig.h

Openrov.ino: just before the line Command cmd:


#if(HAS_ARDUSLAVE)
#include "ArduSlave.h"

ArduSlave kit_sensores;
#endif

AConfig.h: just after #define MPU9150_EEPROM_START 2


#define HAS_ARDUSLAVE (1)
#define ARDUSLAVE_I2CADDRESS 0x77

-----------------------------------------------------------------------------------------------------------------------------------

I would be very gratefull if someone could help me a little bit with some problems:

When I first compile this code into the OpenROV I lost the communication with the openROV and although I receive some information from the ROV and I can continue seeing the cockpit, I cannot move the motors neither see the left battery or the camera image.

At a first moment, I bought a microSD card and I write in it the openROV image and it started to work again. So I made another try with the code and it had happened the same thing that the other time.

In this momment is all the cockpit black as you can see in the picture.

It is advancing in step of 1 to 1 from log 1 to log 183 now, and it continues. I don't know very well what are supposed to be the logs.

I need help with some matters:

1- How could I fix this, and introduce my code? Do you think that the code has any problem? It can be a problem to initialice wire.h both in the IMU depth and in my device?

2. When I manage to introduce my code, I'm doing serial print with the data of the structure... how can I see that data in the computer?

Thank you very much!!!!

Please help me, I am quite desperated!

Regads!

83-cockpit.jpg (197 KB)

#2

If anyone wants to help, I can find the way to send the codes ;)


#3

HeyJavier,

Sorry, been a bit busy this month! I will clear some time this weekend to see how I can help. (Don't let that stop anyone else! )

Brian


#4

Very thankfull Brian,

I've send you an email with some pictures of the log file if you want to see them.

Javi


#5

Did you had time to take a lool at the code Brian? Do you think is all right?


#6

FYI to those trying to use the atlas scientific sensors for pH, those will only be accurate in fresh water, the salt messes with the glass membrane sensors. You have to have a reference electrode (or two) to take accurate ocean pH.


#7

The objective is to use it in the mouth of a river, to help farmers who have their cultives near a river mouth where the salinity and those parameters can vary.


#8

That's a great use, I use a lot of water quality probes to do just that (YSI instruments) and also find the NH4 and NO3 levels from outflows into rivers as a result of fertilizer use.

Salt just makes the pH probes inaccurate is all that I am saying. We're trying to figure out how to do ocean pH because we primarily focus on intertidal ecology and marine protected area research, the cheapest commercially available solution is a SeaFET which is in the range of 10,000 dollars! There's actually an x-prize to try to develop a low cost and effective ocean pH sensor: http://oceanhealth.xprize.org/about/overview


#9

Hey Javier, I had been discussing with Dom. Did you respond back with the version of the software that you are using?


#10

Yes, I send you the message I send Dom about my issues.

The image I'm using is: OpenROV-2.5-29


#11

Got the email. Lets break things down in to the separate problems. OpenROV-2.5-29 is an older pre-release. Try upgrading to the more recent RC5 image. One of the key changes was logic that prevented the I2C bus from freezing up if the MPU9150 mis behaved.

On your physical wiring diagram you show a 3V power lead from the uno going to the level shifter. There is not enough detail to see where that is going through the level shifter your using but I am surprised to see anything labeled 3V on the uno.

You had mentioned seeing the message "log: pilot setup complete" even with the MPU9150 turned off. That is okay. It comes from the pilot module that always loads: https://github.com/OpenROV/openrov-software-arduino/blob/d5d45c9f3b7c2c9c8927feb15ab4f1366cb5a939/OpenROV/Pilot.cpp#L39

You had a question on why you don't see the depth sensor reset message that is in the code, but you do see the depth sensor initialized I2C. Honestly, it is a fluke that the first debug message shows up in cockpit. There is a serial parser in the node process listening to messages from the arduino and if they have the name:value format it will pass them along to the cockpit UI. I'm not sure if it is active in the build you are using, but there is a key command added that pipes the entire raw serial feed down to the cockpit for you to view. The 'u' key.

And a couple questions:

Have you been able to get the arduino-slave code you wrote working before trying to integrate it on the ROV directly?

With the MPU9150 disabled and your arduino-slave disabled and disconnected, does the cockpit work correctly?

If so, when you add just the hardware leads to the arduino-slave but leave it disabled in the firmware of the ROV, does the cockpit still work correctly?

-Brian


#12

Ok. I answer you back in half an hour or so when I finish doing that things.

The level shifter I have used is one very similar to this one:

https://learn.sparkfun.com/tutorials/bi-directional-logic-level-converter-hookup-guide


#13

Hello Brian,

I’ve already actualized the software with this image: https://github.com/OpenROV/openrov-software/releases I think is RC5 as you’ve told me.

This i how it looks like now:


The 3V wire which goes to the arduino uno is because I base don this scheme

https://dlnmh9ip6v2uc.cloudfront.net/assets/6/3/6/e/d/5266e578757b7fdf4c8b4570.png

But I am not very good at electronics and I don’t know if it’s right, please let me know if you think it should be connected in another way.

Talking about electronics, I am not sure if I should haved putt he pull up resistences or the are in the controller board.

How should be my code writed to see the data ArduSlave is sending?

To answer your questions:

I haven’t tested arduslave.cpp and arduslave.h before trying in the ROV becaused I didn’t know how, but the code running in the arduino uno does what is suppossed to do.

As you’ve seen the ROV is working properly and in this image of the code de MS5803_14BA and the MPU9150 were activated by default


I am writing my code to see if it Works, I’ll tell you when I am finished.

Regards!

Javi


#14

Hi Javier:

Can you summarize for us how you are trying to hook things up?

From your Fritzing diagram, you seem to be hooking up a serial device through a level shifter to a Arduino Leonardo. You don't show any hookup to the ROV, so I'm not really sure what's going on with your I2C bus.


#15

To channel your arduslave data to the rov, you simply need to update your code in the controller board to Serial.print("Tag:Value;"); That will then show up on the telemetry screen.


#16

Hello Walt,

Of course. I have only based on that scheme I have not done it exactly equa. I mean I have an arduino uno instead of a Leonardo and I have hooked the SCL and SDA arduino Uno pins to the "High Level" part and the SCL and SDA coming from the OpenROV to the "Low Level" part.

The only strange thing is the 3V wire which is conected to the 3V coming from the OpenROV and to the 3V pin of the UNO.

I do it in that way because I saw in that scheme it was done like that.

Regards!

Javi


#17

Thank you a lot for the info. I'll take a look to the link. I had no idea there were this kind of issues. I'll tell you if I had any problems measuring pH.

Regards!

Javi


#18

SPI ADXL345 to Arduino via BD-LLC

Is more similar to this one.


#19

You mean like in MPU9150?

if (changed) {
Serial.print(F("dia:accel.MinX=")); Serial.print(calData.accelMinX); Serial.println(";");
/// aquí vienen otro porrón de líneas similares para un total de doce datos.
}

dia:accel.MinX=1234;

By standarising the data in that form I should see it?


#20

I suddenly had this screen,

I have not activated my code yet so nothing had should change.