GUI using C# - Serial lags?

Edit: I'm not sure if I should post this here or under "networking" so feel free to move it there.

Hey guys, So I'm trying to make my own GUI for arduino in C#. which basically works fine, except that the longer I leave it running, the more lag I experience between my actions and the updates on my computer. up to tens of seconds.

I only want to view the state/values of the pins on my computer (not send commands back to the arduino), so I'm sending these values via serial.print. My setup is just a basic potmeter on A0.

my arduino code:

int analog0;
int analog1;
// etc

String digital2;
String digital3;
// etc

void setup(){
  Serial.begin(9600);
}

void loop(){
  analog0 = analogRead(A0);
  analog1 = analogRead(A1);
// etc

  digital2 = "D2" + digitalRead(2) ? "high" : "low";
  digital3 = "D3" + digitalRead(3) ? "high" : "low";
// etc

  Serial.print("A0");
  Serial.println(analog0);
  delay(5);
  Serial.print("A1");
  Serial.println(analog1);
  delay(5);
// etc

  Serial.println(digital2);
  delay(5);
  Serial.println(digital3);
  delay(5);
// etc
}

my C# code

        private void Form1_Load(object sender, EventArgs e)
        {
            Arduino.Open();
        }

        private void timer1_Tick(object sender, EventArgs e) // runs every ms!
        {
            String input = Arduino.ReadLine();
            String pin = input.Substring(0, 2);
            String value = input.Substring(1);

            switch (pin)
    {
                    
                case "A0":
                    textBox0.Text = value;
                    break;
                case "A1":
                    textBox1.Text = value;
                    break;
                case "A2":
                    textBox2.Text = value;
                    break;
                default:
                    break;
    }

I hope it's clear what I'm doing: the first two characters define which pin is sending it's values, then the value is printed right after that, followed by a new line. C# reads this and like I said, it works "fine". it's just really slow

I've tried changing the baud rates, the buffer size, the delays, but nothing really works (except delaying by say 1000ms but I want quick updates). decreasing buffer size to 50 bytes improves the speed slightly but still seconds delay.

What is causing this to be so slow? it's not the arduino, which is capable of printing every 5ms, and it shouldn't be my alienware laptop either... is the buffer being clogged or is it something in the C# environment like empty buffer error handling and such?

There's a good chance it's your Strings. Arduino, with its limited RAM, can have issues with Strings. It's best to use strings ( NULL terminated char arrays). Though I see you building your String with literals right before using it. I'd just change some of the logic to only use literals.

Instead of:

 digital2 = "D2" + digitalRead(2) ? "high" : "low";

I'd do:

if (digitalRead(2) == HIGH) Serial.println(F("D2 high"));
else  Serial.println(F("D2 low"));

Far more RAM friendly than Strings. I'd eliminate the Strings and see what happens.

Don't send in either direction faster than the maximum speed of the serial line. If you do, you may encounter congestion at either side. This can cause delayed processing in the Arduino, possibly also causing congestion in the incoming stream. You will be particularly vulnerable to that if processing of an incoming message on either side causes subsequent messages to be transmitted, and the transmitted data size exceeds the received size.

In order to minimise latency you need to ensure that the communication link is [u]never[/u] saturated so that no buffering has to be performed at any time. This means rate-limiting time-driven and event-driven messages so that you never exceed the speed of the connection.

I finally found some more time to work on this. thanks for your replies.

to test both of your recommendations, I made a much smaller sketch, without strings and with a much higher Serial speed. The arduino prints "test" or "push" every 5 ms, C# reads the serial buffer every 5 ms. I really expected this to work, but when I push the button and release it, it takes many seconds before the text changes accordingly.

I have tested the same program with the arduino IDE Serial Monitor, and it runs in real time! this was actually the case in my original sketch as well, so it turns out it wasn't about the strings. something in C# just can't handle serial input every 5 ms.

arduino code:

void setup(){
  Serial.begin(57600);
  pinMode(2,INPUT);
}

void loop(){
  if (digitalRead(2) == HIGH)
  {
    Serial.println("push");
    delay(5);
  }
  else
  {
    Serial.println("test");
    delay(5);
  }
}

C# code:

        private void timer1_Tick(object sender, EventArgs e) // every 5 ms
        {
            if (Arduino.BytesToRead > 0)
            {
                textBox1.Text = Arduino.ReadLine();
            }
        }

I've tried adjusting the delays and the timers. it appears that when I write delay(20) everything works fine. anything below 20 slowly increases the lag. it doesn't matter if I put the C# timer on 1 ms or 20, as long as it's lower than the delay(X) value of course. Updating every 20 ms isn't bad for 1 input channel. but if I want to monitor all the analogs on a Mega, 16*20ms really adds up to 1/3d of a second.

I seem to be stuck. Are there better ways of making a GUI? not using serial?

Your C# code is only checking the serial port at whatever interval you defined, and only read one line each time it checks, so naturally if you send data faster than it is reading it then a backlog will accumulate.

If you replace that ' if (Arduino.BytesToRead > 0)' with ' while (Arduino.BytesToRead > 0)' then it would process all available input every time it ran so there would not be any backlog.

Why are you using a timer in your GUI? You should be using another thread to read the serial port, continuously.

I’ve attached a project I created using C#, that uses threads to deal with serial data, and callbacks to update the user interface.

CommunicateWithArduino.zip (54 KB)

thanks PaulS, that’s a nice file, to be honest I’m not that good with C# yet. however, I’ve used your code and although it works a bit faster, it still accumulates lag… I programmed the arduino to send “a” every 5 ms for a duration of 250 ms, then “b”, then “a” again etc. at the start, it switches nicely, but soon it slows down and when I unplugged the arduino (stopping the serial input) the C# program kept on running (printing a’s and b’s) for about 10 seconds! I’m baffled.
(code:

void loop(){
  for (int i = 0; ; i++){
    if(i % 100 < 50) {
      Serial.println("push");
      delay(5);
    }
    else{
      Serial.println("test");
      delay(5);
    }
  }
}

Jumboman: when I unplugged the arduino (stopping the serial input) the C# program kept on running (printing a's and b's) for about 10 seconds!

Clearly the C# application is not reading the input as fast as the Arduino is writing it. I repeat my suggestion to change your code so that it reads all available serial input each time it executes instead of just reading the first character.

In addition, I'd suggest that you explain the purpose of the program. Sending a single letter 50 times, once every 5 milliseconds, and displaying that letter in a text box on a GUI hardly seems like the thing most people are interested in seeing.

Is there more to what the program will eventually do?