I have a Python script that takes in input from a camera. It then gets the position of an object in the image and sends it to the Arduino via pyserial and usb with the following format.
"Xpos-XYPos-Y" demo: 90X90Y would move the servos I have connected to 90 degrees.
What should happen when i run bellow should be that it moves the motors.
import serial
ser = serial.Serial('/dev/ttyACM1', 9600, timeout=1)
ser.flush()
ser.write(bytes("90X90Y", encoding='utf-8'))
But what really happens... Nothing?
So I thought okay, it might just be that my code is wrong so I tried many different variations.
I would list them but then it would take way too long to read. Basically, I changed the encoding and how I turn it into bytes.
I know the problem isn't my hardware (or at least I think) because I can download the Arduino IDE
onto the pi and send serial info through there. And it works!
Here is my Arduino code:
#include <Servo.h>
// Define Objects
Servo X;
Servo Y;
// Create varibles
String learndata;
String receiveX;
String receiveY;
int moveX;
int moveY;
// Straight forward
int defX = 95;
int defY = 5;
void setup(){
Serial.begin(9600);
//Attatch servos
X.attach(6);
Y.attach(7);
}
void loop(){
if (Serial.available() > 0){
// Parse servo input
receiveX = Serial.readStringUntil('X');
receiveY = Serial.readStringUntil('Y');
moveX = receiveX.toInt();
moveY = receiveY.toInt();
X.write(moveX);
Y.write(moveY);
}//if (Serial.available() > 0){
}//void loop(){
I also tried fully updating the raspberry pi to no avail.
Any help and what I should do? Are there any alternatives?
Related
I'm trying to flip a single bit on my arduino from 0 to 1 via python script. The following arduino code works great to turn on an LED if I type 1 into the serial monitor and hit enter:
int x;
void setup() {
// this code proves that the LED is working
digitalWrite(7, HIGH);
delay(300);
digitalWrite(7, LOW);
Serial.begin(115200);
}
void loop() {
Serial.print(x);
if(Serial.available()){
x = Serial.parseInt();
// if x is anything other than 0, turn the LED on
if (x){
digitalWrite(7, HIGH);
}
}
}
but when I try to use this python script, the variable x presumably stays 0 because the LED isn't turning on:
import serial
import time
arduino = serial.Serial(port='COM3', baudrate=115200, timeout=5)
time.sleep(5)
print(arduino.read())
arduino.write(b"\x01")
print(arduino.read())
arduino.close()
I put the two print statements in to try to figure out what was happening, but I can't make sense of the output. Usually it's
b'0'
b'0'
but sometimes it's
b'0'
b''
or if I run the script right after plugging the arduino in it's:
b'\x10'
b'\x02'
or some other random number.
What am I doing wrong here?
Using bytes("1", "<encoding>") instead of b"\x01" might work, where encoding is the encoding of your python file (like utf-8), although I'm not sure what the difference is.
Another possible error cause: your baud rate is enormous. For something as simple as this, you don't need such a huge baud; using the standard 9600 will work fine. Try changing the baud and see if that helps.
I am fairly new to hardware. I want to control an LED light using NodeMCU and Python. I uploaded an Arduino code in nodeMCU and then used pyserial library to get the serial output. But when I try to give input to the port, it doesn't work. I don't know where the problem is.
Here is the arduino code:
int inputVal = 0;
const int ledPin = 5; //D1 pin of NodeMCU
void setup() {
Serial.begin(9600);
delay(100);
pinMode(ledPin, OUTPUT);
digitalWrite(ledPin, 0);
}
void loop() {
while(Serial.available()>0){
inputVal = Serial.read();
}
Serial.println(inputVal);
if(inputVal==1){
digitalWrite(ledPin, HIGH);
Serial.println("LED is ON");
}
else{
digitalWrite(ledPin, LOW);
Serial.println("LED is OFF");
}
Serial.println("");
}
Here is the python code:
import serial
global ser
ser = serial.Serial("COM8", baudrate=9600, timeout=10,
parity=serial.PARITY_NONE,
stopbits=serial.STOPBITS_ONE,
bytesize=serial.EIGHTBITS)
while(True):
ser.write(bytes(1))
line = ser.readline()
print(line.decode('utf8'))
The output in python comes out to be:
0
LED is OFF
0
LED is OFF
0
LED is OFF
and so on. The ser.write() function isn't writing the value as 1 on the serial port. When I change the value of inputVal in Arduino code, the LED turns on and the output on arduino serial monitor comes as 1 LED is ON, which implies that the circuit connection and Arduino code is working fine.
I also noticed that the COM port that I am using can work with either python or arduino at a time. After uploading the arduino code with inputVal=1, the LED turned on and arduino serial monitor started displaying (1 LED is ON). But, as soon as I ran the python code, the led turned off and the python output came out to be 0 LED is OFF. Please help me.
Also, is there a way for me to control NodeMCU totally by python, without using arduino code first?
the output from python is correct. bytes(integer) creates an array of provided size, all initialized to null in your case size = 1, bytes(1), so the output that you have is 0x00 if you try bytes(10) the out put will be b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'.
what you need to do is to change ser.write(bytes(1)) to ser.write(bytes('1',encoding= 'utf-8')) that should work
I connected a Raspberry Pi and an Arduino via USB. Arduino is getting data from the world via sensors (EC and temperature sensor) and writing this data to serial. The Raspberry is writing this data into a database.
The Arduino sketch:
#include <OneWire.h>
#include <DallasTemperature.h>
int R1= 500;
int Ra=25; //Resistance of powering Pins
int ECPin= A0;
int ECGround=A1;
int ECPower =A4;
float PPMconversion=0.7;
float TemperatureCoef = 0.019;
float K=2.88;
#define ONE_WIRE_BUS 10 // Data wire For Temp Probe is plugged into pin 10 on the Arduino
const int TempProbePossitive =8; //Temp Probe power connected to pin 9
const int TempProbeNegative=9; //Temp Probe Negative connected to pin 8
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);// Pass our oneWire reference to Dallas Temperature.
float Temperature=10;
float EC=0;
float EC25 =0;
int ppm =0;
float raw= 0;
float Vin= 5;
float Vdrop= 0;
float Rc= 0;
float buffer=0;
void setup()
{
Serial.begin(9600);
pinMode(TempProbeNegative , OUTPUT ); //seting ground pin as output for tmp probe
digitalWrite(TempProbeNegative , LOW );//Seting it to ground so it can sink current
pinMode(TempProbePossitive , OUTPUT );//ditto but for positive
digitalWrite(TempProbePossitive , HIGH );
pinMode(ECPin,INPUT);
pinMode(ECPower,OUTPUT);//Setting pin for sourcing current
pinMode(ECGround,OUTPUT);//setting pin for sinking current
digitalWrite(ECGround,LOW);//We can leave the ground connected permanantly
delay(100);// gives sensor time to settle
sensors.begin();
delay(100);
R1=(R1+Ra);// Taking into acount Powering Pin Resitance
};
void loop()
{
GetEC();
PrintReadings(); // Cals Print routine [below main loop]
delay(20000);
}
void GetEC(){
sensors.requestTemperatures();// Send the command to get temperatures
Temperature=sensors.getTempCByIndex(0); //Stores Value in Variable
digitalWrite(ECPower,HIGH);
raw= analogRead(ECPin);
raw= analogRead(ECPin);// This is not a mistake, First reading will be low beause if charged a capacitor
digitalWrite(ECPower,LOW);
Vdrop= (Vin*raw)/1024.0;
Rc=(Vdrop*R1)/(Vin-Vdrop);
Rc=Rc-Ra; //acounting for Digital Pin Resitance
EC = 1000/(Rc*K);
EC25 = EC/ (1+ TemperatureCoef*(Temperature-25.0));
ppm=(EC25)*(PPMconversion*1000);
}
void PrintReadings(){
Serial.print("Rc: ");
Serial.print(Rc);
Serial.print(" EC: ");
Serial.print(EC25);
Serial.print(" Simens ");
Serial.print(ppm);
Serial.print(" ppm ");
Serial.print(Temperature);
Serial.println(" *C ");
Serial.print("Vdrop: ");
Serial.println(Vdrop);
Serial.print("Rc: ");
Serial.println(Rc);
Serial.print(EC);
Serial.println("Siemens");
};
code on Raspberry Pi:
import serial
import time
import re
import sqlite3
for com in range(0,4):
try:
PORT = '/dev/ttyACM'+str(com)
BAUD = 9600
board = serial.Serial(PORT,BAUD)
board.close()
break
except:
pass
DEVICE = '/dev/ttyACM'+str(com)
BAUD = 9600
s = serial.Serial(DEVICE, BAUD)
conn=sqlite3.connect('mydatabase.db')
cursor=conn.cursor()
#s.open()
time.sleep(5) # der Arduino resettet nach einer Seriellen Verbindung, daher muss kurz gewartet werden
#s.write("test");
while True:
response = s.readline()
numbers = re.findall(r"[-+]?\d*\.\d+|\d+", response)
if len(numbers) == 4:
temp = numbers[3]
ec = numbers[1]
result = cursor.execute("INSERT INTO sensordata (temp, ec) VALUES ({temp}, {ec})".form$
conn.commit()
print response
Data is written for about 24 hours on Raspberry side, then I get no serial output from Arduino any more. Same problem when I restart the python script again. When I restart the python script and serial communication is started again, the Arduino resets. I did not change this default behaviour. The fact that I still do not get data via serial shows me that it is no memory problem on the Arduino side. One more hint, that it must be a problem with the Raspberry, do I get from the fact that rebooting Raspberry solves the problem and the data is logged for another 24 hours.
Is anybody curious enough to give me a hint, how to establish a solid communication?
My problem is solved.
When I added massive serial printing on the Arduino side I found out that there is not really nothing received on the Raspberry side but much less, so that my python program could just not parse what the Arduino sketch was sending. Another observation was this:
When I watched the serial device with
screen /dev/ttyACM0
I got a very similar effect and could reproduce the problem. Due to the massive debug printing I added on the Arduino side I saw some characters received via pyserial that my python script was printing but the communication was seriously hurt by this screen command. And watching the serial device via screen I saw much more characters as if screen stole the show. It was a mess that I did not manage to clean up and I had to reboot the Raspberry. But told me that the problem must be on the Raspberry side.
What solved my problem was trying this communication pattern:
https://github.com/gskielian/Arduino-DataLogging/blob/master/PySerial/README.md
Don't understand completely what the author mean by 'HOWEVER, be careful that the Arduino is not constantly sending data to your program -- you will likely encounter errors from the buffer overfilling.'
The Arduino is now asked for data and responds instead of sending continuously.
This is all still mysterious to me but my question is answered and the Raspberry is now successfully receiving sensor data for 6 days.
I have connected Raspberry pi 2 model B with arduino uno via Bi-Directional Level shifter.
Raspberry pi GND ---------- GND Arduino
3.3v ---------- 5v
SCL ---------- A5
SDA ---------- A4
Hope my I2C connection is correct ?
and my Arduino is connected to 8-Channel Relay Board.
Now I have written code in which I can control the Relay board by Raspberry pi. For ex if i Press '1' the Relay 1 goes high.
Now I want to send data back from arduino to raspberry pi in order to cross check if Relay 1 is high or not, if Relay 1 is high then it should send some data back to Raspberry pi or else not.
My Rpi code is
import smbus
import time
# for RPI version 1, use "bus = smbus.SMBus(0)"
bus = smbus.SMBus(1)
# This is the address we setup in the Arduino Program
address = 0x04
def writeNumber(value):
bus.write_byte(address, value)
# bus.write_byte_data(address, 0, value)
return -1
def readNumber():
number = bus.read_byte(address)
# number = bus.read_byte_data(address, 1)
return number
while True:
var = input("")
if not var:
continue
writeNumber(var)
number = readNumber()
My Arduino code:
#include <Wire.h>
#define SLAVE_ADDRESS 0x04
#define RELAY1 9
int number = 0;
int state = 0;
void setup() {
pinMode(RELAY1, OUTPUT);
Serial.begin(9600); // start serial for output
// initialize i2c as slave
Wire.begin(SLAVE_ADDRESS);
// define callbacks for i2c communication
Wire.onReceive(receiveData);
Wire.onRequest(sendData);
Serial.println("Ready!");
}
void loop() {
delay(100);
}
// callback for received data
void receiveData(int byteCount){
while(Wire.available()) {
number = Wire.read();
Serial.print("data received: ");
Serial.println(number);
if (number == 1){
if (state == 0){
digitalWrite(RELAY1, HIGH); // set the LED on
state = 1;
}
else{
digitalWrite(RELAY1, LOW); // set the LED off
state = 0;
}
}
}
}
// callback for sending data
void sendData(){
Wire.write(number);
}
Now if I type 1 and due to some loose connection Relay 1 doesn't goes high, So in this case I want the arduino to take data from relay board and send it to Raspberry pi every time.
It will be great if someone can explain also that how it works.
Hope I was able to explain the problem. I have done lots of research but was not able to find some answer.
I am a beginner in python so please help me.
Thanks in advance.
The problem is that you are doing too much inside receiveData, which is called from the Interrupt Service Routine of the I2C utility code, twi.c. You must handle the data quickly, and don't call any other routines that depend on interrupts being enabled (they are disabled during this ISR).
This means you can't call Serial.print, and you can't call any other Wire sending methods. Even calling millis() or micros() is discouraged, as they do take a fair amount of time, and they depend on the TIMER interrupts being handled.
Of course, you are free call Wire.available() and Wire.read(). Actually, byteCount tells you how many bytes are available, so you don't need to call Wire.available() again.
Essentially, your receivedData routine can read the data inside the routine if you're quick about processing it. Otherwise, you can only set a (volatile) flag and then watch for it in loop. From what I see in your sketch, you could do something like this:
// variables that allow signalling between receiveData ISR and loop
volatile bool newData = false;
volatile uint8_t state = false;
// callback for received data
void receiveData(int byteCount)
{
// Read all the bytes; only the last one changes the relay state
while (byteCount-- > 0)
number = Wire.read();
if (state != number) {
state = number;
newData = true;
}
}
// callback for sending data
void sendData(){
Wire.write(number);
}
void loop()
{
if (newData) {
newData = false; // clear the flag for next time
if (number == 1){
digitalWrite(RELAY1, HIGH); // set the LED on
} else {
digitalWrite(RELAY1, LOW); // set the LED off
}
Serial.print("data received: ");
Serial.println( number );
}
}
The delay in loop is unnecessary, and may cause problems if you add something else to loop.
The volatile keyword keeps the compiler from optimizing loop. Without that keyword, the test for newData in loop would disappear because the compiler thinks that newData doesn't change during loop. Why test it? volatile newData tells the compiler that newData can change at any time, like during the receiveData ISR.
And be sure to print the number in the rpi code, as pholtz suggested!
In arduino code
change sendData() function like this
void sendData(){
int relay_status;
relay_status=digitalRead(4);
Wire.write(relay_status);
}
Also in hardware connect one 4th digital pin(or any other free I/O pins) to relay input.
hope it helps:)
Ok, looks like a pretty good start. Two things I want to suggest here.
First, in your python program you should print number so that you can see it's value changing. It's storing your feedback from the Arduino, so you want to display that feedback to the screen. This is as simple as changing number = readNumber() to print readNumber().
Second, in your Arduino program, are you sure that calling Wire.read() returns what you think it does? It looks to me like read() returns a byte. Chances are that when you type 1 it's really being sent as '1', not 1. Char vs. Int. Make sense?
So you might want to check if(number == '1') instead. Just my 2¢.
Your i2c bus is not connected properly. Remove the level shifter, and add 4.7k pull-ups to the 3.3v vcc on scl and sda lines. I2c chips only drive the line low, and require external resistors to pull the line high. This lets you mix voltage levels on your i2c bus fairly easily. Then you can go back to figuring out what your code is doing.
I get random characters when I perform a serial.readline(), sometimes it is other umbers and sometimes it is whole messages. The output should be "1,2" or "2,2"
Here are a couple of screenshots of the output of serial.readline().
I have tried to put a delay at before serial.readline() but it did not make a difference.
There is usually a strange character at the beginning:
I have also received strange messages:
There is a problem later on in the program that causes the program to hand because sometimes I just receive a blank line.
Is there a way to get consistent output from serial?
Here is the arduino code:
void setup() {
// initialize the LED pin as an output:
pinMode(ledPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT);
Serial.begin(9600);
}
void loop(){
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
// check if the pushbutton is pressed.
// if it is, the buttonState is HIGH:
if (buttonState == HIGH) {
// turn LED on:
digitalWrite(ledPin, HIGH);
Serial.println("1,2");
}
else {
// turn LED off:
digitalWrite(ledPin, LOW);
Serial.println("2,2");
}
}
And here is the python code:
ser = serial.Serial('/dev/ttyUSB0', 9600)
line=ser.readline()
coord= line.strip()
print coord
EDIT:
I tried putting ser.flushInput() after the ser.open() and I get the same output.
Have you flushed the serial buffer
ser.flushInput()
I've been having the same issue when interfacing between pyserial and Arduino. This may be an old post, but in case someone else is having the same trouble, I remedied my problem by inserting:
ser.flushInput()
...right before my ser.readline() call.
How to Read serial data from an Arduino in Linux
Nothing fancy here. I’m getting the current port configuration, setting the input/output speed to 9600 baud, setting the data expectations to be 8 bits per word, with no parity bit and no stop bit, setting canonical mode, and then committing those changes back to the serial port.
If I am not mistaken you have to change the mentioned settings when connecting through serial port.
You do not mention it, but I guess you are using the pySerial library. Regardless you can use it with the correct settings to connect through serial. The constructor of the API allows all the parameters which are noted below:
Pyserial Library
I have not tested this approach as I have had a similar problem in C not Python.
What happens if you break it down to something simpler?
On the Arduino:
void setup()
{
Serial.begin(9600);
}
int i = 0;
void loop()
{
delay(1000);
Serial.print("Hello World ");
Serial.println(i);
i++;
}
And in the Python REPL...
import serial
ser = serial.Serial('/dev/ttyUSB0', 9600)
while(1):
ser.readline()
The first behavior you should observe is that when you initiate the serial connection, the Arduino reboots. This takes a few seconds.
The second behavior you should observe is that (if you're typing this in the REPL slowly) when the while(1) loop begins, you get all of the serial data that had accumulated since you initiated the serial connection. It takes me a few seconds to type all that out, so when I hit Enter after ser.readline() I see:
'Hello World 1\r\n'
'Hello World 2\r\n'
'Hello World 3\r\n'
I only mention this to make sure you're familiar with two things that burned me a bit the last time I messed with serial communication to an Arduino: it needs time to reboot after connecting, and the serial data buffers. readline() will only give you one line in the buffer - not everything that's in the buffer.
Is it possible you're trying to sent/receive data before it's done rebooting? What about button bounce - could a dozen high/low state detections be messing something up?