I am collecting data with a couple of different sensors connected to an Arduino Uno. I have the Arduino connected to a Raspberry Pi 4 via USB cable.
Goal: Send the sensor values to the raspberry pi whenever they are requested.
Problem: Data is successfully being received (by serial communication) by the RPi from Arduino but over time the values seem to hang up and not update. When I stop and restart the program suddenly the values change to more accurate values. To be clear: I keep receiving values but the values appear to be old or repeating values.
Example; I am measuring soil moisture with an analog sensor. I start the program and the values being received seem good, reasonable, and stable. I let the program run for a while (5-10 minutes) and the values seem too stable. So I remove the sensor from the wet soil and dry it off, this should cause the values to drastically change- but they do not, the values continue to read out as if the sensor is still in the soil. I stop the program and restart it. The new values are much more reasonable for a dry moisture sensor.
Possible Cause(??): Devices out of sync ( the only possible cause I have found online).
Possible solutions;
-
(Tried, Did not work) Add a delay in the arduino code. I have a delay(2000) at the end of the loop.
-
(Tried, Did not work) Try different data send triggers; I have tried both a serial Trigger (send serial communication from Rpi to Arduino asking for data). I Have also tried a more physical trigger of setting a Pin to HIGH when data is wanted.
-
Bypass the USB and use the TX/RX pins on the arduino/ RPI to send the data. This is my next step but it is a hardware solution (need level converter and need to wait for that to ship.)
Does this community have any experience with this? Any links to solutions or explanations you have seen?
RPI CODE:
#!/usr/bin/env python3
from __future__ import print_function
import datetime
from random import randint
from time import sleep
import Adafruit_DHT
import pickle
import os.path
import board
import busio
import socket
import adafruit_sgp30
import picamera
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
import csv
import os.path
import os
import time
import serial
import time
DHT_SENSOR = Adafruit_DHT.DHT22
DHT_PIN = 4
GPIO.setup(15, GPIO.OUT)
GPIO.output(15, GPIO.HIGH)
if __name__ == '__main__':
ser = serial.Serial('/dev/ttyACM0', 9600, timeout=1)
ser.flush()
while True:
try:
Time = '{:%D %H:%M}'.format(datetime.datetime.today())
ser.flush()
#Serial Components
# ser.flush()
GPIO.output(15, GPIO.HIGH)
# ser.write(b"RequestFullData") #Sending request to Arduino- Doesn't matter what it says
line = ser.readline().decode('utf-8').rstrip() #Recieve the data in line
f = line.replace("'","") #Manipulate data
f = f.split(',')
# print(f)
f2 = [float(i) for i in f] # Turn Data into a vector
#Local Digital Components
humidity, temperature = Adafruit_DHT.read_retry(DHT_SENSOR, DHT_PIN)
#Data Organized
AirTemp= round(temperature,1)
AirHumid= round(humidity,1)
valco2 = f2[0]
SoiltempC = f2[1]
SoiltempF = f2[2]
SoilMoisture1= f2[3]
SoilMoisture2= f2[4]
SoilMoisture3= f2[5]
print(AirTemp,AirHumid,valco2,SoiltempC,SoilMoisture1,SoilMoisture2,SoilMoisture3)
#Save Enviroment Data ##
with open("/home/pi/MRUData.csv", "a") as log:
log.write("{0},{1},{2},{3},{4},{5},{6},{7}\n".format(str(Time),str(AirTemp),str(AirHumid),str(valco2),str(SoiltempC),str(SoilMoisture1),str(SoilMoisture2),str(SoilMoisture3)))
# print(SoilMoisture1,SoiltempF,SoiltempC)
#Loop time
GPIO.output(15, GPIO.LOW)
time.sleep(10)
except (ValueError, IndexError):
print("Unexpected error:")
time.sleep(5)
Arduino Code:
*/
#include <OneWire.h>
#include <DallasTemperature.h>
#include <SoftwareSerial.h>
#define ONE_WIRE_BUS 5
#define SensorPin1 A0
#define SensorPin2 A1
#define SensorPin3 A2
//#define SensorPin4 A3
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
SoftwareSerial K_30_Serial(12,13); //Sets up a virtual serial port
//Using pin 12 for Rx and pin 13 for Tx
float Celcius=0;
float Fahrenheit=0;
float sensorValue1 = 0;
float sensorValue2 = 0;
float sensorValue3 = 0;
float sensorValue4 = 0;
byte readCO2[] = {0xFE, 0X44, 0X00, 0X08, 0X02, 0X9F, 0X25}; //Command packet to read Co2 (see app note)
byte response[] = {0,0,0,0,0,0,0}; //create an array to store the response
//multiplier for value. default is 1. set to 3 for K-30 3% and 10 for K-33 ICB
int valMultiplier = 1;
int Trigger = 9;
int TriggerState;
void setup()
{
// put your setup code here, to run once:
pinMode(Trigger, INPUT);
Serial.begin(9600);//Opens the main serial port to communicate with the computer
K_30_Serial.begin(9600); //Opens the virtual serial port with a baud of 9600
sensors.begin();
}
// LOOP begins//////////////////////////////////////////////////
void loop() {
TriggerState = digitalRead(Trigger);
if (TriggerState == HIGH)
{
sendRequest(readCO2);
unsigned long valCO2 = getValue(response);
// Serial.print("Co2 ppm = ");
// Serial.print(valCO2);
sensorValue1 = analogRead(SensorPin1);
sensorValue2 = analogRead(SensorPin2);
sensorValue3 = analogRead(SensorPin3);
// sensorValue4 = sensorValue4 + analogRead(SensorPin4);
sensors.requestTemperatures();
Celcius=sensors.getTempCByIndex(0);
Fahrenheit=sensors.toFahrenheit(Celcius);
Serial.print(valCO2);
Serial.print(",");
Serial.print(Celcius);
Serial.print(",");
// Serial.print(" F ");
Serial.print(Fahrenheit);
Serial.print(",");
// Serial.print(" MC ");
// sensorValue = sensorValue/100.0;
Serial.print(sensorValue1);
Serial.print(",");
Serial.print(sensorValue2);
Serial.print(",");
Serial.println(sensorValue3);
// Serial.println(sensorValue1);
// Serial.println(sensorValue1);
delay(2000);
}
}
void sendRequest(byte packet[])
{
while(!K_30_Serial.available()) //keep sending request until we start to get a response
{
K_30_Serial.write(readCO2,7);
delay(50);
}
int timeout=0; //set a timeoute counter
while(K_30_Serial.available() < 7 ) //Wait to get a 7 byte response
{
timeout++;
if(timeout > 10) //if it takes to long there was probably an error
{
while(K_30_Serial.available()) //flush whatever we have
K_30_Serial.read();
break; //exit and try again
}
delay(50);
}
for (int i=0; i < 7; i++)
{
response[i] = K_30_Serial.read();
}
}
unsigned long getValue(byte packet[])
{
int high = packet[3]; //high byte for value is 4th byte in packet in the packet
int low = packet[4]; //low byte for value is 5th byte in the packet
unsigned long val = high*256 + low; //Combine high byte and low byte with this formula to get value
return val* valMultiplier;
}