Arduino serial communication with serial encoder - arduino

I am currently trying to communicate with an absolute encoder over serial, and as you can see from the picture below, it is responding fine to my requests, but the problem I am having is arduino is not reading the response bytes correctly all the time. The request from the encoder for position is the command 0x64 which responds with 4 bytes which consist of an echo byte (0x64 in picture), two bytes of data (0xAD and 0x53 in picture), and a error byte (0x00 in picture). What I am currently doing is sending the command, reading 4 bytes and as a way of debugging I am writing the response of the echo byte back to the serial port (0x18 in picture). As you can see 0x18 != 0x64 so I'm wondering where I am going wrong. I have double checked the baudrate and I'm talking at the correct speed, I just cannot seem to get a consistent read on the response. Below is a simplified version of the code that I have been running to try and fix this issue. The delayMicroseconds() is just there to separate the bytes on the oscilloscope.
Serial.write(0x64);
byte echo_byte = 0;
byte pos_1 = 0;
byte pos_2 = 0;
byte status_byte = 0;
echo_byte = Serial.read();
pos_1 = Serial.read();
pos_2 = Serial.read();
status_byte = Serial.read();
delayMicroseconds(1000);
Serial.write(echo_byte)

You must check and wait until there is a byte available to read on the port before calling Serial.read(). If there are no bytes available for reading, Serial.read() returns -1.
as in:
byte echo_byte = 0;
byte pos_1 = 0;
byte pos_2 = 0;
byte status_byte = 0;
Serial.write(0x64);
while (Serial.available() < 4) // wait for the 4 byte message.
;
Serial.read(echo_byte);
Serial.read(pos_1);
Serial.read(pos_2);
Serial.read(status_byte);
This is a bit cumbersome, and prone to errors, so Serial.readBytes is usually used for mylti-byte transfers, as in:
// Reads position from encoder, returns true if pos is valid.
bool read_pos(unsigned short& pos)
{
struct pos_msg
{
byte echo_byte;
unsigned short pos;
byte status;
};
Serial.write(0x64);
pos_msg msg;
Serial.readBytes((char*)&msg, sizeof(msg));
if (msg.echo_byte != 0x64 || msg.status != 0)
return false;
pos = msg.pos;
return true;
}

Related

Reading multiple bytes in Arduino sent using Pyserial

I'm constantly sending structs of int64 via Pyserial with:
with serial.Serial(port='COM4', baudrate=115200, timeout=.1) as arduino:
value = write_read(struct.pack(">q", int_array[1][i])) #this sends signed int.64 in bytes
print(value)
the struct.pack has this shape, for example:
b'\xff\xff\xff\xff\xff\xff\xff\xef'
and the function write_read consists of:
def write_read(x):
arduino.write((x))
data = arduino.readline()
#the idea is to receive an ACK from the Arduino after 8 bytes (the full
#number)
return data
The code I'm trying to develop in arduino is the following:
void loop() {
// send data only when you receive data:
if (Serial.available() \> 0) {
// read the incoming byte:
incomingByte = Serial.read();
//read 8 bytes and create the result
r= function_to_read_8_last_bytes // or similar
// say what you got:
Serial.print("I received: ");
Serial.printlesultn(r, DEC);
Serial.write("ACK");
}
}
I'm very curious how I could do a robust "read 8 bytes" function.
Should I add some especial character in the Python part to indentify when it ends one value?
Thanks! I'll appreciate any help :)
Given the discussion in the comments, it's hard to receive a stream of bytes and be sure that the receiver is completely synchronized. However let's make some assumptions to ease the problem:
The serial buffer is empty when you connect your laptop to Arduino. This ensures you won't receive spurious data with no meaning. I had this problem happens a lot when the serial connection was ended abruptly by any cause.
You are not constantly sending bytes, Arduino has time to process them until the start of the new sequence.
You only send this data, so there is no need to create a higher level protocol on top of it. Bare in mind that the serial communication is almost just an hardware stack, you receive bytes with no headers.
For assumption 1 you can write a simple piece of code to consume all the spurious bytes in the serial buffer as soon as your main starts from Arudino, so this will be done everytime you connect the serial (as this is also where the power supply comes from). Something like this:
void serialFlush(){
while(Serial.available() > 0) {
char t = Serial.read();
}
}
You can send a "READY" signal back to the Python interface, so that the program knows you are ready to receive data.
Going on with the solution you can implement an easy CRC in python, an additional byte which contains a XOR of all the previous bytes, and you check that in Arduino upon reception complete.
def xor_reduce_long_int(li):
res = 0;
for i in range(8):
mask = (0xFF)<<(i*8)
print(hex(mask))
masked = (li&mask)>>(i*8)
res ^= masked
return res
with serial.Serial(port='COM4', baudrate=115200, timeout=.1) as arduino:
crc=xor_reduce_long_int(int_array[1][i])
value = write_read(struct.pack(">qc", int_array[1][i],crc)) #this sends signed int.64 in bytes
print(value)
And with Arduino I would read 8 bytes when they are available and put them into an unsigned char buffer. I would then define a union that alias such buffer to interpret it as long long int.
typedef struct long_int_CRC
{
union
{
unsigned char bytes[8];
long int data;
};
unsigned char CRC;
}data_T;
// .. Later in main
data_T = received_data;
int received_bytes=0
unsigned char my_CRC = 0;
unsigned char rec_byte= 0;
while( received_bytes < 8 )
{
if(Serial.available() )
{
// Get the byte
rec_byte = Serial.read()
// Store the byte and calc CRC
received_data.bytes[received_bytes] = rec_byte;
my_CRC ^= rec_byte;
// Increment counter for next byte
received_bytes++;
}
}
// Reception complete, check CRC
unsigned char rec_CRC;
if(Serial.available() )
{
rec_CRC = Serial.read()
}
if( my_CRC != rec_CRC )
{
// Something was wrong!
}
// Now access your data as a long int
Serial.print("I received: ");
Serial.printlesultn(received_data.data, DEC);
Serial.write("ACK");

How do make code compatible to ESP32 board?

I'm trying to get a GY-US-42 ultrasonic sensor working on the ESP32. However, I keep getting an error while compiling. For and Arduino Board it is not a problem, but for the ESP32.
My code:
#include "Wire.h"
//The Arduino Wire library uses the 7-bit version of the address, so the code example uses 0x70 instead of the 8-bit 0xE0
#define SensorAddress byte(0x70)
//The sensors ranging command has a value of 0x51
#define RangeCommand byte(0x51)
//These are the two commands that need to be sent in sequence to change the sensor address
#define ChangeAddressCommand1 byte(0xAA)
#define ChangeAddressCommand2 byte(0xA5)
void setup() {
Serial.begin(115200); //Open serial connection at 9600 baud
Wire.begin();
// changeAddress(SensorAddress,0x40,0);
}
void loop(){
takeRangeReading(); //Tell the sensor to perform a ranging cycle
delay(50); //Wait for sensor to finish
word range = requestRange(); //Get the range from the sensor
Serial.print("Range: "); Serial.println(range); //Print to the user
}
//Commands the sensor to take a range reading
void takeRangeReading(){
Wire.beginTransmission(SensorAddress); //Start addressing
Wire.write(RangeCommand); //send range command
Wire.endTransmission(); //Stop and do something else now
}
//Returns the last range that the sensor determined in its last ranging cycle in centimeters. Returns 0 if there is no communication.
word requestRange(){
Wire.requestFrom(SensorAddress, byte(2));
if(Wire.available() >= 2){ //Sensor responded with the two bytes
byte HighByte = Wire.read(); //Read the high byte back
byte LowByte = Wire.read(); //Read the low byte back
word range = word(HighByte, LowByte); //Make a 16-bit word out of the two bytes for the range
return range;
}
else {
return word(0); //Else nothing was received, return 0
}
}
Error:
sketch/GY-US42_I2C.ino.cpp.o:(.literal._Z12requestRangev+0x0): undefined reference to `makeWord(unsigned short)'
sketch/GY-US42_I2C.ino.cpp.o: In function `requestRange()':
/Users/Arduino/GY-US42_I2C/GY-US42_I2C.ino:42: undefined reference to `makeWord(unsigned short)'
collect2: error: ld returned 1 exit status
The word() is for casting a variable or literal into a 16-bit word, it does not add two bytes into a 16-bit word as you do word(HighByte, LowByte), I'm actually surprise this even compiled in Arduino.
To get the range value, you could do:
int range = HighByte * 256 + LowByte;
or:
int range = ((int)HighByte) << 8 | LowByte; //cast HighByte to int, then shift left by 8 bits.
But since Wire.read() is returning an int instead of a byte(you can see its function prototype definition here), therefore you code can actually be written like this:
int reading = Wire.read(); //read the first data
reading = reading << 8; // shift reading left by 8 bits, equivalent to reading * 256
reading |= Wire.read(); // reading = reading | Wire.read()
By the way, when you use #define, you don't need to specifically cast the const value into specific data type, the compiler will take care of the optimization and the right data type, so:
#define SensorAddress byte(0x70)
would be just fine by defining like this:
#define SensorAddress 0x70
You also do not need to cast const value with byte(2) or return word(0). In the latter case, your function prototype already expect the return would be a data type of word.

Serial Communication Between Arduino and EPOS: CRC Calculation Problems

I am trying to interface with an EPOS2 motor controller over RS232 Serial with an Arduino Duemilanove (because it's what I had lying around). I got it to work for the most part - I can send and recieve data when I manually calculate the CRC checksum - but I'm trying to dynamically control the velocity of the motor which requires changing data, and therefore, changing checksum. The documentation for calculating the checksum is here, on page 24:
http://www.maxonmotorusa.com/medias/sys_master/8806425067550/EPOS2-Communication-Guide-En.pdf
I copied the code directly out of this documentation, and integrated it into my code, and it does not calculate the checksum correctly. Below is a shortened version of my full sketch (tested, yielding 0x527C). The weirdest part is that it calculates a different value in my full sketch than in the one below, but both are wrong. Is there something obvious that I'm missing?
byte comms[6] = { 0x10, 0x01, 0x03, 0x20, 0x01, 0x02 }; // CRC should be 0xA888
void setup() {
Serial.begin(115200);
}
void loop() {
calcCRC(comms, 6, true);
while(1);
}
word calcCRC(byte *comms, int commsSize, boolean talkative) {
int warraySize = commsSize / 2 + commsSize % 2;
word warray[warraySize];
warray[0] = comms[0] << 8 | comms[1];
Serial.println(warray[0], HEX);
for (int i = 1; i <= warraySize - 1; i++) {
warray[i] = comms[i * 2 + 1] << 8 | comms[i * 2];
Serial.println(warray[i], HEX);
}
word* warrayP = warray;
word shifter, c;
word carry;
word CRC = 0;
//Calculate pDataArray Word by Word
while (commsSize--)
{
shifter = 0x8000;
c = *warrayP ++;
do {
carry = CRC & 0x8000;
CRC <<= 1;
if (c & shifter) CRC++;
if (carry) CRC ^= 0x1021;
shifter >>= 1;
} while (shifter);
}
if (talkative) {
Serial.print("the CRC for this data is ");
Serial.println(CRC, HEX);
}
return CRC;
}
I used the link below to calculate the checksum that works for this data:
https://www.ghsi.de/CRC/index.php?Polynom=10001000000100001&Message=1001+2003+0201
Thanks so much!!
Where to begin.
First off, you are using commsSize-- for your loop, which will go through six times when you have only three words in the warray. So you are doing an out-of-bounds access of warray, and will necessarily get a random result (or crash).
Second, the build of your first word is backwards from your other builds. Your online CRC suffers the same problem, so you apparently don't even have a reliable test case.
Third (not an issue for the test case), if you have an odd number of bytes of input, you are doing an out-of-bounds access of comms to fill out the last word. And you are running the CRC bits too many times, unless the specification directs some sort of padding in that case. (Your documentation link is broken so I can't see what's supposed to happen.) Even then, you are using random data for the padding instead of zeros.
The whole word conversion thing is a waste of time anyway. You can just do it a byte at a time, given the proper ordering of the bytes. That also avoids the odd-number-of-bytes problem. This will produce the 0xa888 from the input you gave the online CRC calculator (which are your bytes in a messed up order, but exactly as you gave them to the calculator):
unsigned char dat[6] = { 0x10, 0x01, 0x20, 0x03, 0x02, 0x01 };
unsigned crc1021(unsigned char *dat, int len) {
unsigned crc = 0;
while (len) {
crc ^= *dat++ << 8;
for (int k = 0; k < 8; k++)
crc = crc & 0x8000 ? (crc << 1) ^ 0x1021 : crc << 1;
len--;
}
return crc & 0xffff;
}

Arduino I2C - data stream stopped unexpectedly

I am trying to connect an Arduino Uno to a temperature sensor using I2C. At first, the Arduino can send the data stream, but it stops a few minutes later...
If I restart the board, the Arduino can send the data stream, but again it stops a few minutes later. I wonder whether my code is wrong. Please help me.
/*
Program akses DT-SENSE Temp SENSOR - Arduino
Vizard Vision # 2013
*/
#include <Wire.h>
void setup() {
Wire.begin();
Serial.begin(38400);
}
int buffer = 0;
int count = 0;
void loop() {
if(count >= 6000) {
count = 0;
}
Wire.beginTransmission(112); // transmit to device #112 (0x70)
// the address specified in the datasheet is 224 (0xE0) --> 1110 0000 = E0H
// but i2c adressing uses the high 7 bits so it's 112 --> 0111 0000 = 70H
Wire.send(0x00);
// command sensor to measure 16 Byte of Temperature Data
Wire.endTransmission();
delay(100);
Wire.requestFrom(112, 2);
// request 2 bytes from slave device #112
if(2 <= Wire.available()) {
// if two bytes were received
buffer = Wire.receive();
// receive high byte (overwrites previous reading)
buffer = buffer << 8;
// shift high byte to be high 8 bits
buffer |= Wire.receive();
// receive low byte as lower 8 bits
buffer = (buffer - 400)/10;
// Conversion data to Temperature (from datasheet)
Serial.print(count);
Serial.print(" Suhu = ");
Serial.print(buffer);
Serial.write(176);
// Unicode value of Degree Symbol
Serial.println("Celsius");
count ++;
Serial.flush();
}
delay(40);
}
There could be a problem here:
if(2 <= Wire.available()) // if two bytes were received
{
buffer = Wire.receive(); // receive high byte (overwrites previous reading)
buffer = buffer << 8; // shift high byte to be high 8 bits
buffer |= Wire.receive(); // receive low byte as lower 8 bits
It will get into the block if there is 1 or 2 bytes available. If there is 2 bytes, it will go through both Wire.receive() and your buffer variable will be setup correctly, and you're happy. If there is only 1 byte, it will pass first Wire.receive(), and on second Wire.receive() you'll have an unexpected behaviour (i.e. documentation does not tell what it does when that happens). So I'd expect it to be blocking until a byte comes, but as it will never come, it blocks infinitely.
Then you'd wonder "why would this ever return a single byte?". And there can be many reasons:
the datasheet may be lying and on very specific circumstances your i2c slave may return a single byte,
your connection is mishandled at one point, and the slave writes both bytes at an incorrect speed making your lib believe it's only one byte,
there's a false contact in your i2c line and under weird circumstances (temperature, pressure, vibration, a storm in Nicaragua) and only one of the two bytes are getting through the connection...
So you should do the following:
if(Wire.available() == 2) // if two bytes were received
{
buffer = Wire.receive(); // receive high byte (overwrites previous reading)
buffer = buffer << 8; // shift high byte to be high 8 bits
buffer |= Wire.receive(); // receive low byte as lower 8 bits
which will make you avoid going through the unexpected behavior!

tcp send with its real length instead of using sizeof data

I am trying to send a small packet via tcp but i have a problem with the size of it.
My data is 255 byte buffer:
buffer[0] = 0x00;
buffer[1] = 0x04;
buffer[2] = 0x06;
buffer[3] = 0x08;
buffer[4] = 0x01;
buffer[5] = 0x01;
and i use
send(sockfd,buffer,6,MSG_NOSIGNAL|MSG_DONTWAIT);
but data can not be send when i use 6. If i use send like:
send(sockfd,buffer,sizeof(buffer),MSG_NOSIGNAL|MSG_DONTWAIT);
then data is sent but recevier has to parse extra 250 0x00 byte and i don't want it. Why 6 is no ok. I also try 10 randomly nothing changes.
Here is my receiver code Anything writes at that side:
while(1) {
ret = recv(socket,buffer,sizeof(buffer),0);
if (ret > 0)
printf("recv success");
else
{
if (ret == 0)
printf("recv failed (orderly shutdown)");
else
printf("recv failed (errno:%d)",errno);
}
}
Get rid of MSG_DONTWAIT. This is only useful when you have something else to do when the socket send buffer is full and the data can't be sent. As you aren't checking the result of send(), clearly you aren't interested in that condition. However you must check the result of send anyway, as you may have got an error, so fix your code to do that as well.

Resources