I try to send data over an arduino Ethernet shield to client (python on PC)
the problem that i had is when i read like example the pin A0 in arduino i get 1023 but when i send this value to python i get 49152...
arduino code
#include <SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>
byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED }; // Enter a MAC address for your controller below.
IPAddress ip(192,168,0,101);
IPAddress gateway(192,168,0,254);
IPAddress subnet(255,255,255,0);
unsigned int UDPport = 5000;// local port to listen for UDP packets
IPAddress UDPServer(192,168,0,100); // destination device server
const int UDP_PACKET_SIZE= 48;
byte packetBuffer[ UDP_PACKET_SIZE]; //buffer to hold incoming and outgoing packets
unsigned int noChange = 0;
int UDPCount = 0;
EthernetUDP Udp;
unsigned long currentTime;
unsigned long secondTime;
unsigned long msPerSecond = 100UL;
float temperature;
float vitesse;
float charge;
float current;
void setup()
{
Serial.begin(9600);
Ethernet.begin(mac,ip,gateway,gateway,subnet);
Udp.begin(UDPport);
delay(1500);
currentTime=millis();
secondTime = currentTime;
}
void loop()
{
currentTime = millis();
getUDPpacket();
if(currentTime - secondTime > msPerSecond) {
temperature = analogRead(0); //read analog input on pin A0
vitesse = analogRead(1); //read analog input on pin A1
charge = analogRead(2); //read analog input on pin A2
current = analogRead(3); //read analog input on pin A3
Serial.println(temperature);
sendUDPpacket(UDPServer); // send an NTP packet to a time server
secondTime += msPerSecond;
}
}
unsigned int udpCount = 0;
unsigned long sendUDPpacket(IPAddress& address)
{
udpCount++;
memset(packetBuffer, 0, UDP_PACKET_SIZE); sprintf((char*)packetBuffer,"%u,%u,%u,%u",temperature,vitesse,charge,current);
Udp.beginPacket(address, UDPport);
Udp.write(packetBuffer,UDP_PACKET_SIZE);
Udp.endPacket();
}
void getUDPpacket() {
if ( Udp.parsePacket() ) {
if(Udp.remoteIP() == UDPServer) {
Serial.print(F("UDP IP OK "));
}
else {
Serial.println(F("UDP IP Bad"));
return;
}
if(Udp.remotePort() == UDPport) {
Serial.println(F("Port OK"));
}
else {
Serial.println(F("Port Bad"));
return;
}
Udp.read(packetBuffer,UDP_PACKET_SIZE); // read the packet into the buffer
Serial.print(F("Received: "));
Serial.println((char*)packetBuffer);
}
}
the python code
import socket
import time
UDP_IP = "192.168.0.100"
UDP_PORT = 5000
sock = socket.socket(socket.AF_INET, # Internet
socket.SOCK_DGRAM) # UDP
sock.bind((UDP_IP, UDP_PORT))
while True:
data, addr = sock.recvfrom(48)
print data
time.sleep(5)
i think the problem is in this line
sprintf((char*)packetBuffer,"%u,%u,%u,%u",temperature,vitesse,charge,current);
but i dont know what to do
You should enable all warnings (eg in gcc use -Wall) when you compile your C code. That way, it would warn you when you try to print floats with the %u unsigned integer format specifier, as that leads to undefined behaviour.
You should either a) convert temperature, vitesse, charge, and currentto unsigned integer before passing them to sprintf(), or b) change the format specifier to something like %f so that sprintf() knows to expect floating-point data.
Also you should include <stdio.h> so that your program has a prototype for sprintf(); I assume that those headers you have included contain prototypes & constants relevant to the Ethernet & Arduino port IO functions.
Related
I am trying to send float values from Python on Windows to an Arduino. The first problem I encounter is that I cannot view the serial monitor when I think I am sending data from my Python script. I have read online that this is becuase only one application can manage the port at once: https://forum.arduino.cc/t/serial-communication-only-working-when-serial-monitor-is-opened/601107/12
However I have seen examples where the user is viewing the serial monitor to see data coming in over serial from Python and serial.print outs from the Arduino. So I am unsure what is the case... not being able to view the serial monitor sure does make debugging this senario hard.
My Python code:
import struct
import serial
import time
print('test123')
x=0.8
y=0.2
ser = serial.Serial('COM5', 9600, timeout=1)
#print(ser)
time.sleep(3)
def sendmess():
bin = struct.pack('ff',x,y) #Pack float value into 4 bytes
data = ser.write(bin)
#print(bin)
#print(len(bin))
#print([ "0x%02x" % b for b in bin])
#ser.close()
while True:
sendmess()
My Arduino Code:
int d = 250;
float incomingByte = 1;
void setup() {
// initialize the serial communication:
Serial.begin(9600);
pinMode(2, OUTPUT);
}
void loop() {
digitalWrite(2, HIGH);
delay(d);
digitalWrite(2, LOW);
delay(d);
// reply only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
d = 1000;
float incomingByte = Serial.read();
// say what you got:
Serial.println(incomingByte);
}
else{
Serial.println(incomingByte);
d = 20;
}
}
I see the LED flash every second so I know the serial buffer is >0, but I cannot get any data out :(.
Thanks in advance!
Mark
I have tried examples online, but I never get any data to display in the serial monitor. Nor can I say have a pin turn HIGH when I think I am getting the data I think I have sent. But without the Serial Monitor how can I debug this?
Unfortunately, you aren't able to connect more than two devices to the serial connection. However, using Python you should be able to read a response from your arduino and then print that to the python Terminal (or a file) and take a look at that.
The easiest way to do that would be to use pySerial and either ser.read(4) to read back 4 bytes of your float or ser.readline() which will look for either a '\n' which you can add to your arduino code, or a timeout. Then just print it to the python terminal with print().
As for actually reading the float, Serial.read() will only read in the next byte in the buffer. Since a float is 4 bytes long, you need to either read the 4 bytes into an array or use Serial.parseFloat()
Python Code
import struct
import serial
import time
x=0.8
y=0.2
ser = serial.Serial('COM5', 9600, timeout=1)
#print(ser)
time.sleep(3)
def sendmess():
bin = str(x) + str(y) #Pack float value into 4 bytes
data = ser.write(bin.encode())
echo = ser.readline()
print("Echo: " + echo)
#ser.close()
while True:
sendmess()
Arduino Code:
int d = 250;
float X;
float Y;
char buffer[40];
void setup() {
// initialize the serial communication:
Serial.begin(9600);
pinMode(2, OUTPUT);
}
void loop() {
digitalWrite(2, HIGH);
delay(d);
digitalWrite(2, LOW);
delay(d);
// reply only when you receive data:
if (Serial.available() > 0) {
// read the incoming byte:
d = 1000;
X = Serial.parseFloat();
Y = Serial.parseFloat();
// say what you got:
sprintf(buffer, "X: %f Y: %f", X, Y);
Serial.println(buffer);
}
else{
Serial.println(buffer);
d = 20;
}
}
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.
/*
String to Integer conversion
Reads a serial input string until it sees a newline, then converts
the string to a number if the characters are digits.
The circuit:
No external components needed.
created 29 Nov 2010
by Tom Igoe
This example code is in the public domain.
*/
#include <LiquidCrystal.h>
LiquidCrystal lcd(23, 22,13,12,11,10);
String inString = ""; // string to hold input
void setup() {
// Open serial communications and wait for port to open:
Serial.begin(19200);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
lcd.begin(20, 4);
// send an intro:
//println("\n\nString toInt():");
//Serial.println();
}
void loop() {
// Read serial input:
while (Serial.available() > 0) {
lcd.setCursor(0,0);
lcd.print("welcome");
int inChar = Serial.read();
if (isDigit(inChar)) {
// convert the incoming byte to a char
// and add it to the string:
inString += (char)inChar;
}
// if you get a newline, print the string,
// then the string's value:
if (inChar == '\n') {
int data = inString.toInt() ;
lcd.setCursor(0,1);
lcd.print("speed: ");
lcd.println(data);
if(data > 50){
lcd.setCursor(0,2);
lcd.print("Over speed");
}
else{
lcd.setCursor(0,2);
lcd.print("Under speed limit ");
}
// Serial.print("Value:");
//Serial.println(inString.toInt());
//Serial.print("String: ");
//Serial.println(inString);
// clear the string for new input:
inString = "";
}
}
}
This code works while using serial monitor with Arduino, but when run interface Arduino with Raspberry Pi, only "welcome" message come on LCD not data (2 digit number) that I transferred through Raspberry Pi, may be it is due to Python program on Raspberry Pi or any other reason.
You're checking for "\n" but never sending one. so you'll never trigger
if (inChar == '\n')
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.
I am trying to implement a UDP communication protocol between a C program and a python program. The C program has a structure that it sends through the UDP port (tx_port) as binary data. This program also listens on another port (rx_port) for any received data, and then prints the received binary output to the screen.
The python program listens on tx_port and unpacks the received data and prints it to the screen. Then it repacks the data and sends it back through UDP port (rx_port).
Here are the C and Python programs that I used.
C program
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <unistd.h>
#include <pthread.h>
#define BUFLEN 4096
#define RX_PORT 8888
#define TX_PORT 8889
// Structure data
struct data {
long frame_number;
double time;
} tx_data, rx_data;
int dlen = sizeof(tx_data);
struct sockaddr_in si_me, si_other;
int tx_soc;
int slen = sizeof(si_other);
int recv_len;
char* buf;
pthread_t rx_thread;
void* receiver_thread(void *arg)
{
int i =0;
while (1) {
recv_len = recvfrom(tx_soc, buf, sizeof(rx_data), 0, (struct sockaddr *) &si_other, &slen);
printf("\nReceived data : %d\n", recv_len);
for (i = 0; i < recv_len; i++) {
printf("%x ", buf[i]);
}
printf("\n");
fflush(stdout);
};
}
void data_init(void) {
tx_data.frame_number = 0;
tx_data.time = 0;
};
int main(void)
{
// Initialize data
data_init();
//create a UDP socket
if ((tx_soc=socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1)
{
printf("Socket error!");
exit(0);
}
// zero out the structure
memset((char *) &si_me, 0, sizeof(si_other));
memset((char *) &si_other, 0, sizeof(si_other));
// Host socket address
si_me.sin_family = AF_INET;
si_me.sin_port = htons(RX_PORT);
si_me.sin_addr.s_addr = htonl(INADDR_ANY);
// Remote socket address
si_other.sin_family = AF_INET;
si_other.sin_port = htons(TX_PORT);
si_other.sin_addr.s_addr = htonl(INADDR_ANY);
//bind sockets to the ports
if( bind(tx_soc, (struct sockaddr*)&si_me, sizeof(si_me) ) == -1)
{
printf("Binding error!");
}
// Start reader thread.
if (pthread_create(&rx_thread, NULL, &receiver_thread, NULL) != 0) {
printf("\ncan't create thread");
}
//keep listening for data
while(1)
{
// Allocate memory for receive buffer.
buf = (char*) malloc(sizeof(rx_data));
// Update data value.
tx_data.frame_number++;
printf("\nFrame numner: %ld", tx_data.frame_number);
fflush(stdout);
// Send data.
if (sendto(tx_soc, (char*)&tx_data, dlen, 0, (struct sockaddr*) &si_other, slen) == -1)
{
printf("Sending error!");
}
sleep(1);
}
close(tx_soc);
return 0;
}
Python program
from twisted.internet.protocol import DatagramProtocol
from twisted.internet import reactor
import struct
# Packet format string
packet_fmt = ''.join(['i', # Frame number
'd', # Frame time stamp
])
s = struct.Struct(packet_fmt)
class Echo(DatagramProtocol):
def datagramReceived(self, data, (host, port)):
new_data = s.unpack(data)
print new_data
echo_data = s.pack(*new_data)
self.transport.write(echo_data, (host, port))
reactor.listenUDP(8889, Echo())
reactor.run()
When I execute the two programs, I am able to receive data on both sides. I am able to unpack data in python, print it, repack and send it.
But on the C side, the received data does not match the sent data. I have checked on the python side to make sure the repacked data matches the original data.
Here is a sample output from the C and Python programs. I started the python programs first, and then the C program.
What is the mistake I might be making?