reducing delay on raspberry pi to arduino serial communication - python

I'm currently trying to rotate a motor on my Arduino Uno through serial communication from my Raspberry Pi 3. My code itself currently works however sometimes when running the python script the motor will not turn or indicate any response. From what I've been able to find online, I feel like I'm sending signals faster than the Arduino is reading them, and I can't seem to find a way to minimize the delay and make my motor response consistent.
Here is my Arduino code:
#include <Stepper.h>
#define STEPS 128
Stepper stepper(STEPS, 8, 10, 9, 11);
void setup() {
Serial.begin(9600);
}
void loop() {
if (Serial.read() == 50) {
stepper.setSpeed(8); // rpm
stepper.step(128); // do n steps -- corresponds to one revolution in one minute
}
else if (Serial.read() == 51) {
stepper.setSpeed(8); // rpm
stepper.step(-128); // do n steps -- corresponds to one revolution in one minute
}
}
Here is my Python code
import serial
import time
ser = serial.Serial('/dev/ttyACM0', 9600)
time.sleep(1)
num="3"
ser.write(bytes(num.encode()))
Also I'm not sure how Arduino is reading my ser.write, as when num = 2, I see "50" in my Serial Monitor, when num = 3, "51" appears in my Serial Monitor, and so forth.
Thank you!

Serial communication is always done in Bytes. So whatever you send through your interface will be received as a sequence of Bytes. As you encoded your "3" as UTF-8 it will be sent as 0x33 (51). Your "2" is 0x32 (50) respectively.
Increasing the baudrate as suggested in a comment won't help you as it will only increase the speed data is transmitted/received. Without a measurement you won't notice a difference betweeen sending a single byte with 9600 or 115200 baud.
As long as both device operate on the same baudrate and you do not exceed the max baudrate of any device (somewhere around 2 million baud for Arduino Uno) you cannot send to fast. (given a suitable cable and distance)
You might run into problems with too long cables but that's several meters for 9600 baud even in noisy industrial environment.
Usually you wait for data to be available in the receive buffer befor you read.
void loop() {
// send data only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
// say what you got:
Serial.print("I received: ");
Serial.println(incomingByte, DEC);
}
}
Maybe not doing so causes some delay. I cannot tell for sure as you did not provide the length of the observed delay.
If the Arduino is already running when you execute your Python code I don't see any other issue with your code. If it is booting while you send you might observe some delay because of the Arduino bootloader. It will wait some time for possible firmware updates befor it starts the actual application code.

Small pieces of data may sit around in the output buffer before being sent. Try using Serial.flush() after write to let the os know you want the data sent asap.

Related

Connecting Python to arduino - check if string is equal to do task

I am passing a string from a computer with python(using pyserial) to my arduino uno and if it is equal to a set value, I need it to perform a task - I haven't even made it far enough to get the set values, I can't even get something to happen if it is passed at all. I just copied some of the blink code, to run if anything is received on serial and sometimes it works, and sometimes it doesn't, seemingly without reason. If anyone has an example of how to do this or knows where I am going wrong help would be appreciated.
Python Code
import serial
import time
def write():
arduino = serial.Serial('/dev/ttyUSB0', 9600, timeout=.1)
time.sleep(1) #give the connection a second to settle
arduino.write(str.encode("Hello from Python!"))
write()
Arduino Uno Code
void setup() {
Serial.begin(9600);
}
void loop() {
if(Serial.available() > 0) {
char data = Serial.read();
char str[2];
str[0] = data;
str[1] = '\0';
digitalWrite(LED_BUILTIN, HIGH); // turn the LED on (HIGH is the voltage level)
delay(1000); // wait for a second
digitalWrite(LED_BUILTIN, LOW); // turn the LED off by making the voltage LOW
delay(1000);
}
}
Add a delay(100) before your if(Serial.available() > 0) { statement.
More about this:
Your Arduino only has 1 core. If you do not have a delay() in your loop(), then the loop will take up 100% cpu usage all the time. This stops it from being able to execute background concurrent threads, e.g. to listen to Serial port, do bluetooth/wifi stuff, etc..
The delay() allows the main loop (or any thread) to sleep, so that the arduino's interrupt can execute other concurrent threads.

pySerial and Arduino communication

So far, I was exploring Python with Arduino using pySerial. I made some projects where pySerial reads something from the serial port.
import serial
arduinoSerialData = serial.Serial('com11',9600) #Create Serial port object called arduinoSerialData
while (1==1):
if (arduinoSerialData.inWaiting()>0):
myData = arduinoSerialData.readline()
print (myData)
int trigPin=13; //Sensor Trig pin connected to Arduino pin 13
int echoPin=11; //Sensor Echo pin connected to Arduino pin 11
float pingTime; //time for ping to travel from sensor to target and return
float targetDistance; //Distance to Target in inches
float speedOfSound=776.5; //Speed of sound in miles per hour when temp is 77 degrees.
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(trigPin, OUTPUT);
pinMode(echoPin, INPUT);
}
void loop() {
// put your main code here, to run repeatedly:
digitalWrite(trigPin, LOW); //Set trigger pin low
delayMicroseconds(2000); //Let signal settle
digitalWrite(trigPin, HIGH); //Set trigPin high
delayMicroseconds(15); //Delay in high state
digitalWrite(trigPin, LOW); //ping has now been sent
delayMicroseconds(10); //Delay in low state
pingTime = pulseIn(echoPin, HIGH); //pingTime is presented in microceconds
pingTime=pingTime/1000000; //convert pingTime to seconds by dividing by 1000000 (microseconds in a second)
pingTime=pingTime/3600; //convert pingtime to hourse by dividing by 3600 (seconds in an hour)
targetDistance= speedOfSound * pingTime; //This will be in miles, since speed of sound was miles per hour
targetDistance=targetDistance/2; //Remember ping travels to target and back from target, so you must divide by 2 for actual target distance.
targetDistance= targetDistance*63360; //Convert miles to inches by multipling by 63360 (inches per mile)
Serial.println(targetDistance);
delay(100); //delay tenth of a second to slow things down a little.
}
For now, my code looks something like this. How can I make use of my ultrasonic sensor in Python and send signals to my Arduino program? In other words, can I make my Arduino file read from the Python file that I have or it is only one direction?
pySerial allows for communication over serial in both directions. On the Arduino side, you need to call Serial.read where appropriate to read data stream from Python. In Python, you just need to send data using the function serial.write. If using Python 3, input to serial.write needs to be in byte format.

How to make Raspberry pi respond to Arduino code via USB connection

I have tried connecting Arduino to the raspberry Pi through USB cable. The Arduino board is connected to an Ultrasonic sensor and sends a serial message of either 0 or 1 based on whether it finds a barrier in a certain distance (very simple code). The problem is this : I'm trying to get the Raspberry Pi to read the Arduino code AND play a mp3 file at the same time but for some reason that doesn't seem to work ! I'm not sure if the problem lies in coding or If maybe it's impossible for Pi to respond to a message sent from Arduino to the serial monitor(It would be really sad if that's the case). Any help would be very appreciated
This is the Arduino Code (I'm using UNO board) :
/*
HC-SR04 Ping distance sensor:
VCC to Arduino
Vin GND to Arduino GND
Echo to Arduino pin 12
Trig to Arduino pin 11 */
#include <NewPing.h> //downloaded from the internet & unzipped in libraries folder in Arduino Directory
#define TRIGGER_PIN 11 // Arduino pin tied to trigger pin on the ultrasonic sensor.
#define ECHO_PIN 12 // Arduino pin tied to echo pin on the ultrasonic sensor.
int maximumRange = 70; // Maximum range needed
int minimumRange = 35; // Minimum range needed
long duration, distance; // Duration used to calculate distance
void setup() {
Serial.begin (9600);
pinMode(TRIGGER_PIN, OUTPUT);
pinMode(ECHO_PIN, INPUT);
}
void loop() {
/* The following trigPin/echoPin cycle is used to determine the distance of the nearest object through reflecting soundwaves off of it */
digitalWrite(TRIGGER_PIN, LOW);
delayMicroseconds(2);
digitalWrite(TRIGGER_PIN, HIGH);
delayMicroseconds(10);
digitalWrite(TRIGGER_PIN, LOW);
duration = pulseIn(ECHO_PIN, HIGH);
distance = (duration/2) / 29.1; //formula to convert the value measured by the ultrasonic sensor into centimeters
if (distance >= maximumRange || distance <= minimumRange)
{
Serial.println("0"); //means the path is clear
}
else {
Serial.println("1"); //means there is an obstacle in front of the ultrasonic sensor !
}
delay(50); //Delay 50ms before next reading.
}
And this is the python code that I used in my Pi (I have Raspberry Pi 2):
NOTE : I have commented the parts that don't work since I tried many different code combinations shown below
import serial
import RPi.GPIO as GPIO
import sys
import os
from subprocess import Popen
from subprocess import call
import time
import multiprocessing
GPIO.setmode(GPIO.BOARD)
GPIO.setwarnings(False)
arduinoSerialData = serial.Serial('/dev/ttyACM0', 9600)
while True:
time.sleep(0.01)
if(arduinoSerialData.inWaiting()>0):
myData = arduinoSerialData.readline()
print(myData)
if myData == '1': #THIS IS WHERE THE PROBLEMS START
#os.system('omxplayer sound.mp3') #tried this didn't work
#os.system('python player.py') #which is basically a python program with the previous line in it, also not working!
# I even tried enclosing that part (after if myData == '1') in a while loop and also didn't work !
Firstly, your IF condition doesn't look right. I don't see how distance <= minimumRange means the path is clear.
Next, you are writing a line to the serial port; a line that could be either 0\r\n or 1\r\n. Then you're reading a line from the Arduino, returning one of the two aforementioned possibilities. You're then comparing the line you've read, to 1. Neither 0\r\n nor 1\r\n is equal to 1, so its no surprise that the condition is never true. You can fix this in a number of ways:
Change the Serial.println() to Serial.print()
Change arduinoSerialData.readline() to arduinoSerialData.readline().rstrip()
Change the condition to if 1 in myData:
Another thing to remember is, read() returns a bytes object in Python 3 not a string as in Python 2. So any comparison involving literals should make sure to include the requisite b'' envelope. Like, if you strip the CRLF from the read data, your condition should instead be if myData == b'1':.

Serial comms from Arduino to RPi via pins

I am stuck and dont know why. I am trying to transmit from an Arduino Nano to a RPi via the TX and Rx pins respectively.
This my code so far:
Arduino TX:
void setup(){
Serial.begin(9600);
}
void loop(){
bProgramLoop = 1
while(bProgramLoop == 1){
Serial.write(1);
}
}
The Raspberry Side:
import serial
oSer = serial.Serial("/dev/ttyAMA0",baudrate=9600,timeout=1)
while True:
sSerialInput = oSer.read(1)
#sSerialInput = oSer.readline()
print sSerialInput
After loading the sketch onto the Arduino and starting the python script, the Raspberry simply does not read anything.
NOTE:
I have connected the Tx pin from the Arduino to the Rx pin from the RPi via a Voltage divider and some jumper wires.
I have tried "readline()" too, but no luck
Any suggestions?
I have found the a solution to the problem I am having. I am still a proper noob, but as far as I can figure it out, sending serial data over the Tx pin is problematic because it is used by the usb port and then to your PC.
Thus the solution is to use the SoftwareSerial library. I have modified my two code sketches as follows:
Arduino:
#include <SoftwareSerial.h>
SoftwareSerial mySerial(4,3); // (RX,TX) - Pin Setup for any digital pins you want as Rx or Tx
void setup(){
Serial.begin(9600);
mySerial.begin(57600); // initialize serial communication with serial pin
}
void loop(){
bProgramLoop = 1
while(bProgramLoop == 1){
mySerial.write("Anything");
}
}
Raspberry:
import serial
oSer = serial.Serial("/dev/ttyAMA0",baudrate=9600,timeout=1)
while True:
sSerialInput = oSer.readline()
print sSerialInput
As it is I am able to transmit data from the Arduino to the RPi. HOWEVER, I am still having issues converting the string to an integer or float.
see this post for details: Python readline() returns string that wont convert to int or float

Pyserial readline() shows mix up of bits

I am very new to Arduino and Python. I'm working on the communication between an Arduino Uno and my laptop using Pyserial. The Python script in my laptop is called by an H3D Viewer, which is linked to a Novint Falcon.
My laptop sends the positional data of the Falcon to the Arduino, to be sent to the robot. Right now I'm merely trying to read back the data I sent from the Arduino, to make sure everything works. But it doesn't!
Here is part of my Python script (which is called by a .x3d file).
dp_text, = references.getValue()
class display (threading.Thread):
def __init__(self, delay):
threading.Thread.__init__(self)
self.delay = delay
def run(self):
while 1:
receivedFalconData=[]
tex=[]
tex.append("DevicePosX = " + str(localFalconData))
receivedFalconData=ser.readline()
ser.flush()
ser.flushInput()
tex.append("Input = " + str(receivedFalconData))
dp_text.string.setValue(tex)
time.sleep(self.delay)
displaying = display(0.1)
displaying.start()
The above thread is in charged of refreshing the text node in the H3D Viewer every 100ms. The Arduino's code is below:
#include <SoftwareSerial.h>
char Axispos[6] ={0,0,0,0,0,0};
int xvalue= 0;
SoftwareSerial mySerial(7,6); //RX, TX
void setup() {
Serial.begin( 9600 );
Serial.flush();
mySerial.begin(9600);
}
void loop(){
while( Serial.available() > 0 )
{
Serial.readBytes(Axispos,6);
Serial.flush();
xvalue = (Axispos[0] << 8) + (Axispos[1] & 0xff);
Serial.println(xvalue);
Serial.flush();
mySerial.write(Axispos);
mySerial.flush();
delay(500);
}
}
The x-axis value read by the Arduino is sent back to the laptop and stored in receivedFalconData. This value is supposed to be the same as localFalconData, which is the x-axis value in the script itself.
The results: receivedFalconData mimics localFalconData for a few seconds, before going wild.
It sometimes shows the correct value again, though, which tells me this is probably an issue with the Pyserial input buffer overflow? How could this be the case, since (if I'm correct) serial.readline() empties the input buffer after reading it? Furthermore, the Arduino only sends data every .5 second, whereas the laptop reads every .1 second.
But when the readline() part is placed in the class for sending data (which is called whenever the Falcon has new data available), receivedFalconData is perfectly correct.
Also, I get two of these ☐ symbols behind receivedFalconData when it is displayed in H3D...
Can someone who has experience with Pyserial please please help me? I would gladly give more info if my problem is still unclear to you.

Categories

Resources