Reading UDP Messages with a cycle Time of 500 micro seconds with an Controllino Mega

Hello,
i got a High Performance Converter Maschine from M&P, which controls a synchronous motor. My challenge is it to control the converter using an Controllino Mega.
The converter is sending a UDP-message every 500 microseconds with new values. I can extract the single 20 Bytes of the payload from the incoming UDP-Message to read out the values from the motor (speed, torque ...).

Currently the Controllino is too "slow" to print the values to the serial port, so I get a delay of about 500milliseconds .
How can I improve my code that the Controllino can handle the amount of data ? Is there a way to read for example only every 10th message, to prevent the 500ms delay ?
The actual problem is not that I miss some messages, it is rather that the values show up too late on the serial montior. For example, if the motor is on a rotation angle of 360° and I turn it to an angle of 180° the value shows up 500 ms later on the display of the serial port.

Do you think the Arduino is able to handle this Task ?

Here is my Code for reading the UDP Packets. The magic happens in the void loop(). The other functions are only for analog value for a safety operation with the motor so i think you can ignore that part.

#include <Controllino.h>
#include<SPI.h>
#include <Ethernet.h>
#include <EthernetUdp.h>

#define TIMER_INTERRUPT_DEBUG         0
#define _TIMERINTERRUPT_LOGLEVEL_     0
#define USE_TIMER_3     true

#include <TimerInterrupt.h>

const int EMRM  = CONTROLLINO_R0; //HPC emergency off RM
const int ign   = CONTROLLINO_R1; //HPC ignition
const int STORM = CONTROLLINO_R2; //HPC STO RM

const int inTempA = CONTROLLINO_A0; //temperature bearing A KATT
const int inTempB = CONTROLLINO_A1; //temperature bearing B KATT
const int inTempU = CONTROLLINO_A2; //temperature phase U KATT
const int inTempV = CONTROLLINO_A3; //temperature phase V KATT
const int inTempW = CONTROLLINO_A4; //temperature phase W KATT
const int inTempSh= CONTROLLINO_A7; //temperature shaft KATT

const int inHPCvol = CONTROLLINO_A5; //flow sensor HPC
const int inHPCtemp= CONTROLLINO_A6; //flow sensor temperature

const int HBLED = CONTROLLINO_D23; //heartbeat
const int TimerInterval = 1000; //read temps every second

int tempA = 200;
int tempB = 200;
int tempU = 200;
int tempV = 200;
int tempW = 200;
int tempSh= 200;

int HPCvol  = 0;
int HPCtemp = 0;

bool warnTempBea        = true;
const int  warnTempBeaTres    = 95;
bool critTempBea        = true;
const int  critTempBeaTres    = 105;
bool tempBeaMeasFault   = true;
bool warnTempPhase      = true;
const int  warnTempPhaseTres  = 150; //150
bool critTempPhase      = true;
const int  critTempPhaseTres  = 165; //165
bool tempPhaseMeasFault = true;
bool warnTempShaft      = true;
const int  warnTempShaftTres  = 145;
bool critTempShaft      = true;
const int  critTempShaftTres  = 160;
bool tempShaftMeasFault = true;
bool warnStateTemp      = true;
bool saveStateTemp      = false;

bool toggle = false;
/////////////////////////////////////////////
//Umrichtier Variablen
float UmrechungsfaktorNormiert = 1073741824;// eintspricht 4000 0000 in HEX siehe Handbuch S.23
float BezugwertIstDrehwinkelNormiert = 360; //Bezugwert auf den Normiert wird
float BezugwertIstDrehzahlNormiert = 9549 ; 
float BezugwertIstDrehmomentNormiert = 1;

// UDP SetUP
//bool thisPacketIsNotEmpty = false;
//bool previousPacketIsLoaded = false;

byte mac[] = 
              {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};//Mac Adresse Arudino frei gewählt
IPAddress ip(192, 168, 0, 2);// IP Adresse des PLC

unsigned int localPort = 25000;      // local port to listen on //Port aus dem Handbuch S24

// buffers for receiving and sending data
byte packetBuffer[UDP_TX_PACKET_MAX_SIZE];  // buffer to hold incoming packet,


byte ReplyBuffer[] = "acknowledged";        // a string to send back

// An EthernetUDP instance to let us send and receive packets over UDP
EthernetUDP Udp;


void TimerHandler(void) {
  digitalWrite(HBLED,toggle);
  toggle = !toggle;

  digitalWrite(EMRM,HIGH);
  digitalWrite(STORM,HIGH);
  
  readTempKATT();
  if (saveStateTemp) {
    digitalWrite(ign, HIGH);
  }
  else {
    digitalWrite(ign, LOW);
  }

  readHPCCool();
  
//  printValuesToSerial();
}

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);
  Ethernet.begin(mac, ip);
// 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 UDP
  Udp.begin(localPort);

  pinMode(EMRM,OUTPUT);
  pinMode(ign,OUTPUT);
  pinMode(STORM,OUTPUT);

  pinMode(inTempA,INPUT);
  pinMode(inTempB,INPUT);
  pinMode(inTempU,INPUT);
  pinMode(inTempV,INPUT);
  pinMode(inTempW,INPUT);
  pinMode(inTempSh,INPUT);

  pinMode(inHPCvol,INPUT);
  pinMode(inHPCtemp,INPUT);
  
  digitalWrite(EMRM, LOW);
  digitalWrite(ign, LOW);
  digitalWrite(STORM, LOW);

  pinMode(HBLED,OUTPUT);

  ITimer3.init();
  ITimer3.attachInterruptInterval(TimerInterval, TimerHandler);
  
}

void loop() 

{
 /* while (true) 
  {
    Serial.println("Loop: ");
    thisPacketIsNotEmpty = (Udp.parsePacket() > 0);
 Serial.println(thisPacketIsNotEmpty);
    if (thisPacketIsNotEmpty) { // raise flag that a packet is loaded and read it in the buffer
      previousPacketIsLoaded = true;
      Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    }
    else if (!thisPacketIsNotEmpty && previousPacketIsLoaded) { // if the current packet is empty, but a loaded packet exists, break out of the loop
      previousPacketIsLoaded = false;
      Serial.print("break: ");
      break;
    }
    else { // you should never reach this spot
      
    }
  }*/
// if there's data available, read a packet
  int packetSize = Udp.parsePacket();
  if (packetSize) 
  
  {
    
  
    // read the packet into packetBufffer
   Udp.read(packetBuffer, UDP_TX_PACKET_MAX_SIZE);
    
      
   // Serial.println("Contents:");
    for (int i=0 ; i <= UDP_TX_PACKET_MAX_SIZE ; i++) {
       
    /*  Serial.print("Byte ");
      Serial.print(i);
      Serial.print(" : ");
      Serial.println(packetBuffer[i],BIN);*/
    }
    uint32_t drehwinkel = packetBuffer[16];// 32 bit Variable in die die vier Bytes der Botschaft geschrieben werden sollen 
  drehwinkel <<= 8;
  drehwinkel +=  packetBuffer[17];
  drehwinkel <<= 8;
  drehwinkel +=  packetBuffer[18];
  drehwinkel <<= 8;
  drehwinkel +=  packetBuffer[19];
  float drehwinkelfloat = float(drehwinkel);

drehwinkelfloat= drehwinkelfloat*BezugwertIstDrehwinkelNormiert/UmrechungsfaktorNormiert;

  uint32_t drehzahl = packetBuffer[4];// 32 bit Variable in die die vier Bytes der Botschaft geschrieben werden sollen 
  drehzahl <<= 8;
  drehzahl +=  packetBuffer[5];
  drehzahl <<= 8;
  drehzahl +=  packetBuffer[6];
  drehzahl <<= 8;
  drehzahl +=  packetBuffer[7];
  float drehzahlfloat = float(drehzahl);

//drehzahlfloat= drehzahlfloat*BezugwertIstDrehzahlNormiert/UmrechungsfaktorNormiert;
 uint32_t drehmoment = packetBuffer[8];// 32 bit Variable in die die vier Bytes der Botschaft geschrieben werden sollen 
  drehmoment <<= 8;
  drehmoment +=  packetBuffer[9];
  drehmoment <<= 8;
  drehmoment +=  packetBuffer[10];
  drehmoment <<= 8;
  drehmoment +=  packetBuffer[11];
  float drehmomentfloat = float(drehmoment);

//drehmomentfloat= drehmomentfloat*BezugwertIstDrehmomentNormiert/UmrechungsfaktorNormiert;
/*

Serial.print("Received packet of size ");
    Serial.println(packetSize);
    Serial.print("From ");
    IPAddress remote = Udp.remoteIP();
    for (int i=0; i < 4; i++) 
    {
      Serial.print(remote[i], DEC);
      if (i < 3) 
      {
        Serial.print(".");
      }
    }
 //   Serial.print(", port ");
  //  Serial.println(Udp.remotePort());
Serial.println("Große Packet Buffer:");
    Serial .println(sizeof(packetBuffer));
   */
  // Serial.println("Contents:");
 /*   for (int i=0 ; i <= UDP_TX_PACKET_MAX_SIZE ; i++) {
     Serial.print("Byte ");
      Serial.print(i);
      Serial.print(" : ");
      Serial.println(packetBuffer[i],BIN);
    }*/
 // Serial.println("Drehzahl:");
  //Serial.println(drehzahlfloat); // Raw binary value
  Serial.print("Drehwinkel: ");
  Serial.println(drehwinkelfloat);  // Raw binary value
//  Serial.println("Drehmoment:");
  //Serial.println(drehmomentfloat);  // Raw binary value
 
//Serial.println(packetBuffer[17],BIN);

    // send a reply to the IP address and port that sent us the packet we received
//    Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
  // Udp.write(ReplyBuffer);
 //  Udp.endPacket();
}
// thisPacketIsNotEmpty = false;
  //previousPacketIsLoaded = false;

//delay(500);
}

void readTempKATT(){
  tempA  = analogRead(inTempA)  *0.225;
  tempB  = analogRead(inTempB)  *0.225;
  tempU  = analogRead(inTempU)  *0.3;
  tempV  = analogRead(inTempV)  *0.3;
  tempW  = analogRead(inTempW)  *0.3;
  tempSh = analogRead(inTempSh) *0.54;
  
  if (tempA >= critTempBeaTres || tempB >= critTempBeaTres) {
    critTempBea = true;
  }
  else if (tempA >= warnTempBeaTres || tempB >= warnTempBeaTres) {
    warnTempBea = true;
  }
  else if (tempA >=0 || tempB >= 0) {
    critTempBea = false;
    warnTempBea = false;
    tempBeaMeasFault = false;
  }
  else {
    tempBeaMeasFault = true;
  }

  
  if (tempU >= critTempPhaseTres || tempV >= critTempPhaseTres || tempW >= critTempPhaseTres) {
    critTempPhase = true;
  }
  else if (tempU >= warnTempPhaseTres || tempV >= warnTempPhaseTres || tempW >= warnTempPhaseTres) {
    warnTempPhase = true;
  }
  else if (tempU >= 0 || tempV >= 0 || tempW >= 0) {
    critTempPhase = false;
    warnTempPhase = false;
    tempPhaseMeasFault = false;
  }
  else {
    tempPhaseMeasFault = true;
  }

  
  if (tempSh >= critTempShaftTres) {
    critTempShaft = true;
  }
  else if (tempSh >= warnTempShaftTres) {
    warnTempShaft = true;
  }
  else if (tempSh >= 0) {
    critTempShaft = false;
    warnTempShaft = false;
    tempShaftMeasFault = false;
  }
  else {
    tempShaftMeasFault = true;
  }

  if (!critTempBea && !tempBeaMeasFault && !critTempPhase && !tempPhaseMeasFault && !critTempShaft && !tempShaftMeasFault) {
    saveStateTemp = true;
  }
  else {
    saveStateTemp = false;
  }

  if (!warnTempBea && !warnTempPhase && !warnTempShaft) {
    warnStateTemp = false;
  }
  else {
    warnStateTemp = true;
  }
}

void readHPCCool() {
  HPCvol  = (analogRead(inHPCvol)*0.475)-10.8333;
  HPCtemp = (analogRead(inHPCtemp)*0.5)-16.6666;
}

void printValuesToSerial() {
  Serial.print("A:");
  Serial.print(tempA);
  Serial.print("degC");
  Serial.print("\t");
  Serial.print("B:");
  Serial.print(tempB);
  Serial.print("degC");
  Serial.print("\t");
  Serial.print("U:");
  Serial.print(tempU);
  Serial.print("degC");
  Serial.print("\t");
  Serial.print("V:");
  Serial.print(tempV);
  Serial.print("degC");
  Serial.print("\t");
  Serial.print("W:");
  Serial.print(tempW);
  Serial.print("degC");
  Serial.print("\t");
  Serial.print("Shaft:");
  Serial.print(tempSh);
  Serial.print("degC");
  Serial.print("\t");
  Serial.print("Vdot:");
  Serial.print(HPCvol);
  Serial.print("lpermin");
  Serial.print("\t");
  Serial.print("T:");
  Serial.print(HPCtemp);
  Serial.println("degC");
}

To start with, try using 115200 baud.

1 Like

And you complain about it being slow? That's the slowest baud rate in use today, practically...

1 Like

Why do you need to print so much information out and what will you do with it ?

The printing is only for the beginning to check my programm. At the End the i will not print everthing on the Serial Bus.

Yes this make it quite faster! i didn´t know that there are more possible Baudrates, because in every sketch i found there was everytime 9600 :smiley:

Maybe reading the reference will explain what you can do with Serial.begin :wink: Serial.begin() - Arduino Reference

The golden rule in high speed data acquisition is that the minimum interval that you can collect data must be higher than the time it takes you to "print" the data. So if you "print the data out" and it takes 30 ms to do that, then you can only sample data at more than 30 ms interval. This applies even with buffering and/or DMA because eventually, you'll run out of buffer or you request a new DMA transaction when the previous one is not finished yet

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.