I'm trying to learn how to send messages from the Raspberry Pi 4 to the Arduino Mega 2650 device via USB cable for use in a Jukebox project. I'm starting by doing some tutorials and I'm stumped as to a certain behavior. I hope someone can help me.
Here is the code on the Arduino Mega device:
#define LED_2_PIN 2
#define LED_3_PIN 3
#define LED_4_PIN 4
void powerOffAllLEDs() {
digitalWrite(LED_2_PIN, LOW);
digitalWrite(LED_3_PIN, LOW);
digitalWrite(LED_4_PIN, LOW);
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
pinMode(LED_2_PIN, OUTPUT);
pinMode(LED_3_PIN, OUTPUT);
pinMode(LED_4_PIN, OUTPUT);
powerOffAllLEDs();
}
void loop() {
// put your main code here, to run repeatedly:
if (Serial.available() > 0) {
int ledNumber = Serial.read() - '0';
powerOffAllLEDs();
switch (ledNumber) {
case 2:
digitalWrite(LED_2_PIN, HIGH);
break;
case 3:
digitalWrite(LED_3_PIN, HIGH);
break;
case 4:
digitalWrite(LED_4_PIN, HIGH);
break;
default:
// wrong pin number, do nothing
// all LEDs will be powered off
break;
}
}
}
If I run this code on the Raspberry Pi, I see one of the LED's flash quickly on and off.
import time, serial
ser=serial.Serial('/dev/ttyACM0', 9600, timeout=1)
ser.flush()
while True:
ser.write(b"4\n")
time.sleep(1)
If I run this code on the Raspberry Pi, I don't see any LED's light-up.
import time, serial
ser=serial.Serial('/dev/ttyACM0', 9600, timeout=1)
ser.flush()
ser.write(b"4\n")
time.sleep(1)
If I comment out the "powerOffAllLEDs()" just before the switch statement on the Arduino, then the light stays on with the first Raspberry Pi code. It still does nothing with the second.
Its almost like the "Serial.available()" is picking up stuff from the Raspberry Pi even though it shouldn't be sending anything.
This is obviously just a tutorial I'm trying to understand...ultimately I need to be able to send a two character (1 letter and 1 number - ie. "A1") code and have the LED stay on until I send another code.
Related
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.
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.
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.
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':.
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