Read multiple arduino's using a Raspberry Pi 3 through USB - python

I have 3 arduino's that have RC522 rfid readers attached to them. They each have their own power supplies and they are connected to a raspberry pi 3 via the usb ports. I am getting really inconsistent results when running the reader in python. It does appear all 3 are reading but the loop does some weird things. Sometimes the chip code keeps repeating after the chip is removed and other times it works properly. There does not appear to be any consistency with which arduino is behaving oddly either.
Any help would be greatly appreciated!!!
Here is the arduino code (The same code was copied to each arduino with the exception of the initial println that indicates which arduino is connected).
#include <SPI.h>
#include <MFRC522.h>
#define RST_PIN 5 // Configurable, see typical pin layout above
#define SS_PIN 53 // Configurable, see typical pin layout above
#define MOSI_PIN 51
#define MISO_PIN 50
#define SCK_PIN 52
MFRC522 rfid(SS_PIN, RST_PIN); // Instance of the class
MFRC522::MIFARE_Key key;
String read_rfid;
void setup() {
Serial.begin(9600);
SPI.begin(); // Init SPI bus
rfid.PCD_Init(); // Init MFRC522
for (byte i = 0; i < 6; i++) {
key.keyByte[i] = 0xFF;
}
Serial.println(F("The Toy Maker's Sanctuary RDIF Reader 1 Online."));
//Serial.println(F("Using the following key:"));
//printHex(key.keyByte, MFRC522::MF_KEY_SIZE);
}
void loop() {
// Reset the loop if no new card present on the sensor/reader. This saves the entire process when idle.
if ( ! rfid.PICC_IsNewCardPresent())
return;
// Select one of the cards
if ( ! rfid.PICC_ReadCardSerial())
return;
dump_byte_array(rfid.uid.uidByte, rfid.uid.size);
Serial.println(read_rfid);
}
/*
Helper routine to dump a byte array as hex values to Serial.
*/
void dump_byte_array(byte *buffer, byte bufferSize) {
read_rfid = "";
for (byte i = 0; i < bufferSize; i++) {
read_rfid = read_rfid + String(buffer[i], HEX);
}
}
Here is the python code
import serial
ser0=serial.Serial("/dev/ttyACM0", 9600, timeout=1)
ser1=serial.Serial("/dev/ttyACM1", 9600, timeout=1)
ser2=serial.Serial("/dev/ttyACM2", 9600, timeout=1)
ser0.baudrate=9600
ser1.baudrate=9600
ser2.baudrate=9600
read_ser0=""
read_ser1=""
read_ser2=""
while True:
read_ser0=ser0.readline()
print("0: ",read_ser0)
read_ser1=ser1.readline()
print("1: ",read_ser1)
read_ser2=ser2.readline()
print("2: ",read_ser2)
read_ser0=""
read_ser1=""
read_ser2=""

Related

Arduino/Python Serial communication

I want to send data from python to may Arduino Mega via serial output. The Arduino's RX Led blinks, when I run the Python script. However, the Serial.available() = false. This is just an example code. The real project is building a speedometer for sim racing games (using UDP data). Any idea why it isn't working?
Here is the code:
Python:
import time
import serial
port = "COM3"
Arduino = serial.Serial(port ,9600, timeout=1);
i = 0
while i<= 9999 :
time.sleep(1/10)
i+=1
print(i)
Arduino.write(i)
Arduino:
#include <Arduino.h>
#include <TM1637Display.h>
#define CLK 2
#define DIO 3
int i=0;
int Number;
TM1637Display display(CLK, DIO);
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(9600);
display.setBrightness(0x0f);
display.showNumberDec(9999);
delay(3000);
}
void loop() {
Number= Serial.read();
if (Serial.available()>0){
display.setBrightness(0x0f);
display.showNumberDec(Number);
}
if (Serial.available() == false){
display.setBrightness(0x0f);
display.showNumberDec(0000);
}
}
This is how it works. Big thanks to csongoose from reddit who helped me a lot. Also thanks to all your replies on this.
Python:
import time
import serial
port = "COM3"
Arduino = serial.Serial(port ,9600, timeout=1);
i = 0
while i<= 9999 :
time.sleep(1)
i+=1
print(i)
#converts int i to string b
b = "%s" %i
Arduino.write(bytes(b, 'utf-8'))
#the Arduino waits for this and can seperate the numbers
Arduino.write(b'\n')
Arduino:
#include <Arduino.h>
#include <TM1637Display.h>
#define CLK 2
#define DIO 3
#define D1 5
#define D2 7
int Number;
String b;
//i am using a 7-digit display to show the numbers
TM1637Display display(CLK, DIO);
void setup() {
pinMode(LED_BUILTIN, OUTPUT);
pinMode(D1 ,OUTPUT);
pinMode(D2 ,OUTPUT);
Serial.begin(9600);
}
void loop() {
if (Serial.available()>0){
//looks for new numbers, which are sperated with '\n'
b = Serial.readStringUntil('\n');
//converts string b to integer Number
Number = b.toInt();
display.setBrightness(0x0f);
display.showNumberDec(Number);
//delay equals the same rate as python sends data
delay(1000);
}
//this indicates if the data is available and if the Arduino has rebooted
//you need to wait for it and then start your Python stream
if (Serial.available() == 0){
digitalWrite( D1, HIGH);}
else digitalWrite(D1, LOW);
if (Number != 0){
digitalWrite( D2, HIGH);}
else digitalWrite(D2, LOW);
}

Remote I/O Error on I2C Bus Raspi Master Arduino Mega Slave

I have connected my raspi (Master) with Arduino Mega (Slave) and want to continuously transfer the analog readings from analog pins A0-A3 to the raspi. Program runs for some time and the crashes giving me:
[Errno 121] Remote I/O Error
I am suspecting 2 things could be the problem: 1) The while loop => longer sleep times result in a longer running time until the program crashes 2) I read somewhere that the wire library does an onReceive command before it does an onRequest?
Here is my Arduino and raspi code:
Arduino Mega Code
#include
int SLAVE_ADDRESS = 0x08;
int analogPin1 = A0;
int analogPin2 = A1;
int analogPin3 = A2;
int analogPin4 = A3;
void setup(){
Wire.begin(SLAVE_ADDRESS);
Wire.onRequest(sendAnalogReading);
}
void loop(){
}
void sendAnalogReading(){
uint16_t reading1 = analogRead(analogPin1);
uint16_t reading2 = analogRead(analogPin2);
uint16_t reading3 = analogRead(analogPin3);
uint16_t reading4 = analogRead(analogPin4);
Wire.write((char *) &reading1, 2);
Wire.write((char *) &reading2, 2);
Wire.write((char *) &reading3, 2);
Wire.write((char *) &reading4, 2);
}
This is the script on my Raspi:
import smbus
import time
bus = smbus.SMBus(1)
SLAVE_ADDRESS = 0x08
def requestreading():
block = bus.read_i2c_block_data((SLAVE_ADDRESS), 0, 8)
print(block)
while True:
#var = input("Press any key for reading: ")
requestreading()
time.sleep(0.1)
The could should run continuously however i feel the actual runtime until it crashes depends on 2 factors. Length of time.sleep() in my while loop and if the measured values change much.

Cannot send/receive number through USB to Arduino to control a motor

I'm having a project to use pyserial to send a number to an Arduino. This number is RPM (round per minute). Arduino will receive this number to control the motor (in here I use PID Controller) and then send the number Arduino received back to Python console. The problem is, I tried to send float number to Arduino, but it receives nothing. Here is the problem:
#include <TimerOne.h>
#include <Encoder.h>
#define A 2 //Encoder pins
#define B 3
Encoder encoder(2,3);
//Config pins for motor control:
int pinAIN1 = 9; //Direction
int pinAIN2 = 8; //Direction
int pinPWMA = 5; //Speed
int pinSTBY = 4; //Stanby
float receive;
float tsamp = 0.01;
float xung = 0;
float last_xung = 0;
float current_speed = 0;
float ref_speed ; //The reference speed
float error = 0;
float last_error = 0;
float PID,last_PID;
float Kp =0.15 , Ki =0, Kd = 0.01;
void dotocdo()
{
if ( ref_speed >= 0)
{
digitalWrite(pinAIN1, 1);
digitalWrite(pinAIN2, 0);
analogWrite(pinPWMA, PID);
}
if ( ref_speed < 0)
{
digitalWrite(pinAIN1, 0);
digitalWrite(pinAIN2, 1);
analogWrite(pinPWMA, abs(PID));
}
float P;
static float I,D;
current_speed = 60*(xung-last_xung)/(tsamp*374*4);
last_xung = xung;
Serial.println(current_speed);
error=abs(ref_speed)-abs(current_speed);
P = Kp*error;
D = Kd*(error - last_error)/tsamp;
I = Ki*error*tsamp;
PID = last_PID + P + I + D;
last_error = error;
last_PID = PID;
if (PID >= 255) {PID = 255;}
if (PID <= -255) {PID = -255;}
}
void setup() {
Serial.begin(115200);
pinMode(pinPWMA, OUTPUT);
pinMode(pinAIN1, OUTPUT);
pinMode(pinAIN2, OUTPUT);
pinMode(pinSTBY, OUTPUT);
pinMode(A, INPUT);
pinMode(B, INPUT);
digitalWrite(pinSTBY, 1);
Timer1.initialize(10000);
Timer1.attachInterrupt(dotocdo);
}
void loop()
{
if (Serial.available())
{
receive= Serial.parseFloat();
ref_speed=receive;
Serial.println(receive);
}
xung=encoder.read();
}
And here is the Python code on Raspberry:
import time
import socket
import sys
import serial
import struct
UNO_1 = serial.Serial('/dev/ttyUSB0', 115200)
while (1):
n=float(25)
UNO_1.write(bytes(b'%f'%n))
receive=UNO_1.readline()
print(receive)
This is the error (Arduino receives nothing):
Does anyone know how to fix this problem?
Has any communication worked before?
Double-check your connections (swapped TX and RX, forgot GND)
Try using a serial terminal (I think pyserial has a demo included) to send data manually.
Your Python script may just be timing out.
Your Python script might be sending too many zeroes or control characters that Serial.parseFloat() does not like (it stops if it does not like something).
Alternativley, just get started with echo programs that don't actually try to parse numbers to see if any data comes through: try this.

How to read pot connected to arduino from Rpi using python and i2c

I'm trying to write analog readings from a potentiometer connected to an Arduino and read those values using I2C from python on an RPi. I have gotten Arduino to Arduino to work using the code below. What I cannot seem to do correctly is write two bytes from the Arduino and read two bytes from the RPi.
Arduino Master code:
#include <Wire.h>
#define SLAVE_ADDRESS 0x2a
void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(9600); // start serial for output
}
void loop()
{
Wire.requestFrom(SLAVE_ADDRESS, 2); // request 2 bytes from slave
byte loByte;
byte hiByte;
if(Wire.available() >= 2) // slave may send less than requested
{
hiByte = Wire.read();
loByte = Wire.read();
}
int val = (hiByte << 8) + loByte;
Serial.print("read value:");
Serial.println(val);
delay(500);
}
Arduino Slave code:
#include <Wire.h>
#include <stdlib.h>
#define SLAVE_ADDRESS 0x2a
//#define potPin 0
int readVal;
byte hi;
byte lo;
void setup()
{
// Communication I2C
Wire.begin(SLAVE_ADDRESS);
Wire.onRequest(requestEvent); // register event
Serial.begin(9600);
}
void loop()
{
readVal = analogRead(A2);
Serial.println(readVal);
hi = highByte(readVal);
lo = lowByte(readVal);
}
void requestEvent()
{
byte buf [2];
buf [0] = hi;
buf [1] = lo;
Wire.write(buf, sizeof buf); // send 2-byte response
}
The closest I have gotten reading from an RPi is:
RPi Master code:
import smbus
import time
bus = smbus.SMBus(1)
address = 0x2a
while True:
bus.write_byte(address, 1)
number = bus.read_byte(address)
print(number)
time.sleep(1)
Arduino slave code:
#include <Wire.h>
#define SLAVE_ADDRESS 0x2a
int number = 0;
void setup() {
Wire.begin(SLAVE_ADDRESS);
Wire.onReceive(receiveData);
Wire.onRequest(sendData);
}
void loop() {
}
void receiveData(int byteCount){
while(Wire.available()) {
number = Wire.read();
number = analogRead(A2);
}
}
void sendData(){
Wire.write(number);
}
I seem to be able to get 0-255, but after 255 the value starts again. No doubt there is a more precise way to say I am only getting one byte of data or something along those lines. Ultimately I want to have 2 pots connected to the Arduino feeding readings into the RPi.
On Arduino, analogRead returns an int value in the range 0-1023. On this hardware, an int is two bytes.
However, the form of Wire.write that you use in the sendData function only writes a single byte, discarding part of the integer.
There are basically two solutions.
The simplest would be to take the return value of analogRead, divide it by 4 and cast it into a byte. Send that out with Wire.write. This does reduce the resolution of the value of the pot-meter, but is it a very simple solution.
The other was is to send an integer value over the wire. Since you're reading bytes on the RPi, you cannot know if you are reading the first or second byte of an integer. So you would probably have to use a signal to indicate the start of a two-byte sequence. You would also have to take the endian-ness of both platform into account. All in all, this is much more complicated.
Thanks for the feedback. It helped me think through this a bit more and do more digging. This is what I have working.
Arduino side for writing:
#include <Wire.h>
#define SLAVE_ADDRESS 0x2a
#define pot1pin A2
#define pot2pin A3
byte pot1byte;
byte pot2byte;
void setup()
{
Wire.begin(SLAVE_ADDRESS);
Wire.onRequest(requestEvent);
}
void loop() {
int pot1int = analogRead(pot1pin);
int pot2int = analogRead(pot2pin);
pot1byte = map(pot1int, 0, 1024, 0, 255);
pot2byte = map(pot2int, 0, 1024, 0, 255);
}
void requestEvent()
{
Wire.write(pot1byte);
delay(30);
Wire.write(pot2byte);
}
RPi side for reading:
import smbus
bus = smbus.SMBus(1)
address = 0x2a
while (1):
block = bus.read_i2c_block_data(address, 0, 2) # Returned value is a list of 2 bytes
print(block)
As you can see I am reading 2 pots, converting the output to 0-255, writing to the I2C bus and then reading the 2 bytes on the RPi side. I did have to change the Arduino delay value during testing because I was getting the error "IOError: [Errno 5] Input/output error" after a few minutes. Now maybe I will go back and write 2 bytes per pot and read 4 bytes so I don't lose and resolution.

Talking SMBus between RaspberryPi and ATMEGA 324PA - AVR not clock stretching

I'm trying to get an ATMEGA 324PA to run as an SMBus slave.
I'm using the following code on the Pi:
import smbus as smbus
i2c = smbus.SMBus(1)
i2c_addr = 0x30
result = i2c.read_block_data( i2c_addr, reg )
On the AVR, I'm using:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include "smb_slave.h"
#define SMB_COMMAND_RETURN_VENDOR_STRING 0x10
int main(void)
{
// Set data direction of PORTB as output and turn off LEDs.
DDRA = 0xff;
PORTA = 0xff;
// Initialize SMBus
SMBusInit();
SMBEnable();
// Enable interrupts globally
sei();
for (;;)
{
}
return 0;
}
void ProcessReceiveByte(SMBData *smb)
{
smb->txBuffer[0] = ~PIND;
smb->txLength = 1;
}
static void ReturnVendorString(SMBData *smb)
{
unsigned char *vendor = (unsigned char*) "Vendor\0";
unsigned char i;
unsigned char temp;
i = 0;
// Copy vendor ID string from EEPROM.
while ((temp = vendor[i]) != '\0')
{
i++;
smb->txBuffer[i] = temp;
}
smb->txBuffer[0] = i; // Byte count.
smb->txLength = i + 1; // Number of bytes to be transmitted including byte count.
smb->state = SMB_STATE_WRITE_READ_REQUESTED;
PORTA ^= 0x40; // debug
}
static void UndefinedCommand(SMBData *smb)
{
// Handle undefined requests here.
smb->error = TRUE;
smb->state = SMB_STATE_IDLE;
}
void ProcessMessage(SMBData *smb)
{
if (smb->state == SMB_STATE_WRITE_REQUESTED)
{
switch (smb->rxBuffer[0]) // Command code.
{
case SMB_COMMAND_RETURN_VENDOR_STRING: // Block read, vendor ID.
ReturnVendorString(smb);
break;
default:
UndefinedCommand(smb);
break;
}
}
else
{
smb->state = SMB_STATE_IDLE;
}
}
With a (gcc-adapted) version of: http://www.atmel.com/images/AVR316.zip from http://www.atmel.com/devices/ATMEGA324A.aspx?tab=documents
Something's partially working, as my logic analyser shows:
But I assume I'm doing something wrong as the AVR is not ACK'ing the READ, nor clock-stretching nor sending a response.
Where should I look next?
Can I have confidence in the Python smbus module on the RasPi?
Could what I'm seeing be related to https://github.com/raspberrypi/linux/issues/254 ?
The issue you linked is the problem -- i2c clock stretching is simply broken on the Raspberry Pi. More info: http://www.advamation.com/knowhow/raspberrypi/rpi-i2c-bug.html
If a sensor has alternative output such as UART sometimes that's an option but for some projects I've had to use a micro or Beaglebone or some other thing.
I tried using SMBus from a Beaglebone instead (replacing the Raspberry Pi).
This worked perfectly, after I added some 10K pull-up resistors to the i2c bus. (The Raspberry Pi has internal pull-ups on the i2c pins.)

Categories