I'm trying to stream the data from an ultrasonic rangefinder on an Arduino to my laptop. I seem to be having an issue with getting the new value from the Arduino. When I launch the Python script it starts printing the data just like I hoped. However this data does not change when I change the distance the sensor sees, it's almost like the serial.readline() is stuck on one of the first values. I'm new to this serial communication stuff so any help is greatly appreciated!
The code is below and for sanity I did check that the sensor is working with the serial monitor in the Arduino IDE.
import numpy
import serial
import time
import sys
import cv2
import pickle
#set up the camera stuff
cap = cv2.VideoCapture(0)
#container for images
images=[]
#container for distances
distances=[]
#first frame number
frame_num=1
#setup the serial connection and pause to establish it
ser = serial.Serial('/dev/cu.usbmodem1421', 9600,timeout=1)
time.sleep(5)
while True:
try:
#grab and image
ret,frame=cap.read()
#grab the distance
distance=ser.readline()
print(distance)
#process the image to a gray and 1241,376
#gray=cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
#gray_resized=cv2.resize(gray,(1241,376))
#cv2.imshow("FRAME",gray_resized)
#print(distance)
#images.append([frame_num,gray_resized])
#distances.append([frame_num,distance])
#ser.flush()
except KeyboardInterrupt:
#pickle.dump( images, open( "save.p", "wb" ) )
#pickle.dump( distances, open( "save.p", "wb" ) )
sys.exit()
Arduino code:
// defines pins numbers
const int trigPin = 7;
const int echoPin = 8;
// defines variables
long duration;
int distance;
void setup() {
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
Serial.begin(9600); // Starts the serial communication
delayMicroseconds(50);
}
void loop() {
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance in CM
distance= duration*0.034/2;
String distance_out=String(distance);
// Prints the distance on the Serial Monitor in CM
Serial.println(distance);
Serial.flush();
//Serial.print("Distance: ");
//Serial.println(distance);
}
Actually, python's serial.readline() is blocking until it get a EOL, so if you do not have lock issue that mean the Arduino is writing in the buffer faster that your python script read it.
You should flush the buffer after reading to ensure (close to) realtime reading with serial.flushInput() or serial.reset_input_buffer() depending of your version
Related
I am trying to send float values from Python on Windows to an Arduino. The first problem I encounter is that I cannot view the serial monitor when I think I am sending data from my Python script. I have read online that this is becuase only one application can manage the port at once: https://forum.arduino.cc/t/serial-communication-only-working-when-serial-monitor-is-opened/601107/12
However I have seen examples where the user is viewing the serial monitor to see data coming in over serial from Python and serial.print outs from the Arduino. So I am unsure what is the case... not being able to view the serial monitor sure does make debugging this senario hard.
My Python code:
import struct
import serial
import time
print('test123')
x=0.8
y=0.2
ser = serial.Serial('COM5', 9600, timeout=1)
#print(ser)
time.sleep(3)
def sendmess():
bin = struct.pack('ff',x,y) #Pack float value into 4 bytes
data = ser.write(bin)
#print(bin)
#print(len(bin))
#print([ "0x%02x" % b for b in bin])
#ser.close()
while True:
sendmess()
My Arduino Code:
int d = 250;
float incomingByte = 1;
void setup() {
// initialize the serial communication:
Serial.begin(9600);
pinMode(2, OUTPUT);
}
void loop() {
digitalWrite(2, HIGH);
delay(d);
digitalWrite(2, LOW);
delay(d);
// reply only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
d = 1000;
float incomingByte = Serial.read();
// say what you got:
Serial.println(incomingByte);
}
else{
Serial.println(incomingByte);
d = 20;
}
}
I see the LED flash every second so I know the serial buffer is >0, but I cannot get any data out :(.
Thanks in advance!
Mark
I have tried examples online, but I never get any data to display in the serial monitor. Nor can I say have a pin turn HIGH when I think I am getting the data I think I have sent. But without the Serial Monitor how can I debug this?
Unfortunately, you aren't able to connect more than two devices to the serial connection. However, using Python you should be able to read a response from your arduino and then print that to the python Terminal (or a file) and take a look at that.
The easiest way to do that would be to use pySerial and either ser.read(4) to read back 4 bytes of your float or ser.readline() which will look for either a '\n' which you can add to your arduino code, or a timeout. Then just print it to the python terminal with print().
As for actually reading the float, Serial.read() will only read in the next byte in the buffer. Since a float is 4 bytes long, you need to either read the 4 bytes into an array or use Serial.parseFloat()
Python Code
import struct
import serial
import time
x=0.8
y=0.2
ser = serial.Serial('COM5', 9600, timeout=1)
#print(ser)
time.sleep(3)
def sendmess():
bin = str(x) + str(y) #Pack float value into 4 bytes
data = ser.write(bin.encode())
echo = ser.readline()
print("Echo: " + echo)
#ser.close()
while True:
sendmess()
Arduino Code:
int d = 250;
float X;
float Y;
char buffer[40];
void setup() {
// initialize the serial communication:
Serial.begin(9600);
pinMode(2, OUTPUT);
}
void loop() {
digitalWrite(2, HIGH);
delay(d);
digitalWrite(2, LOW);
delay(d);
// reply only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
d = 1000;
X = Serial.parseFloat();
Y = Serial.parseFloat();
// say what you got:
sprintf(buffer, "X: %f Y: %f", X, Y);
Serial.println(buffer);
}
else{
Serial.println(buffer);
d = 20;
}
}
I made a code to control on a led by health percentage changing in league of legends. I used python and OCR to detect the health and send the health numbers to Arduino to control the led to make it blink with a 3 seconds delay when the health > 80% and blink for 1 second delay when the health < 80%.
The problem is that the led only blink with a 3 seconds delay for all health percentages. what shall I do ? thx in advance
Python code:
import serial
import time
import numpy as np
import cv2
from PIL import ImageGrab, Image
import os
import pytesseract
ser = serial.Serial('COM3', 9600)
#This loop allows opencv to capture the screen continuously
while True:
img = ImageGrab.grab(bbox=[840, 1020, 940, 1050 ])
img_np = np.array(img)
frame = cv2.cvtColor(img_np, cv2.COLOR_BGR2GRAY)
text = pytesseract.image_to_string(frame)
v3=-1
if "/" in text:
x = text.split("/")
try:
v1 = int(x[0])
v2 = int(x[1])
v3 = int((v1/v2)*100)
if v3<=100:
print(str(v3))
v4= str(abs(v3))
ser.write(b'v4')
time.sleep(0.1)
time.sleep(2)
except:
pass
cv2.imshow("Screen", frame)
if cv2.waitKey(1) == 27:
break
cv2.destroyAllWindows()
Arduino code
const int led=8;
String value;
int i;
void setup()
{
Serial.begin(9600);
pinMode(led, OUTPUT);
Serial.println("Connection established...");
}
void loop()
{
while (Serial.available())
{
value = Serial.read();
i = value.toInt();
if (100 >= i > 80)
{
digitalWrite(led, HIGH);
delay(3000);
digitalWrite(led, LOW);
}
else if (0 <= i < 80)
{
digitalWrite(led, HIGH);
delay(500);
digitalWrite(led, LOW);
}
else { digitalWrite(led, LOW);
}
}
}
enter code here
I assume in ser.write(b'v4') that you don't need " ' " since now all you're sending is the string "v4" regardless of it's value.
Serial.read() reads only 1 byte of data. If more bytes come in during your delay(), still the oldest byte is read. That means that your Serial port might be completely filled with values larger than 80.
You should do the 2 following things:
break up your arduino program to make sure, that you actually receive and evaluate the correct values on the port in a reasonable time.
do the LED blinking without delay(). Here is one of many tutorials how to do it: https://www.forward.com.au/pfod/ArduinoProgramming/TimingDelaysInArduino.html
I'm trying that my ESP-32 sends a high output to the Raspberry pi 3 B +. I already tried using different pins but the result is always the same. The Raspberry things he always gets a high input. The goal is, that the raspberry should take a photo when the esp 32 sends a high output.
Before you ask how the ESP should know when he should send an output. Well, it is when he detects an object.
Here you can see my python code
import time
import os # import the time
from picamera import PiCamera # import image from the camera into the Raspberry
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM) # define pins
GPIO.setup(11, GPIO.IN) # setup pin 18 as input
if __name__=='__main__':
#Variable
cam = Picamera() # makes the variable cam
while True:
if(GPIO.input(11) == GPIO.HIGH):
#Define how newimagen is made of (Variable) # make the variable fname which give us the date and Time
os.chdir('/home/pi/Desktop/image/') # Define where we are working now
images = [i for i in os.listdir(os.getcwd()) if i.lower().startswith('image')] # define what images is :
# os.listdir returns a list containing of the entries in the directory os.getcwd...
# os.getcwd returns the current working directory of a process
if images:
newest = max(images, key=os.path.getmtime) # max() is a method that returns the largest item of sth
# os.path.getmtime return the time of last modification
else:
newest = 'image0.jpg'
number = int(''.join([i for i in newest if i.isdigit()])) #number is the number of the newest image : image1 --> number = 1. This method look up if there is an image and which number it has
newimagen = 'image'+str(number+1)+'.jpg' # newimagen is the variable that decide which image it will be(image1 or image2...)
#Camera Code changing
cam.resolution = (2592,1944) # method to change the resoltuion
#Main Code
cam.capture('/home/pi/Desktop/image/'+newimagen) # method that take a photo and then save it on the local desktop as the name of newimagen
Here my Arduino Code
// Define SensorS pins
#define trigPin 15
#define echoPin 2
//Define SensorXL pins
#define trigPinXL 14
#define echoPinXL 13
//Define Raspberry Pin
#define RaspiPin 26
//Define Motor pins
#define motorIn3 16 //Input 3
#define motorIn1 17 //Input 1
#define motorIn4 18 //Input 4
#define motorIn2 19 //Input 2
// Defines variables
long duration;
int distance;
// Define ActivateDistance
const int activateDistance = 40;
const int activateDistance2 =40;
void setup()
{
// Sets the trigPin as an Output
pinMode(trigPin, OUTPUT);
pinMode(trigPinXL, OUTPUT);
// Sets the echoPin as an Input
pinMode(echoPin, INPUT);
pinMode(echoPinXL, INPUT);
// sets the Motorpins as outputs:
pinMode(motorIn1, OUTPUT);
pinMode(motorIn2, OUTPUT);
pinMode(motorIn3, OUTPUT);
pinMode(motorIn4, OUTPUT);
//Sets Raspberry Pin as output
pinMode(RaspiPin, OUTPUT);
// Starts the serial communication
Serial.begin(9600);
}
void stop()
{
// stop motor without duration
Serial.println("STOP");
digitalWrite(motorIn1, LOW);
digitalWrite(motorIn2, LOW);
digitalWrite(motorIn3, LOW);
digitalWrite(motorIn4, LOW);
}
void left(int duration)
{
//Motor goes to left
Serial.println("LEFT");
digitalWrite(motorIn1, LOW);
digitalWrite(motorIn2, HIGH);
digitalWrite(motorIn3, HIGH);
digitalWrite(motorIn4, LOW);
delay(duration);
stop();
}
void right(int duration)
{
//Motor goes to left
Serial.println("RIGHT");
digitalWrite(motorIn1, HIGH);
digitalWrite(motorIn2, LOW);
digitalWrite(motorIn3, LOW);
digitalWrite(motorIn4, HIGH);
delay(duration);
stop();
}
void forward(int duration)
{
//Motor goes forward
Serial.println("FORWARD");
digitalWrite(motorIn2, HIGH);
digitalWrite(motorIn4, HIGH);
digitalWrite(motorIn3, LOW);
digitalWrite(motorIn1, LOW);
delay(duration);
stop();
}
long get_distance(void)
{
//get distance from sensor
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPin, HIGH);
// Calculating the distance
distance = duration * 0.034 / 2;
return distance;
}
long get_distanceXL(void)
{
//get distance from sensor
// Clears the trigPin
digitalWrite(trigPinXL, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPinXL, HIGH);
delayMicroseconds(10);
digitalWrite(trigPinXL, LOW);
// Reads the echoPin, returns the sound wave travel time in microseconds
duration = pulseIn(echoPinXL, HIGH);
// Calculating the distance
distance = duration * 0.034 / 2;
return distance;
}
int turn = 0;
void loop()
{
// check sensor
if (get_distance() <= activateDistance)
{
Serial.println("Found an Obstacle!!!");
// go right for 1 second
right(1000);
while(turn<4)
{
//turn on the Raspberry Pin
digitalWrite(RaspiPin, HIGH);
if(get_distanceXL()>activateDistance2)
{
//go left for 1 second
left(1000);
forward(1500);
turn = turn + 1;
}
else
//go forward for 1 second
forward(1000);
}
//turn off the Raspberry Pin
digitalWrite(RaspiPin, LOW);
}
else
// go forward for 1 second
forward(1000);
}
I've opened my Terminal and saw this issue. I am not sure if this will help with my problem :
mmal: mmal_vc_port_enable: failed to enable port vc.null_sink:in:0(OPQV): ENOSPC
mmal: mmal_port_enable: failed to enable connected port (vc.null_sink:in:0(OPQV))0x1d13d20 (ENOSPC)
mmal: mmal_connection_enable: output port couldn't be enabled
Traceback (most recent call last):
File "/home/pi/Desktop/camera.py", line 12, in <module>
cam = PiCamera() # makes the variable cam
File "/usr/lib/python2.7/dist-packages/picamera/camera.py", line 433, in __init__
self._init_preview()
File "/usr/lib/python2.7/dist-packages/picamera/camera.py", line 513, in _init_preview
self, self._camera.outputs[self.CAMERA_PREVIEW_PORT])
File "/usr/lib/python2.7/dist-packages/picamera/renderers.py", line 558, in __init__
self.renderer.inputs[0].connect(source).enable()
File "/usr/lib/python2.7/dist-packages/picamera/mmalobj.py", line 2212, in enable
prefix="Failed to enable connection")
File "/usr/lib/python2.7/dist-packages/picamera/exc.py", line 184, in mmal_check
raise PiCameraMMALError(status, prefix)
picamera.exc.PiCameraMMALError: Failed to enable connection: Out of resources
There is a small error in your logic:
if(GPIO.input(11) == GPIO.HIGH)
Instead, you should be checking if there is any input on your pin 11, like
if(GPIO.input(11)){
// the rest f you logic
}
Which will return True or False, based on if there is any input (current) going trough PIN 11.
GPIO.HIGH is supposed to to set a pin to HIGH, not to check if the pin is getting input or no.
Ok I have been searching for an example for a while now can not seem to find any examples of relaying the tkinter slider values over I2C to Arduino. So far I have not tried to communicate with the Arduino yet. Ill cross that bridge next; for now I just want to figure out how to write the slide widget values and send over I2C.
Here is a simple GUI slider widget in Python 2 with what I believe is the correct setup for I2C communications. Ive updated the Rpi to set up the I2C as well. What I want to do in Arduino is simply read the values 0 to 180 for a servo control. It is important that it just writes values or in some way that can be used for an input. I have other code in the arduino that drives the same servo, if other conditions are met and this would then be ignored.
from Tkinter import*
import RPi.GPIO as GPIO
import time
import smbus
bus = smbus.SMBus=(1)
SLAVE_ADDRESS = 0x04
class App:
def __init__(self, master):
def SendScaleReading(self):
S = scale.get()# Now how do we write this and get the Scale Value and send it??
bus(SLAVE_ADDRESS, ord('S'))#According to an example this should be
#"bus.write_byte(SLAVE_ADDRESS, ord('S'))"
frame = Frame(master)
frame.pack()
scale = Scale(frame, from_=0, to=180, orient=HORIZONTAL, command=SendScaleReading)
scale.grid(row=1, column=1)
root = Tk()
root.wm_title('I2C servo control')
app = App(root)
root.geometry("200x50+0+0")
root.mainloop()
Ok a friend helped me out with and I wasnt too far off. Once I got this far I only a small issue with an IO error. I was getting [Errno 5] IO errors. Make sure you have a ground connected between the Arduino and Pi. When I searched this seemed to be overlooked by the many fixes out there offered. You need SDA, SLA and Gnd all connected.
So anyways here is the code that is working running an arduino i2c blink sketch. This will blink the led on pin 13 faster or slower based on the slider input in from the Rpi over I2C. I am going to try and write this code to control a servo next and if successful I will also post that code.
Rpi / python2 code below:
from Tkinter import*
import RPi.GPIO as GPIO
import time
import smbus
bus = smbus.SMBus(1)
SLAVE_ADDRESS = 0x28
class App:
def __init__(self, master):
def SendScaleReading(self):
S = scale.get()
print("we have" );
print( S )
bus.write_byte_data(SLAVE_ADDRESS, S, S )
frame = Frame(master)
frame.pack()
scale = Scale(frame, from_=0, to=180, orient=HORIZONTAL, command=SendScaleReading)
scale.grid(row=1, column=1)
root = Tk()
root.wm_title('I2C servo control')
app = App(root)
root.geometry("200x50+0+0")
root.mainloop()
Arduino i2c wire Blink sketch below:
#include <Wire.h>
// unique address for this I2C slave device
#define ADDRESS 0x28
// constants won't change. Used here to
// set pin numbers:
const int ledPin = 13; // the number of the LED pin
// Variables will change:
int ledState = LOW; // ledState used to set the LED
long previousMillis = 0; // will store last time LED was updated
// the follow variables is a long because the time, measured in miliseconds,
// will quickly become a bigger number than can be stored in an int.
volatile long interval = 1000; // interval at which to blink (milliseconds)
void setup() {
// set the digital pin as output:
pinMode(ledPin, OUTPUT);
Wire.begin(ADDRESS); // join i2c bus with address #4
Wire.onReceive(receiveEvent); // register event
Wire.onRequest(requestEvent); // register the request handler
}
//gets called when I2C read occurs
void requestEvent() {
//any request for data will return 0x14 (random number i picked for testing)
Wire.write( 0x14 );
}
// get called when I2C write occurs
void receiveEvent(int howMany) {
//just going to support 1 byte commands for now
if (howMany >0 ) {
int c = Wire.read();
interval = c * 10;
}
while (Wire.available() > 0 ) {
Wire.read();
}
}
void loop()
{
// here is where you'd put code that needs to be running all the time.
// check to see if it's time to blink the LED; that is, if the
// difference between the current time and last time you blinked
// the LED is bigger than the interval at which you want to
// blink the LED.
unsigned long currentMillis = millis();
if(currentMillis - previousMillis > interval) {
// save the last time you blinked the LED
previousMillis = currentMillis;
// if the LED is off turn it on and vice-versa:
if (ledState == LOW)
ledState = HIGH;
else
ledState = LOW;
// set the LED with the ledState of the variable:
digitalWrite(ledPin, ledState);
}
}
Ok well the servo code ended up being rather simple. Im sure it can be cleaned up so anyone with the know how please feel free to make improvements.
Arduino I2C Driven Servo Sketch is below:
#include <Wire.h>
#include <Servo.h>
// unique address for this I2C slave device
#define ADDRESS 0x28
Servo myservo;
int pos = 0;
void setup() {
myservo.attach(9);
Wire.begin(ADDRESS); // join i2c bus with address #4
Wire.onReceive(receiveEvent); // register event
Wire.onRequest(requestEvent); // register the request handler
}
//gets called when I2C read occurs
void requestEvent() {
//any request for data will return 0x14 (random number i picked for testing)
Wire.write( 0x14 );
}
// get called when I2C write occurs
void receiveEvent(int Pos) {
int val = Wire.read();
pos = val;
while (Wire.available() > 0 ) {
Wire.read();
}
}
void loop()
{
myservo.write(pos);
delay(15);
}
I'm getting a value of my moisture sensor over serial from Arduino to Raspberry PI. My Python script is supposed to log it. And it does, but the timing is getting delayed more and more exponentially. My guess (after 5 hours of Google) is that the problem is in the buffer somewhere and I am reading old data and "catching up". How do I adjust my code to get the latest serial info from my Arduino? Please keep in mind that I am a BIG noob and if you can explain as simple as possible. I've been up all night figuring it out but it's just that I know so very little about programming. Also adding the graph, there you can see the drift-off, I put the sensor out of water and put it in when I saw the graph drop.
Arduino code:
/*
Chirp - arduino example
Connection
Chirp pin 1 - no connection
Chirp pin 2 - Arduino VCC
Chirp pin 3 - Arduino A5
Chirp pin 4 - Arduino A4
Chirp pin 5 - Arduino pin 2
Chirp pin 6 - Arduino GND
*/
#include <Wire.h>
#define RELAY1 7
void writeI2CRegister8bit(int addr, int value) {
Wire.beginTransmission(addr);
Wire.write(value);
Wire.endTransmission();
}
unsigned int readI2CRegister16bit(int addr, int reg) {
Wire.beginTransmission(addr);
Wire.write(reg);
Wire.endTransmission();
delay(1100);
Wire.requestFrom(addr, 2);
unsigned int t = Wire.read() << 8;
t = t | Wire.read();
return t;
}
void setup() {
Wire.begin();
Serial.begin(9600);
pinMode(RELAY1, OUTPUT);
digitalWrite(RELAY1,HIGH);
pinMode(2, OUTPUT);
digitalWrite(2, LOW); //Reset the Chirp
delay(1); //maybe allow some time for chirp to reset
digitalWrite(2, HIGH); //Go out from reset
writeI2CRegister8bit(0x20, 3); //send something on the I2C bus
delay(1000); //allow chirp to boot
}
void loop() {
Serial.println(readI2CRegister16bit(0x20, 0)); //read capacitance register
//writeI2CRegister8bit(0x20, 3); //request light measurement
//delay(9000); //this can take a while
//Serial.print(", ");
//Serial.println(readI2CRegister16bit(0x20, 4)); //read light register
if (readI2CRegister16bit(0x20, 0) < 420){
//Serial.println ("watering");
digitalWrite(RELAY1,LOW);
delay(2000);
digitalWrite(RELAY1,HIGH);
delay(2000);
}
else{
digitalWrite(RELAY1,HIGH);
//Serial.println ("moist");
delay(2000);
}
}
Python code:
import serial
import time
import csv
import os
import plotly.plotly as py
from plotly.graph_objs import Scatter, Layout, Figure
os.chdir('/home/pi/csvdata')
username = '------------'
api_key = '------------'
stream_token = '------------'
py.sign_in(username, api_key)
trace1 = Scatter(
x=[],
y=[],
stream=dict(
token=stream_token,
maxpoints=200000000000
)
)
layout = Layout(
title='------------'
)
fig = Figure(data=[trace1], layout=layout)
print py.plot(fig, filename='------------')
stream = py.Stream(stream_token)
stream.open()
def mainloop():
name=time.strftime('%b %d %Y %H:%M:%S')
f=open(name+'.csv', 'wt')
writer = csv.writer(f,delimiter=',')
ser = serial.Serial('/dev/ttyUSB0',9600,timeout=1)
for t in range(500):
#time.sleep(5)
kk=ser.readline()
kk2=kk.split('\r',1)
s=kk2[0]
text=time.strftime('%X %x'),s
streamtext=({'x': time.strftime('%X %x'), 'y': kk})
writer.writerow (text)
stream.write (streamtext)
f.flush()
print (text)
time.sleep(5);
ser.flush()
#ser.flushInput()
#ser.flushOutput()
if t == 499:
print ("why")
f.close()
ser.close()
mainloop()
else:
time.sleep(5);
mainloop()
You haven't posted your code from the Arduino and Python, so here is an example that demonstrates what you want to do. copy the relevant parts into your code.
Arduino:
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
randomSeed(analogRead(0));
}
void loop() {
// put your main code here, to run repeatedly:
int moisture_value = random(300);
// millis() is the time in milliseconds since the arduino started running
Serial.println(String(millis()) + ":" + String(moisture_value)); // We send two pieces of data, i.e. time since arduino started and the sensor value
delay(1000);
}
Python:
import serial
import datetime
# Converts to an integer if it is an integer, or it returns it as a string
def try_parse_int(s):
try:
return int(s)
except ValueError:
return s
ser = serial.Serial('/dev/ttyACM0', 115200)
time_start = datetime.datetime.now() # The time that we started receiving data
while True:
data = ser.readline().decode("utf-8").strip('\n').strip('\r') # remove newline and carriage return characters
[time, moisture_value] = data.split(':')
print("Received: '{}'".format(data))
time_received = time_start + datetime.timedelta(milliseconds=try_parse_int(time)) # Add delta time to start time
print("Moisture value: {} at {}".format(try_parse_int(moisture_value), time_received))
This works by sending the time since the Arduino started along with the sensor reading. If we add this to the know starting time in Python, then we know the time that the reading was taken. Even if the sending is delayed for some reason, it doesn't matter.
Example output:
Received: '0:116'
Moisture value: 116 at 2017-03-15 11:26:43.024711
Received: '1000:4'
Moisture value: 4 at 2017-03-15 11:26:44.024711
Received: '2000:128'
Moisture value: 128 at 2017-03-15 11:26:45.024711
Received: '3001:123'
Moisture value: 123 at 2017-03-15 11:26:46.025711
Time formatting:
You can also format the time in a way that you prefer;
time_received = time_start + datetime.timedelta(milliseconds=try_parse_int(time)) # Add delta time to start time
time_formatted = '{0:%H}:{0:%M}:{0:%S} on {0:%d}/{0:%m}/{0:%y}'.format(time_received)
print("Moisture value: {} at {}".format(try_parse_int(moisture_value), time_formatted))
Output:
Moisture value: 46 at 11:42:10 on 15/03/17
Received: '117050:174'
Moisture value: 174 at 11:42:11 on 15/03/17
Received: '118050:298'