Forum Rule: Always post complete source code & details to reproduce any issue!
Results 1 to 3 of 3

Thread: Teensy 4.1 high rate websocket communication

  1. #1
    Junior Member
    Join Date
    Nov 2021
    Posts
    2

    Teensy 4.1 high rate websocket communication

    Hi everyone,

    I am building a showlaser for my graduation assignment. I use the teensy 4.1 as the controller in the laser and my pc to send commands to the teensy 4.1 by a websockets connection. I succeeded in setting up the communication, but there is one thing wrong. When i send like 5000 messages in a for loop the Teensy crashes and the connection is lost. If i send 50 messages to the teensy the teensy does not crash and the connection remains.

    My goal is to send around 30000 messages per second, with a stable connection. The message is a string and looks like this "x:-4000", "r:255". Are websockets suited for this use case or are their better ways to accomplish this? I would really like to use the ethernet connection since i had problems with serial being too laggy for the laser in the previous showlaser version that i build.


    Below is the code i used for the teensy.
    The teensy code is the example sketch found in Websockets2_Generic -> Generic -> Teensy41_NativeEthernet -> MultipleClients_Teensy41_Server.

    Code:
    /****************************************************************************************************************************
      MultiClients_Teensy41_Server.ino
      For Teensy 4.1 with NativeEthernet.
    
      Based on and modified from Gil Maimon's ArduinoWebsockets library https://github.com/gilmaimon/ArduinoWebsockets
      to support STM32F/L/H/G/WB/MP1, nRF52, SAMD21/SAMD51, SAM DUE, Teensy boards besides ESP8266 and ESP32
    
      The library provides simple and easy interface for websockets (Client and Server).
      
      Built by Khoi Hoang https://github.com/khoih-prog/Websockets2_Generic
      Licensed under MIT license
     *****************************************************************************************************************************/
    /*
      Teensy41 Websockets Server and Http Server (using NativeEthernet).
      Combining the Teensy41-Server example with the NativeEthernet WebServer
      example (https://github.com/vjmuzik/NativeEthernet/blob/master/examples/WebServer/WebServer.ino).
    
      This sketch:
      1. Connects to a ethernet network
      2. Starts a websocket server on port 80
      3. Waits for connections
      4. As soon as a client wants to establish a connection, it checks whether a
         free slot is available and accepts it accordingly
      5. If the client is accepted it sends a welcome message and echoes any
         messages from the client
      6. Goes back to step 3
    
      Note:
      Make sure you share your computer's internet connection with the Teensy
      via ethernet.
    
      Libraries:
      To use this sketch install
        TeensyID library (https://github.com/sstaub/TeensyID)
        NativeEthernet (https://github.com/vjmuzik/NativeEthernet)
    
      Hardware:
      For this sketch you need a Teensy 4.1 board and the Teensy 4.1 Ethernet Kit
      (https://www.pjrc.com/store/ethernet_kit.html).
    
      Written by https://github.com/arnoson
    */
    
    #if !(defined(__IMXRT1062__) && defined(ARDUINO_TEENSY41))
      #error This is designed only for Teensy 4.1. Please check your Tools-> Boards
    #endif
    
    #define WEBSOCKETS_USE_ETHERNET     true
    #define USE_NATIVE_ETHERNET         true
    
    #include <WebSockets2_Generic.h>
    
    using namespace websockets2_generic;
    
    // We will set the MAC address at the beginning of `setup()` using TeensyID's
    // `teensyMac` helper.
    byte mac[6];
    
    // Enter websockets server port.
    const uint16_t port = 81;
    
    // Define how many clients we accpet simultaneously.
    const byte maxClients = 4;
    
    WebsocketsClient clients[maxClients];
    WebsocketsServer server;
    
    void teensyMAC(uint8_t *mac) {
        for(uint8_t by=0; by<2; by++) mac[by]=(HW_OCOTP_MAC1 >> ((1-by)*8)) & 0xFF;
        for(uint8_t by=0; by<4; by++) mac[by+2]=(HW_OCOTP_MAC0 >> ((3-by)*8)) & 0xFF;
        Serial.printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    }
    
    void setup()
    {
      // Set the MAC address.
      teensyMAC(mac);
    
      // Start Serial and wait until it is ready.
      Serial.begin(115200);
      while (!Serial);
    
      Serial.println("\nStart MultiClients_Teensy41_Server on Teensy 4.1");
      Serial.println(WEBSOCKETS2_GENERIC_VERSION);
    
      // Connect to ethernet.
      if (Ethernet.begin(mac))
      {
        Serial.println("Ethernet connected");
      }
      else
      {
        Serial.println("Ethernet failed");
      }
    
      // Start websockets server.
      server.listen(port);
    
      if (server.available())
      {
        Serial.print("Server available at ws://");
        Serial.print(Ethernet.localIP());
        // Also log any non default port.
        if (port != 80)
          Serial.printf(":%d", port);
    
        Serial.println();
      }
      else
      {
        Serial.println("Server not available!");
      }
    }
    
    void handleMessage(WebsocketsClient &client, WebsocketsMessage message)
    {
      auto data = message.data();
      Serial.println("Data: " + data);
    }
    
    void handleEvent(WebsocketsClient &client, WebsocketsEvent event, String data)
    {
      if (event == WebsocketsEvent::ConnectionClosed)
      {
        Serial.println("Connection closed");
      }
    }
    
    int8_t getFreeClientIndex()
    {
      // If a client in our list is not available, it's connection is closed and we
      // can use it for a new client.
      for (byte i = 0; i < maxClients; i++)
      {
        if (!clients[i].available())
          return i;
      }
    
      return -1;
    }
    
    void listenForClients()
    {
      if (server.poll())
      {
        int8_t freeIndex = getFreeClientIndex();
    
        if (freeIndex >= 0)
        {
          WebsocketsClient newClient = server.accept();
          newClient.onMessage(handleMessage);
          newClient.onEvent(handleEvent);
          clients[freeIndex] = newClient;
        }
      }
    }
    
    void pollClients()
    {
      for (byte i = 0; i < maxClients; i++)
      {
        clients[i].poll();
      }
    }
    
    void loop()
    {
      listenForClients();
      pollClients();
    }


    This is the c# code i use on the computer.

    Code:
    for (int i = 0; i < 50; i++)
                {
                    await _laserConnection.SendMessage($"x:{new Random(Guid.NewGuid().GetHashCode()).Next(-4000, 4000)}");
                }
    The sendMessage method

    Code:
    public async Task SendMessage(string message)
            {
                var rcvBytes = Encoding.ASCII.GetBytes(message);
                var rcvBuffer = new ArraySegment<byte>(rcvBytes);
                bool messageSend = false;
                int connectionAttempts = 0;
    
                while (!messageSend)
                {
                    connectionAttempts++;
                    if (connectionAttempts > 1)
                    {
                        Console.WriteLine(connectionAttempts);
                    }
    
                    try
                    {
                        await _clientWebSocket.SendAsync(rcvBuffer, WebSocketMessageType.Binary, true, CancellationToken.None);
                        messageSend = true;
                    }
                    catch (Exception)
                    {
                        await Connect();
                    }
                }
            }

  2. #2
    Senior Member
    Join Date
    Mar 2017
    Location
    Oakland, CA, USA
    Posts
    474
    I’m curious why websockets would be better than a regular socket here. Seems like a little more overhead. According to http://eng.kifi.com/websockets-vs-regular-sockets/, websockets are for browser-to-server communication when you can’t do regular sockets.

    Of course, you may prefer the websockets API. I just think regular TCP might be faster.

    I’m also curious if the same code would fail using the QNEthernet library. There’s NativeEthernet and QNEthernet as the two options (that I know of) for Arduino-style libraries. (Setup is a little different, however.) That will allow you to rule out either your code or the library.

    Regarding serial speed, what baud rate were you using? Did you try with other protocols too, eg. SPI?
    Last edited by shawn; 11-06-2021 at 08:02 PM.

  3. #3
    Junior Member
    Join Date
    Nov 2021
    Posts
    2

    Thank you

    Thank you for suggesting sockets! I wrote an implementation and it is so much faster! I can send around 200000 messages per second . This is way more than i need and it is very stable, no more crashing of the Teensy. You made me very happy thank you!

    Teensy code
    Code:
    /*
      Chat Server
    
      A simple server that distributes any incoming messages to all
      connected clients.  To use, telnet to your device's IP address and type.
      You can see the client's input in the serial monitor as well.
      Using an Arduino Wiznet Ethernet shield.
    
      Circuit:
       Ethernet shield attached to pins 10, 11, 12, 13
    
      created 18 Dec 2009
      by David A. Mellis
      modified 9 Apr 2012
      by Tom Igoe
    
    */
    
    #include <SPI.h>
    #include <NativeEthernet.h>
    
    // Enter a MAC address and IP address for your controller below.
    // The IP address will be dependent on your local network.
    // gateway and subnet are optional:
    byte mac[6];
    
    IPAddress ip(192, 168, 1, 177);
    
    EthernetServer server(80);
    boolean alreadyConnected = false; // whether or not the client was connected previously
    
    void teensyMAC(uint8_t *mac) {
      for (uint8_t by = 0; by < 2; by++) mac[by] = (HW_OCOTP_MAC1 >> ((1 - by) * 8)) & 0xFF;
      for (uint8_t by = 0; by < 4; by++) mac[by + 2] = (HW_OCOTP_MAC0 >> ((3 - by) * 8)) & 0xFF;
      Serial.printf("MAC: %02x:%02x:%02x:%02x:%02x:%02x\n", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
    }
    
    void setup() {
      // Set the MAC address.
      teensyMAC(mac);
      Ethernet.begin(mac, ip);
    
      // Open serial communications and wait for port to open:
      Serial.begin(115200);
      while (!Serial) {
        ; // wait for serial port to connect. Needed for native USB port only
      }
    
      // Check for Ethernet hardware present
      if (Ethernet.hardwareStatus() == EthernetNoHardware) {
        Serial.println("Ethernet shield was not found.  Sorry, can't run without hardware. :(");
        while (true) {
          delay(1); // do nothing, no point running without Ethernet hardware
        }
      }
      if (Ethernet.linkStatus() == LinkOFF) {
        Serial.println("Ethernet cable is not connected.");
      }
    
      // start listening for clients
      server.begin();
    
      Serial.print("Chat server address:");
      Serial.println(Ethernet.localIP());
    }
    
    void loop() {
      // wait for a new client:
      EthernetClient client = server.available();
    
      // when the client sends the first byte, say hello:
      if (client) {
        while (client.connected()) {
    
          while (client.available() > 0) {
            char c = client.read();
            Serial.write(c);
          }
        }
    
        client.stop();
        Serial.println("Client disconnected");
      }
    }
    C# code
    Code:
    public class LaserConnection
        {
            private Socket _socket;
    
            public LaserConnection()
            {
                var t = Task.Run(async () => await Connect());
                t.Wait();
            }
    
            private async Task Connect()
            {
                IPAddress address = IPAddress.Parse("192.168.1.177");
                IPEndPoint remoteEP = new IPEndPoint(address, 80);
    
                _socket = new Socket(address.AddressFamily,
                    SocketType.Stream, ProtocolType.Tcp);
    
                await _socket.ConnectAsync(remoteEP);
            }
            
            public void Disconnect()
            {
                _socket.Shutdown(SocketShutdown.Both);
                _socket.Close();
            }
    
            public void SendMessage(string message)
            {
                try
                {
                    byte[] msg = Encoding.ASCII.GetBytes(message);
                    _socket.Send(msg);
                }
                catch (Exception)
                {
                    Task.Run(async () => await Connect()).Wait();
                }
            }

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •