I'm trying to write data from python to serial with this sketch
import serial
import smtplib
import time
s=serial.Serial('/dev/tty.usbserial-AH01LLHS',9600)
precx=500
ist=30
i=0
while True:
s.write('1')
stringa=s.readline()
array=stringa.split(',')
x=int(array[0])
y=int(array[1])
z=int(array[2])
print(x,y,z)
if(precx!=500):
diffx=abs(x-precx)
diffy=abs(y-precy)
diffz=abs(z-precz)
if((diffx>ist)|(diffy>ist)|(diffz>ist)):
print('Ohu god',i)
i+=1
#time.sleep(2)
precx=x
precy=y
precz=z
But when I execute the program I see nothing on the console, and the Arduino Rx led is off.
This is my Arduino sketch (nano atmega 328):
//Add the SPI library so we can communicate with the ADXL345 sensor
#include <SPI.h>
//Assign the Chip Select signal to pin 10.
int CS=10;
//This is a list of some of the registers available on the ADXL345.
//To learn more about these and the rest of the registers on the ADXL345, read the datasheet!
char POWER_CTL = 0x2D; //Power Control Register
char DATA_FORMAT = 0x31;
char DATAX0 = 0x32; //X-Axis Data 0
char DATAX1 = 0x33; //X-Axis Data 1
char DATAY0 = 0x34; //Y-Axis Data 0
char DATAY1 = 0x35; //Y-Axis Data 1
char DATAZ0 = 0x36; //Z-Axis Data 0
char DATAZ1 = 0x37; //Z-Axis Data 1
//This buffer will hold values read from the ADXL345 registers.
char values[10];
//These variables will be used to hold the x,y and z axis accelerometer values.
int x,y,z;
boolean snd;
void setup(){
//Initiate an SPI communication instance.
SPI.begin();
//Configure the SPI connection for the ADXL345.
SPI.setDataMode(SPI_MODE3);
//Create a serial connection to display the data on the terminal.
Serial.begin(9600);
//Set up the Chip Select pin to be an output from the Arduino.
pinMode(CS, OUTPUT);
//Before communication starts, the Chip Select pin needs to be set high.
digitalWrite(CS, HIGH);
//Put the ADXL345 into +/- 4G range by writing the value 0x01 to the DATA_FORMAT register.
writeRegister(DATA_FORMAT, 0x01);
//Put the ADXL345 into Measurement Mode by writing 0x08 to the POWER_CTL register.
writeRegister(POWER_CTL, 0x08); //Measurement mode
}
void loop(){
//snd=true;
//Reading 6 bytes of data starting at register DATAX0 will retrieve the x,y and z acceleration values from the ADXL345.
//The results of the read operation will get stored to the values[] buffer.
readRegister(DATAX0, 6, values);
//The ADXL345 gives 10-bit acceleration values, but they are stored as bytes (8-bits). To get the full value, two bytes must be combined for each axis.
//The X value is stored in values[0] and values[1].
x = ((int)values[1]<<8)|(int)values[0];
//The Y value is stored in values[2] and values[3].
y = ((int)values[3]<<8)|(int)values[2];
//The Z value is stored in values[4] and values[5].
z = ((int)values[5]<<8)|(int)values[4];
if (Serial.available() > 0) {
if(Serial.read()=='1'){
snd=true;
}
else{
snd=false;
}
}
if(snd){
//Print the results to the terminal.
Serial.print(x, DEC);
Serial.print(',');
Serial.print(y, DEC);
Serial.print(',');
Serial.print(z, DEC);
Serial.println("");
delay(10);
}
}
//This function will write a value to a register on the ADXL345.
//Parameters:
// char registerAddress - The register to write a value to
// char value - The value to be written to the specified register.
void writeRegister(char registerAddress, char value){
//Set Chip Select pin low to signal the beginning of an SPI packet.
digitalWrite(CS, LOW);
//Transfer the register address over SPI.
SPI.transfer(registerAddress);
//Transfer the desired register value over SPI.
SPI.transfer(value);
//Set the Chip Select pin high to signal the end of an SPI packet.
digitalWrite(CS, HIGH);
}
//This function will read a certain number of registers starting from a specified address and store their values in a buffer.
//Parameters:
// char registerAddress - The register addresse to start the read sequence from.
// int numBytes - The number of registers that should be read.
// char * values - A pointer to a buffer where the results of the operation should be stored.
void readRegister(char registerAddress, int numBytes, char * values){
//Since we're performing a read operation, the most significant bit of the register address should be set.
char address = 0x80 | registerAddress;
//If we're doing a multi-byte read, bit 6 needs to be set as well.
if(numBytes > 1)address = address | 0x40;
//Set the Chip select pin low to start an SPI packet.
digitalWrite(CS, LOW);
//Transfer the starting register address that needs to be read.
SPI.transfer(address);
//Continue to read registers until we've read the number specified, storing the results to the input buffer.
for(int i=0; i<numBytes; i++){
values[i] = SPI.transfer(0x00);
}
//Set the Chips Select pin high to end the SPI packet.
digitalWrite(CS, HIGH);
}
Thanks in advance.
You should definitely check the suggestions from the comments:
make the program simpler so that it always sends values without "flow control" (using the "1" byte you send),
use a serial monitor to check the output.
First, you shall check if you add a s.flush() before and after your s.write('1') helps. Then you may want to add flush() in your arduino code too.
To me it really looks like a starving issue at the initialization of your "flow control" algorithm. On the paper it looks good, but in real life, it may not. Very often, the Arduino sends a lot of garbage when it starts filling up the host serial port's buffer. And the other way around may be true. So instead of having a 1 on the arduino side, you may get a !##$##%##%!##$ that's totally useless.
So on either side, before getting in the loops, you should add an init protocol. The arduino sends READY, the host sends READY, you flush out everything until you get READY on both sides. Something that would look like:
void setup() {
Serial.begin(9600);
Serial.println('READY');
Serial.flush();
char ch1 = 0, ch2 = 0;
char incomingByte = 0;
while (ch1 != 'O' && ch2 != 'K') {
ch1 = Serial.read();
if (ch1 == 'O' && ch2 == 'K')
break;
ch2 = Serial.read();
}
}
and on the python side:
with serial.Serial('/dev/tty.usbserial-AH01LLHS',9600) as s:
s.flush()
ready = ""
while ready != "READY":
ready = s.readline()
s.flush()
while True:
# ... you stuff
of course that's only an idea of what you may do. You can make it more sophisticated, or way more simple. But before making such flow control, you really need to create a meeting point.
Related
I need to read multiple (at least 2) serial ports (currently two ports on a FT2232H module connected through USB).
I am using it to monitor a serial connections, so the two ports have their RX connected in parallel to RX and TX of the serial I need to monitor.
Setup is very similar to this.
I am setting up ports like this:
#define waitTime 0
int start_dev(const int speed, const char *dev) {
int fd = open(dev, O_RDWR | O_NOCTTY |O_NONBLOCK| O_NDELAY);
int isBlockingMode, parity = 0;
struct termios tty;
isBlockingMode = 0;
if (waitTime < 0 || waitTime > 255)
isBlockingMode = 1;
memset (&tty, 0, sizeof tty);
if (tcgetattr (fd, &tty) != 0) {
/* save current serial port settings */
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
exit(1);
}
cfsetospeed (&tty, speed);
cfsetispeed (&tty, speed);
tty.c_cflag = (tty.c_cflag & ~CSIZE) | CS8; // 8-bit chars
// disable IGNBRK for mismatched speed tests; otherwise receive break
// as \000 chars
tty.c_iflag &= ~IGNBRK; // disable break processing
tty.c_lflag = 0; // no signaling chars, no echo,
// no canonical processing
tty.c_oflag = 0; // no remapping, no delays
tty.c_cc[VMIN] = (1 == isBlockingMode) ? 1 : 0; // read doesn't block
tty.c_cc[VTIME] = (1 == isBlockingMode) ? 0 : waitTime; // in unit of 100 milli-sec for set timeout value
tty.c_iflag &= ~(IXON | IXOFF | IXANY); // shut off xon/xoff ctrl
tty.c_cflag |= (CLOCAL | CREAD); // ignore modem controls,
// enable reading
tty.c_cflag &= ~(PARENB | PARODD); // shut off parity
tty.c_cflag |= parity;
tty.c_cflag &= ~CSTOPB;
tty.c_cflag &= ~CRTSCTS;
if (tcsetattr (fd, TCSANOW, &tty) != 0) {
printf("__LINE__ = %d, error %s\n", __LINE__, strerror(errno));
exit(1);
}
return fd;
}
... and currently I have this code for reading (I also tried with select()):
...
for (running=1; running;) {
for (int*p=devs; p<end; p++) {
char b[256];
int n = read(*p, b, sizeof(b));
if (n > 0) {
for (int i=0; i<n; i++) {
...
}
}
}
}
...
This is obviously highly suboptimal because it doesn't suspend waiting for chars.
Problem is I experience some kind of buffering because when two processes exchange data on a tight loop I often see a few requests together and then the corresponding answers (1b6f is request and 19 is the empty answer):
1b6f
19
1b6f
19
1b6f
19
1b6f
191919
1b6f1b6f1b6f
19191919
1b6f1b6f1b6f1b6f
1b6f1b6f1b6f
191919
I also tried using python (pyserial), but I get similar results.
How should I proceed to ensure correct timings are enforced?
Note: I am not very interested in precise timing, but sequence should be preserved (i.e.: I would like to avoid seeing an answer before the request).
In my opinion what you're trying to do, which is if I understood correctly a kind of port sniffer to identify the transactions exchanged on a serial link is not feasible with USB-to-serial converters and a conventional OS, unless you're running at slow baudrates.
The USB port will always introduce a certain latency (probably tens of milliseconds), and you'll have to put the unpredictability of the OS on top of that.
Since you have two ports you could try to run two separate threads and timestamp each chunk of data received. That might help improve things but I'm not sure it will allow you to clearly follow the sequence.
If you had real (legacy) serial ports, and a not very loaded OS maybe you could do it somehow.
But if what you want is a serial port sniffer on the cheap you can try something like this solution. If you do forwarding on your ports you'll know what is coming from where at all times. Of course, you need to have access to either side of the communication.
If you don't have that luxury, I guess it would be quite easy to get what you want with almost any kind of microcontroller.
EDIT: Another idea could be to use a dual serial port to USB converter. Since both ports are served by the same chip, somehow I think it's likely that you can follow the sequence with one of those. I have access to this one if you post a full working snippet of your code I can test it next week, if you're curious to know.
The two serial ports will have buffering - the ordering of arrival of individual characters cannot be determined at the application level. That would require writing your own driver or reducing any buffering to 1 character perhaps - at the risk of overrun.
Even then it could only work if you had a real UART and direct control of it and it had no hardware FIFO. With a Virtual UART implemented as a USB CDC/ACM class driver it is not possible in any case because the real-time UART transactions are lost in the master-slave USB transfers which are entirely different to the way a true UART works. Besides that the FT2232H has internal buffering over which you have no control.
In short, you cannot get real-time sequencing of individual characters on two separate ports in your implementation due to multiple factors, most of which cannot be mitigated.
You have to understand that the FT2232 has two real UARTS and USB device interface presenting as two CDC/ACM devices. It has firmware that buffers and exchanges data between the UART and the USB, and USB exchanges are polled for by the host - in its own sweet time, rate and order. The data is transferrred asynchronoulsy in packets rather than individual characters and recovery of the original time of arrival of any individual character is not possible. All you know is the order of arrival of characters on a single port - you cannot determine the order of arrival between ports. And all that is even before the data is buffered by the host OS device driver.
A hardware solution is probably required, using a microcontroller that, working at the UART level will timestamp and log the arrival of each character on each of two ports, then transfer the timestamped log data to your host (perhaps via USB) where you can then reconstruct the order of arrival from the timestamps.
I am setting up ports like this:
...
This is obviously highly suboptimal because it doesn't suspend waiting for chars.
In spite of this awareness you use and post this code?
I suspect that this "suboptimal" code that polls the system for data while wasting CPU cycles and consumes the process's time slice is part of the problem. You have not posted a complete and minimal example of the problem, and I have only been able to partially replicate the issue.
On a SBC that has two USARTs, I have a program that is generating "request" and "response" data on the serial ports. The generation program is:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int set_interface_attribs(int fd, int speed)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
tty.c_cc[VMIN] = 1;
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
int main(void)
{
char *masterport = "/dev/ttyS0";
char *slaveport = "/dev/ttyS2";
int mfd;
int sfd;
int wlen;
/* open request generator */
mfd = open(masterport, O_RDWR | O_NOCTTY | O_SYNC);
if (mfd < 0) {
printf("Error opening %s: %s\n", masterport, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(mfd, B115200);
/* open response generator */
sfd = open(slaveport, O_RDWR | O_NOCTTY | O_SYNC);
if (sfd < 0) {
printf("Error opening %s: %s\n", slaveport, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(sfd, B115200);
/* simple output loop */
do {
wlen = write(mfd, "ABCD", 4);
if (wlen != 4) {
printf("Error from write cmd: %d, %d\n", wlen, errno);
}
tcdrain(mfd); /* delay for output */
wlen = write(sfd, "xy", 2);
if (wlen != 2) {
printf("Error from write resp: %d, %d\n", wlen, errno);
}
tcdrain(sfd); /* delay for output */
} while (1);
}
Problem is I experience some kind of buffering because when two processes exchange data on a tight loop I often see a few requests together and then the corresponding answers
You do not clarify what you call a "tight loop", but the above program will generate the "response" 30 milliseconds after a "request" (as measured by a two-channel oscilloscope).
BTW the serial terminal interface is highly layered. Even without the overhead of the external bus used by USB, there is at least the termios buffer and the tty flip buffer, as well as a DMA buffer. See Linux serial drivers
Each USART of the SBC is connected to a FTDI USB-to-RS232 converter (which are part of an old quad-port converter). Note that the USB port speed is only USB 1.1. The host PC for the serial capture is 10-year old hardware running an old Ubuntu distro.
An attempt to replicate your results produced:
ABCD
x
y
A
BCD
xy
ABCD
xy
ABCD
xy
A
BCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABC
D
xy
ABCD
xy
ABCD
xy
ABC
D
xy
ABCD
xy
ABCD
xy
ABC
D
xy
ABCD
xy
ABCD
xy
ABC
D
xy
ABCD
xy
ABCD
xy
ABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCDABCD
xyxyxyxyxyxyxyxyxyxyxyxyxy
ABCD
xy
ABCD
xy
AB
CD
xy
ABCD
xy
ABCD
xy
AB
CD
xy
ABCD
xy
ABCD
x
y
A
BCD
xy
ABCD
xy
ABCD
x
y
AB
CD
xy
ABCD
xy
ABCD
x
y
Only once (about 1.5 seconds after the capture program is started) is there a multi-write capture. (There's even a noticeable pause in output before this happens.) Otherwise every read/capture is of a partial or single/complete request/response.
Using a capture program that uses blocking I/O, the results are consistenly "perfect" for a 4-byte request message and 2-byte response message.
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
Tweaking the program by changing the VMIN=4 for requests and VMIN=2 for responses to VMIN=1 for everything, changes the quality of the captures slightly:
ABCD
xy
ABCD
x
ABCD
y
ABCD
xy
ABC
xy
D
x
ABCD
y
ABCD
xy
ABCD
xy
ABCD
xy
ABCD
xy
ABC
xy
D
x
ABCD
y
Although partial captures occur, there are never any multiple "messages" per read. The output is smooth and consistent, without any pause as with the nonblocking program.
The capture program that uses blocking reads is:
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
int set_interface_attribs(int fd, int speed, int rlen)
{
struct termios tty;
if (tcgetattr(fd, &tty) < 0) {
printf("Error from tcgetattr: %s\n", strerror(errno));
return -1;
}
cfsetospeed(&tty, (speed_t)speed);
cfsetispeed(&tty, (speed_t)speed);
tty.c_cflag |= (CLOCAL | CREAD); /* ignore modem controls */
tty.c_cflag &= ~CSIZE;
tty.c_cflag |= CS8; /* 8-bit characters */
tty.c_cflag &= ~PARENB; /* no parity bit */
tty.c_cflag &= ~CSTOPB; /* only need 1 stop bit */
tty.c_cflag &= ~CRTSCTS; /* no hardware flowcontrol */
/* setup for non-canonical mode */
tty.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL | IXON);
tty.c_lflag &= ~(ECHO | ECHONL | ICANON | ISIG | IEXTEN);
tty.c_oflag &= ~OPOST;
/* fetch bytes as they become available */
tty.c_cc[VMIN] = rlen;
tty.c_cc[VTIME] = 1;
if (tcsetattr(fd, TCSANOW, &tty) != 0) {
printf("Error from tcsetattr: %s\n", strerror(errno));
return -1;
}
return 0;
}
int main(void)
{
char *masterport = "/dev/ttyUSB2";
char *slaveport = "/dev/ttyUSB3";
int mfd;
int sfd;
/* open request reader */
mfd = open(masterport, O_RDWR | O_NOCTTY | O_SYNC);
if (mfd < 0) {
printf("Error opening %s: %s\n", masterport, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(mfd, B115200, 4);
/* open response reader */
sfd = open(slaveport, O_RDWR | O_NOCTTY | O_SYNC);
if (sfd < 0) {
printf("Error opening %s: %s\n", slaveport, strerror(errno));
return -1;
}
/*baudrate 115200, 8 bits, no parity, 1 stop bit */
set_interface_attribs(sfd, B115200, 2);
tcflush(mfd, TCIOFLUSH);
tcflush(sfd, TCIOFLUSH);
/* simple noncanonical input loop */
do {
unsigned char buffer[80];
int rdlen;
rdlen = read(mfd, buffer, sizeof(buffer) - 1);
if (rdlen > 0) {
buffer[rdlen] = 0;
printf("%s\n", buffer);
} else if (rdlen < 0) {
printf("Error from read: %d: %s\n", rdlen, strerror(errno));
} else { /* rdlen == 0 */
printf("Timeout from read\n");
}
rdlen = read(sfd, buffer, sizeof(buffer) - 1);
if (rdlen > 0) {
buffer[rdlen] = 0;
printf("%s\n", buffer);
} else if (rdlen < 0) {
printf("Error from read: %d: %s\n", rdlen, strerror(errno));
} else { /* rdlen == 0 */
printf("Timeout from read\n");
}
} while (1);
}
This is essentially a dual half-duplex capture on each serial terminal for a request-response dialog. An actual full-duplex dialog cannot be accurately captured/displayed.
These results using blocking reads would seem to contradict the other answers that USB-serial converters would buffer and packetize the serial data into unrecognizable byte segments.
Only when I use nonblocking reads do I encounter the "buffering" that you report.
You are making bad use of the VMIN and VTIME c_cc cells. If you read carefully the termios(3) manual page, on a basis of VMIN > 0 && VTIME > 0, the driver will not send the data to the application until a timeout of the VTIME duration is detected. In this case the VTIME parameter is an intercharacter timeout (but it blocks until it receives the first char). I think you misinterpret that case. This was introduced in the driver to handle variable length packet input devices, like mice or network, that can deliver several packets in sequence, to ensure that the buffer will be in synch with the starting of a packet (while handling packet loss). But the operation in that mode is to wait indefinitely for the first char, and then wait up to VTIME tenths of a second to see if another char is received, once the VMIN count is reached, in that case, the driver buffers the char and waits for another timeout. This is made for packets with variable length, and a header, you normally set VMIN as the size of the header, then use an intercharacter timeout to handle lost characters after some timeout. This is not what you tell in your question.
To create a scenario in which you read multiple ports and receive individual chars as soon as you get them, you have to use VMIN == 1, VTIME == 0 so you will get each character as soon as it is received. And to receive the first one you get, independently of which port you receive it from, you need to use select(2) system call, which will block you until some input is available on one of several ports, then look at which port it is, and then do a read(2) of that port. If you want fine timestamps, do a clock_gettime(2) as soon as you return from the select(2) system call (you have not yet read(2) the char, but you know then that it is there, later, once you read it, you can associate the timestamp to the right character and port.
As I see in your question, you have already fought with termios(3) and you have an idea of what you want, read select(2) man page and prepare code to handle with that. If you run in trouble, drop me a comment below, so I'll write some code for you. Remember: VMIN is the minimum number of chars you want to receive, never the maximum (the maximum you put it in the parameter to read(2)), and VTIME is only an absolute timeout, when VMIN == 0 (but you can handle timeouts in select(2), better than in the driver)
This kind of mistake is common, I've passed through it also :)
EDIT
I have developed a simple example to monitor several tty lines (not necessarily two) with the approach indicated here. Just to say that it allows a raspberry pi 2B+ to be used as a serial protocol analyzer, by reading character by character and using the best time granularity approach.
My classmate and I have been working on this project based on this Instructables article https://www.instructables.com/id/Building-a-Simple-Pendulum-and-Measuring-Motion-Wi/, our idea is to make a pendulum, calculate the g force (from the pendulum's period) and then show its value on a LCD we got connected to the Arduino. We got the code up and running (it calculates the period), and we understood that the Arduino has to do some type of conversion (utf-8) to pass the values it gets from the potentiometer to Python. However when we try to send the value we get from calculating the period of the graph back to the arduino and show it on the LCD, it shows 634 or other similiar values, we tried to instead of the decode it does initially, go the other way around with encode, but it won't work. We can't check the value it is getting from the serial, because the serial monitor simply doesn't open while the python script is running. What is the most pratical way we can use to "transfer" floats calculated in a Python script to the Arduino, so that we can calculate g and show it on the screen. Many forums advice to instead of transferring the floats, convert them to strings since it would be easy for the arduino to receive, but we aren't sure that would even work. I'm sure this is a simple question, but we just can't seem to get it. If you find anything else wrong with the code please let me know, we know it's a bit sketchy. Thanks.
Python code:
arduino = serial.Serial('COM3', 115200, timeout=.1) #Open connection to Arduino
samples = 200 #We will take this many readings
angle_data = np.zeros(samples) #Creates a vector for our angle data
time_data = np.zeros(samples) #Creates a vector of same length for time
i = 0;
calibrate = 123 #Value to zero potentiometer reading when pendulum is motionless, read from Arduino
while i!=samples:
data = arduino.readline()[0:-2].decode('utf-8')
if data:
angle_data[i] = (float(data) - calibrate)*math.pi/180
time_data[i] = time.perf_counter()
print(angle_data[i])
i = i + 1
min = np.min(angle_data)
print (min)
min_pos, = np.where(angle_data == min)
min_x = time_data[min_pos]
print (min_x)
nos_left = int(min_pos)
max = 0;
for i in range(nos_left,200):
if angle_data[i] > max: max = angle_data[i]
print (max)
max_pos, = np.where(angle_data == max)
max_x = time_data[max_pos]
print (max_x)
period = (max_x - min_x) * 2
print (period)
gforce = (0.165 * 4 * (math.pi) * (math.pi)) / ((period) * (period))
print (gforce)
value_g = arduino.write(gforce)
plt.plot(time_data,angle_data,'ro')
plt.axis([0,time_data[samples-1],-math.pi,math.pi])
plt.xlabel("Time (seconds)")
plt.ylabel("Angle (Radians)")
plt.title("Pendulum Motion - Measured with Arduino and potentiometer")
plt.show()
arduino.close()
Arduino code
const int rs = 12, en = 11, d4 = 5, d5 = 4, d6 = 3, d7 = 2;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
int period = 0;
void setup() {
lcd.begin(16, 2);
Serial.begin(115200); // use the same baud-rate as the python side
pinMode(A0,INPUT);
lcd.print(" Pendulo ");
int gforce = 0;
}
void loop() {
// set the cursor to column 0, line 1
// (note: line 1 is the second row, since counting begins with 0):
// print the number of seconds since reset:
int degrees;
degrees = getDegree();
Serial.println(degrees);
Serial.println("\n");
delay(50);
if (Serial.available() > 0) {
// read the incoming byte:
gforce = Serial.read();
Serial.print("I received: ");
Serial.println(gforce, DEC);
}
lcd.setCursor(0, 1);
lcd.print(gforce);
}
int getDegree()
{
int sensor_value = analogRead(A0);
float voltage;
voltage = (float)sensor_value*5/1023;
float degrees = (voltage*300)/5;
return degrees;
}
This appears to be a good case for the Arduino Serial's parseFloat() method:
if (Serial.available() > 0) {
/* instead of Serial.read(), use: */
gforce = Serial.parseFloat();
Serial.print("I received: ");
Serial.println(gforce, DEC);
}
Essentially, it pulls out anything that looks like a float within the received serial data, even if it's mixed with other non-numerical characters.
It also works with Software Serial.
I'm trying to send messages through the serial USB interface of my Arduino (C++) to a Raspberry Pi (Python).
On the Arduino side I define a struct which I then copy into a char[]. The last part of the struct contains a checksum that I want to calculate using CRC32. I copy the struct into a temporary char array -4 bytes to strip the checksum field. The checksum is then calculated using the temporary array and the result is added to the struct. The struct is then copied into byteMsg which gets send over the serial connection.
On the raspberry end I do the reverse, I receive the bytestring and calculate the checksum over the message - 4 bytes. Then unpack the bytestring and compare the received and calculated checksum but this fails unfortunately.
For debugging I compared the crc32 check on both the python and arduino for the string "Hello World" and they generated the same checksum so doesn't seem to be a problem with the library. The raspberry is also able to decode the rest of the message just fine so the unpacking of the data into variables seem to be ok as well.
Any help would be much appreciated.
The Python Code:
def unpackMessage(self, message):
""" Processes a received byte string from the arduino """
# Unpack the received message into struct
(messageID, acknowledgeID, module, commandType,
data, recvChecksum) = struct.unpack('<LLBBLL', message)
# Calculate the checksum of the recv message minus the last 4
# bytes that contain the sent checksum
calcChecksum = crc32(message[:-4])
if recvChecksum == calcChecksum:
print "Checksum checks out"
The Aruino crc32 library taken from http://excamera.com/sphinx/article-crc.html
crc32.h
#include <avr/pgmspace.h>
static PROGMEM prog_uint32_t crc_table[16] = {
0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
};
unsigned long crc_update(unsigned long crc, byte data)
{
byte tbl_idx;
tbl_idx = crc ^ (data >> (0 * 4));
crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f)) ^ (crc >> 4);
tbl_idx = crc ^ (data >> (1 * 4));
crc = pgm_read_dword_near(crc_table + (tbl_idx & 0x0f)) ^ (crc >> 4);
return crc;
}
unsigned long crc_string(char *s)
{
unsigned long crc = ~0L;
while (*s)
crc = crc_update(crc, *s++);
crc = ~crc;
return crc;
}
Main Arduino Sketch
struct message_t {
unsigned long messageID;
unsigned long acknowledgeID;
byte module;
byte commandType;
unsigned long data;
unsigned long checksum;
};
void sendMessage(message_t &msg)
{
// Set the messageID
msg.messageID = 10;
msg.checksum = 0;
// Copy the message minus the checksum into a char*
// Then perform the checksum on the message and copy
// the full msg into byteMsg
char byteMsgForCrc32[sizeof(msg)-4];
memcpy(byteMsgForCrc32, &msg, sizeof(msg)-4);
msg.checksum = crc_string(byteMsgForCrc32);
char byteMsg[sizeof(msg)];
memcpy(byteMsg, &msg, sizeof(msg));
Serial.write(byteMsg, sizeof(byteMsg));
void loop() {
message_t msg;
msg.module = 0x31;
msg.commandType = 0x64;
msg.acknowledgeID = 0;
msg.data = 10;
sendMessage(msg);
Kind Regards,
Thiezn
You are making the classic struct-to-network/serial/insert communication layer mistake. Structs have hidden padding in order to align the members onto suitable memory boundaries. This is not guaranteed to be the same across different computers, let alone different CPUs/microcontrollers.
Take this struct as an example:
struct Byte_Int
{
int x;
char y;
int z;
}
Now on a basic 32-bit x86 CPU you have a 4-byte memory boundary. Meaning that variables are aligned to either 4 bytes, 2 bytes or not at all according to the type of variable. The example would look like this in memory: int x on bytes 0,1,2,3, char y on byte 4, int z on bytes 8,9,10,11. Why not use the three bytes on the second line? Because then the memory controller would have to do two fetches to get a single number! A controller can only read one line at a time. So, structs (and all other kinds of data) have hidden padding in order to get variables aligned in memory. The example struct would have a sizeof() of 12, and not 9!
Now, how does that relate to your problem? You are memcpy()ing a struct directly into a buffer, including the padding. The computer on the other end doesn't know about this padding and misinterprets the data. What you need a serialization function that takes the members of your structs and pasts them into a buffer one at a time, that way you lose the padding and end up with something like this:
[0,1,2,3: int x][4: char y][5,6,7,8: int z]. All as one lengthy bytearray/string which can be safely sent using Serial(). Of course on the other end you would have to parse this string into intelligible data. Python's unpack() does this for you as long as you give the right format string.
Lastly, an int on an Arduino is 16 bits long. On a pc generally 4! So assemble your unpack format string with care.
The char array I was passing to the crc_string function contained '\0' characters. The crc_string was iterating through the array until it found a '\0' which shouldn't happen in this case since I was using the char array as a stream of bytes to be sent over a serial connection.
I've changed the crc_string function to take the array size as argument and iterate through the array using that value. This solved the issue.
Here's the new function
unsigned long crc_string(char *s, size_t arraySize)
{
unsigned long crc = ~0L;
for (int i=0; i < arraySize; i++) {
crc = crc_update(crc, s[i]);
}
crc = ~crc;
return crc;
}
This is the code I am currently using to send and receive int values from a RaspberryPi to an Arduino using i2C. It works fine for values 0-255, but because of the 1 byte limit, anything larger fails.
To circumvent this, I'd like to send and receive string values instead, and then convert back to int if necessary.
What changes would I need to make in the following?
Here is my RPi Python code
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:
try:
var = int(raw_input("Enter 1 - 9: "))
except ValueError:
print "Could you at least give me an actual number?"
continue
writeNumber(var)
print "RPI: Hi Arduino, I sent you ", var
# sleep one second
#time.sleep(1)
number = readNumber()
print "Arduino: Hey RPI, I received a digit ", number
print
And here is my Arduino code
#include <Wire.h>
#define SLAVE_ADDRESS 0x04
int number = 0;
int state = 0;
void setup() {
pinMode(13, 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();
if (Wire.available() > 1) // at least 2 bytes
{
number = Wire.read() * 256 + Wire.read();
}
Serial.print("data received: ");
Serial.println(number);
//sendData();
if (number == 1){
if (state == 0){
digitalWrite(13, HIGH); // set the LED on
state = 1;
}
else{
digitalWrite(13, LOW); // set the LED off
state = 0;
}
}
}
}
// callback for sending data
void sendData(){
Wire.write(number);
}
This problem essentially has two parts: splitting an integer into its bytes and reassembling an integer from bytes. These parts must be replicated on both the Pi and Arduino. I'll address the Pi side first, in Python:
Splitting an integer:
def writeNumber(value):
# assuming we have an arbitrary size integer passed in value
for character in str(val): # convert into a string and iterate over it
bus.write_byte(address, ord(character)) # send each char's ASCII encoding
return -1
Reassembling an integer from bytes:
def readNumber():
# I'm not familiar with the SMbus library, so you'll have to figure out how to
# tell if any more bytes are available and when a transmission of integer bytes
# is complete. For now, I'll use the boolean variable "bytes_available" to mean
# "we are still transmitting a single value, one byte at a time"
byte_list = []
while bytes_available:
# build list of bytes in an integer - assuming bytes are sent in the same
# order they would be written. Ex: integer '123' is sent as '1', '2', '3'
byte_list.append(bus.read_byte(address))
# now recombine the list of bytes into a single string, then convert back into int
number = int("".join([chr(byte) for byte in byte_list]))
return number
Arduino Side, in C
Split an Integer:
void sendData(){
int i = 0;
String outString = String(number); /* convert integer to string */
int len = outString.length()+1 /* obtain length of string w/ terminator */
char ascii_num[len]; /* create character array */
outString.toCharArray(ascii_num, len); /* copy string to character array */
for (i=0; i<len); ++i){
Wire.write(ascii_num[i]);
}
}
Reassembling a received Integer:
Note: I'm having some trouble understanding what your other code in this routine is doing, so I'm going to reduce it to just assembling the integer.
void receiveData(int byteCount){
int inChar;
String inString = "";
/* As with the Python receive routine, it will be up to you to identify the
terminating condition for this loop - "bytes_available" means the same thing
as before */
while(bytes_available){
inChar = Wire.read();
inString += char(inChar);
}
number = inString.toInt();
}
I don't have the materials on hand to test this, so it's possible I've gotten the byte order flipped in one routine or another. If you find stuff coming in or out backwards, the easiest place to fix it is in the Python script by using the built-in function reversed() on the strings or lists.
References (I used some code from the Arduino Examples):
Arduino String objects
Arduino String Constructors
Python Built-ins chr() and ord()
Check the following Link:
[http://www.i2c-bus.org/][1]
When I was sending data back and forward using I2C I was converting the string characters to bytearrays and viceversa. So since you are always sending bytes. It will always work since you are sending numbers between 0-255.
Not sure this helps but at least may give you an idea.
You could convert the number to a string of digits like you said. But you could also send the raw bytes.
String of digits
Advantages
Number can have infinite digits. Note that when Arduino reads the number as a string, it is infinite, but you can't convert it all to integer if it overflows the 16-bit range (or 32-bit for Due).
Disadvantages
Variable size, thus requiring more effort in reading.
Waste of bytes, because each decimal digit would be a byte, plus the null-terminator totalizing (digits + 1) size.
Having to use decimal arithmetic (which really is only useful for human counting), note that a "number to string" operation also uses decimal arithmetic.
You can't send/receive negative numbers (unless you send the minus signal, wasting more time and bytes).
Raw bytes
Advantages
Number of bytes sent for each integer is always 4.
You can send/receive negative numbers.
The bitwise arithmetic in C++ for extracting each byte from the number is really fast.
Python already has the struct library which packs/unpacks each byte in a number to a string to send/receive, so you don't need to do the arithmetic like in C++.
Disadvantages
Number has a limited range (signed 32-bit integer in our case, which ranges from -2147483648 to 2147483647). But it doesn't matter because no Arduino can handle more than 32-bit anyways.
So I would use the raw bytes method, which I can provide some untested functions here:
import struct
# '<i' stands for litle-endian signed integer
def writeNumber(value):
strout = struct.pack('<i', value)
for i in range(4):
bus.write_byte(address, strout[i])
return -1
def readNumber():
strin = ""
for _ in range(4):
strin += bus.read_byte(address)
return struct.unpack('<i', strin)[0]
And the Arduino part:
void receiveData(int byteCount)
{
// Check if we have a 32-bit number (4 bytes) in queue
while(Wire.available() >= 4)
{
number = 0;
for(int i = 0; i < 32; i += 8)
{
// This is merging the bytes into a single integer
number |= ((int)Wire.read() << i);
}
Serial.print("data received: ");
Serial.println(number);
// ...
}
}
void sendData()
{
for(int i = 0; i < 32; i += 8)
{
// This is extracting each byte from the number
Wire.write((number >> i) & 0xFF);
}
}
I don't have any experience with I2C, but if its queue is a FIFO, then the code should work.
I need to send integers greater than 255? Does anyone know how to do this?
Here's how (Thanks for the idea, Alex!):
Python:
def packIntegerAsULong(value):
"""Packs a python 4 byte unsigned integer to an arduino unsigned long"""
return struct.pack('I', value) #should check bounds
# To see what it looks like on python side
val = 15000
print binascii.hexlify(port.packIntegerAsULong(val))
# send and receive via pyserial
ser = serial.Serial(serialport, bps, timeout=1)
ser.write(packIntegerAsULong(val))
line = ser.readLine()
print line
Arduino:
unsigned long readULongFromBytes() {
union u_tag {
byte b[4];
unsigned long ulval;
} u;
u.b[0] = Serial.read();
u.b[1] = Serial.read();
u.b[2] = Serial.read();
u.b[3] = Serial.read();
return u.ulval;
}
unsigned long val = readULongFromBytes();
Serial.print(val, DEC); // send to python to check
Encode them into binary strings with Python's struct module. I don't know if arduino wants them little-endian or big-endian, but, if its docs aren't clear about this, a little experiment should easily settle the question;-).
Way easier :
crc_out = binascii.crc32(data_out) & 0xffffffff # create unsigned long
print "crc bytes written",arduino.write(struct.pack('<L', crc_out)) #L, I whatever u like to use just use 4 bytes value
unsigned long crc_python = 0;
for(uint8_t i=0;i<4;i++){
crc_python |= ((long) Serial.read() << (i*8));
}
No union needed and short !