1

I have a code with which I am reading in 35ms intervals the current and position values of a machine's CNC axis from a remote computer.

The data is read from the CNC/PLC control system of the machine

My C# code has to run on our company server with Windows Server 2019. I am sending the data to Kafka, our AI experts have to interpret the current and position curve shapes for an AI algorithm. So the data has to be read every 35 ms as precise as possible

Normally I have used first a system timer with a 35ms period. It seems to work but I am not sure if this is the best way. Is there a more precise method than using a system timer?

My code

 public void Main()
 {
 InitializeTimer_1();
 }
  public void InitializeTimer_1()
    {
        System.Timers.Timer timer1 = new System.Timers.Timer();
        timer1.Elapsed += new ElapsedEventHandler(OnTimedEvent1);
        timer1.Interval = 35;
        timer1.Enabled = true;
    }

  public void OnTimedEvent1(object sender, EventArgs e)
    {
        // my Data reading code
    }
Vivek Nuna
  • 25,472
  • 25
  • 109
  • 197
Mdarende
  • 469
  • 3
  • 13
  • 1
    "_So the data has to be read excactly every 35 ms._" How exact is "_exactly_"? Assuming it is very _exact_ and you really need "_the most precise way_", use a RTOS then. That means, Linux and Windows are out of the window (hah!). MacOS as well. And .NET, too. Unless you are overstating your needs here, your best way forward would probably to figure out a way to configure the software on that "remote computer" to send position values together with a time stamp (with ms resolution). Then there would be no need to pull the data from the remote computer in exact 35 ms intervals anymore. –  Dec 18 '22 at 13:25
  • Related: [High resolution timer in C#](https://stackoverflow.com/questions/24839105/high-resolution-timer-in-c-sharp?noredirect=1&lq=1) – Theodor Zoulias Dec 18 '22 at 13:33
  • @MySkullCaveIsADarkPlace Unfortunately I cannot run a code directly on the machines control system. Because there are some barriers like, the OS on the IPC's are very old (Win XP) and also it is not wanted to do that. Additionaly our applications hast to run on our official company servers, which are all Windows Server 2019. So I have to live with that limitation. – Mdarende Dec 18 '22 at 13:33
  • Well, Win XP itself is not a RTOS, so basically that means "not very exact" and "not the most precise way" (with respect to millisecond resolution). Because even if you were to manage to do the read attempts in .NET in precise 35 ms intervals, Windows XP itself (and the driver stacks involved in the communication) will take a variable amount of time to prepare and send back the response which could possibly be in the lower millisecond range, considering the age the IPC must be if it is running XP. –  Dec 18 '22 at 13:38
  • @MySkullCaveIsADarkPlace. Sorry I have to explaine a little bit more: The data is read from the PLC of the machine (Siemens S7-300). I have no possibility to write I code inside the PLC. The machine has a IPC with Windows XP that is communicating with the PLC. – Mdarende Dec 18 '22 at 13:41
  • Okay, i see. Perhaps you could state the deviation from the perfect 35 ms interval your application scenario would tolerate. Because without an RTOS, and using an OS like Linux/Windows/MacOS, there will be unavoidable deviations from the perfect 35 ms interval that might or might not be a problem for you. There might even be huge interruptions depending on the hardware setup and the software configuration on the machine you intend to run your software on. –  Dec 18 '22 at 13:42
  • 1
    Generally speaking with regard to .NET, be aware of garbage collection, which, depending on the demands by and the deviations tolerable to your application scenario, might (or might not) require certain mitigation strategies in your code, or might in the worst imaginable case make .NET unsuitable for your purposes entirely.... –  Dec 18 '22 at 13:48
  • @viveknuna Sorry, but I really didn't downvoted it. :-) – Mdarende Dec 18 '22 at 13:50
  • You'll probably want some tiny microcontroller as close to the plc as possible to create a timestamped log. Then serialise that data back to your end in larger blocks. – Jeremy Lakeman Dec 20 '22 at 06:25

2 Answers2

0

There are multiple ways to solve this problem.

It first depends on what kind of application you have.

If you have a console app then you can schedule it to run every 35ms using the windows task scheduler and it will work.

If it is a long-running process like windows service then you can use the same code you have

There is one very useful library hangfire, you can explore this as well.

Also, refer to this post as well, you may get more directions.

Edit: System.Timers.Timer is sufficient for most the purpose, you could also consider System.Threading.Timer for short intervals, it allows more precise timings but its will run on a separate thread so keep that in mind. There is one more option System.Diagnostics.Stopwatch which has more high precision than other approaches.

The actual precision of the timer also depends on hardware, OS and the workload on the machine.

Now you can evaluate all the approaches and chose the best one for you.

Vivek Nuna
  • 25,472
  • 25
  • 109
  • 197
  • One question regarding hangifre: I am using windows service, because I want that my app should run even if nobody is logged in our company server. Can I achieve this also with hangfire? I mean without logging in, the app should run after each restart of the server automatically. – Mdarende Dec 18 '22 at 14:46
  • @Mdarende yes you can – Vivek Nuna Dec 18 '22 at 14:47
  • @Mdarende I have improved my answer, if it's useful then please accept otherwise I will delete it – Vivek Nuna Dec 20 '22 at 05:25
  • 1
    Thank you so much, Now I know the related alternatives, will accept your answer – Mdarende Dec 20 '22 at 09:47
-1

The timer accepts a direct callback method. If you want to execute something periodic, it can be done as follows:

var timer = new Timer(TimerCallback, state, startAfterTimeSpan, repeatTimeSpan);

Where you can e.g. write a method

private void TimerCallback(object state)
{
    // do something
}
Roland Buergi
  • 1,157
  • 9
  • 23