Home > Net >  How to receive the struct sent over UDP from python , in esp8266
How to receive the struct sent over UDP from python , in esp8266

Time:04-23

I am sending UDP packets from my computer to esp8266, but after receiving the packet, it looks something like this in the Arduino serial monitor: enter image description here

The original data i am sending: enter image description here

Here is the block of code for the receiving end (esp8266):

void udp_rcv()
{
  int packetSize = UDP.parsePacket();
  if (packetSize) {
    Serial.print("Received packet! Size: ");
    Serial.println(packetSize); 
    int len = UDP.read(packet, 255);
    if (len > 0)
    {
      packet[len] = '\0';
    }
    Serial.print("Packet received: ");
    Serial.println(packet[0]);
}

And this is the code sending the UDP packet from my pc using python:

pygame.event.pump()
roll     = mapping(joystick.get_axis(0),-1,1,1000,2000)
pitch    = mapping(joystick.get_axis(1),1,-1,1000,2000)
yaw      = mapping(joystick.get_axis(2),-1,1,1000,2000)
throttle = mapping(joystick.get_axis(3),1,-1,1000,2000)
mode     = joystick.get_button(6)

# Be sure to always send the data as floats
# The extra zeros on the message are there in order for the other scripts to do not complain about missing information
message = [roll, pitch, yaw, throttle, mode, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
buf = struct.pack('>'   'd' * len(message), *message)
sock.sendto(buf, (UDP_IP, UDP_PORT))
print( message)

All I am trying to do is use my Joystick gamepad inputs to send it to the esp8266 via UDP protocol

CodePudding user response:

To send and receive data across different platforms, you need to aware of the data type and data structure that you are sending as well as the Endianness of both the sender and the receiver.

Regarding your Python code

I'm not sure why you explicitly specify big endian with > for packing the data, most of the modern computers are using little endian rather than big endian (unless you had a Motorola 68000 or PowerPC machine), furthermore all the MCU such as Uno and ESP8266 are little endian MCU. So it would be make more sense to specify little endian with < to pack your data.

Secondly, you are assuming your data are in double but if you look at screen shot on message, mode is definitely not a double but an int (on most of modern PCs, int is 32-bit long).

So instead of packing your data with:

buf = struct.pack('>'   'd' * len(message), *message)

What you should really do is:

buf = struct.pack('<ddddiddddddddd', *message)

Regarding your Arduino Code

The data sending from the Python code is a series of bytes that can be represented in C as:

struct __attribute__((packed)) JoyStick {
  double roll;
  double pitch;
  double yaw;
  double throttle;
  int32_t mode;
  double array[9]; 
};

Since the packet data is an array of uint8_t (or char as you might declared), it will be easier to copy the data into a variable of JoyStick_t type, so that you can access the data as a struct.

  int packetSize = UDP.parsePacket();
  if (packetSize) {
    Serial.printf("Received %d bytes\n", packetSize);
    if (UDP.read(packet, packetSize) > 0)) {
      JoyStick myJoystick;                      //create a struct
      memcpy(&myJoystick, packet, packetSize);  //copy packet array to the a struct
      Serial.printf("%f %f %f %f %d\n", 
                    myJoystick.roll, 
                    myJoystick.pitch, 
                    myJoystick.yaw, 
                    myJoystick.throttle, 
                    myJoystick.mode);           // access the data in the struct
    }
  }
  • Related