Question about the RMC.Connect and Disconnect methods

I am building a vb.NET application that will interface with my RMC150e controller. I have done some preliminary testing when time permits (when machine is down) and have tested the Connect and Disconnect methods as well as read some values from the controller into some text boxes on my UI. This is all done at the Form.Load event, then at the end of that, I use the RMC.Disconnect method to close the connection. There are some values that need to be read continuously from the RMC to the UI, like actual pressure of the pressure axis for example, to name just one register of several. I am not a polished VB programmer but I can work my way through it. My questions are:

  1. When I create an instance of the RMCLink object on the Form.Load event so that I can initially read the values from the RMC, should I then disconnect and only connect again when I need to read or write a value? For instance, when I want to write new PID values to the tuning registers with a button_click event?
  2. Can multiple instances of RMCLink object have open connections at the same time?
  3. I need to be able to read continuous data from the RMC, like actual pressure of the pressure axis on to a static display text box on the UI. My thoughts are that I will need to make this a multithreaded application in order to make that work. Is this correct? Are there any code examples where data is being read continuously from the RMC?

Thank you,
Don

Don,

  1. Normally, you would open the connection once and leave it open for the entire duration of the application running. When closing a TCP connection, it actually hangs around for a while, and continuously opening and closing can cause the connection queue (not sure if I have the right terminology) to fill up. This is not specific to RMCLink or the RMC, but is part of TCP.

  2. Multiple instances of RMCLink can connect to the RMC. The RMC supports up to 64 simultaneous TCP connections.

  3. Yes, I do believe you would want multithreading so that the GUI interface responds properly. I will check if we have code examples.

Jacob,

Thank you. Good, only having to manage one connection makes things so much easier. I will do one open connection for now and see how that works. I may have to use another connection later when I integrate the Beckhoff embedded PC, but we will see, maybe not. At least I have a good understanding now.

I have some preliminary coding done now for multithreading to test the continuous reading of the axis status register. Going out to the floor to test. Will report back.

Don

I see you have done some work with a multi-threaded solution. I don’t think creating multiple threads is necessary here - there can be some obscure gotchas synchronizing communication between multiple threads.

If the concern were that the UI might “freeze up”, then moving the communication logic to a separate thread would be the way to go. Since we only need to read at say, 1-2Hz (as fast as we can read a changing text box), a simple timer will do.

Here’s a simple solution that uses a timer.

To create the timer-based solution:

  1. Create a Timer – by adding a “Component->Timer” to the form.
  2. Create a Timer Event – by double clicking the “Tick” event in the timer’s property page
  3. It will be called “OnTimerEvent()”
  4. Add this code to OnTimerEvent():
    ' don’t try reading unless we’re connected to the controller
    If rmc.IsConnected(RMCLinkNET.PingType.DoNotPing) = False Then
            Return
    End If

    Try

            Dim data() As Single = New Single(1) {}
            Dim axis As Integer

            ' specify the axis you want to read
            axis = 0

           ' Modify these 2 lines to read the registers you're interested in

            ' Read the Target Position (Fx:53) into data(0).
            rmc.ReadFFile(FileNumber150.fn150StatusAxis0 + axis, 53, data, 0, 1)

            ' Read the Actual Position (Fx:8) into data(1).
            rmc.ReadFFile(FileNumber150.fn150StatusAxis0 + axis, 8, data, 1, 1)

            ' Update the display.
            axisGroup.Text = "Axis " + axis.ToString()
            tarPosValue.Text = String.Format("{0:F3}", data(0))

            tarPosValue.Refresh()

            actPosValue.Text = String.Format("{0:F3}", data(1))
            actPosValue.Refresh()


        Catch ex As ReadWriteFailedException
            MessageBox.Show("Unable to read data. " + ex.Message)

        End Try

That’s all that’s needed to read the data using a timer. And you can simply write the values directly to the form because all of the code is running in the same thread. To start the timer, just call Timer1.Start(). It might be easiest to add a “Start Timer” and a “Stop Timer” button to your form for testing. Just drag them from the ToolBox onto the form.

Double click on the Start/Stop Timer buttons and add this code:

Private Sub StartButton_Click(sender As Object, e As EventArgs) Handles Button1.Click
       
    Timer1.Start()

End Sub

Private Sub StopButton_Click(sender As Object, e As EventArgs) Handles Button2.Click
       
    Timer1.Stop()

End Sub

By default the timer fires every 100ms. You probably can turn that down to 500-1000ms since you’re just displaying textual data.

Once you’re satisfied with the functionality, you could move the Timer.Start()/Timer.Stop() calls to the form load (after connect) and unload (before disconnect) functions so it will start automatically when loaded.

For more information on the .Net timer class, see msdn.microsoft.com/en-us/librar … 10%29.aspx.

Mark -

Thank you for the good feedback and example. I got pulled into a meeting so I wasn’t able to test my multithread solution. I’m still going to test it tomorrow just to see what it does and how it reacts. The timer solution though looks to be the way to go, since that it is pretty easy and keeps things simple. Like you said, I don’t need to update super fast but I’d like it to be >= 2Hz. Will try it tomorrow.

Thanks,
Don

Mark,

I tried both the timer solution and the multithread solution with reading just a few registers. Both are working and appear to be pretty straight forward. Here is the code for the multithread solution:

Public Class frmMain
    Private RMC As RMCLink
    Dim thread1 As System.Threading.Thread = New System.Threading.Thread(AddressOf ReadRegisters)
    thread1.Start()

Private Sub ReadRegisters()
        Dim Axis0Status() As Single = New Single(53) {}

        While RMC.IsConnected(PingType.Ping) = True
            Try
                'Insert all register read code that will be for GUI only, here
                RMC.ReadFFile(FileNumber150.fn150StatusAxis0, 8, Axis0Status, 0, 54)
                numEdt11.Value = Axis0Status(0)
                numEdt12.Value = Axis0Status(1)
                numEdt13.Value = Axis0Status(2)
                numEdt14.Value = Axis0Status(3)
            Catch ex As ReadWriteFailedException
                MessageBox.Show("Unable to read from the controller. " & ex.Message)
            End Try
        End While
 End Sub

This appears to be working and not hanging up the GUI in any way. Not sure what “gotchas” that I will run into that may or may not be an issue.

Thanks,
Don

Don,

Glad to see you have a working solution.

The assignments, like “numEdt11.Value = Axis0Status(0)” are moving data from one thread to another. Sometimes that’s a problem if say the form thread is updating the text field right in the middle of the time the other thread tries write to it. Seems like it’s working - just keep the time solution around just in case :slight_smile:

I don’t know what computer this program is running on, but the loop to read the data is running continuously. It may be reading the data 100s or even 1000s of times per second. That can put a heavy load on the processor re-reading data that the user will never see anyway.

It might pay to put a “Threading.Thread.Sleep(100)” inside the loop to put the thread to sleep for 100ms or so after each loop iteration. That will dramatically decrease the amount of processing power needed to read the data without impacting the display rate perceptibly. Of course, depending on your needs, it may not matter - but if you’re planning on leaving it up 24/7, may as well minimize the processor/power consumption.

Thanks for the multi-threaded code example!

Mark

I will definitely be keeping the timer solution in my back pocket since I still have a lot more testing to do before I feel that the multithread solution will suffice. Good point on the continuous reads inside the while loop potentially dragging down the processor. I didn’t think about that :frowning: . I suppose next time I test it while connected to the RMC, I’ll try looking at the CPU performance inside task manager and see what the difference is. I’m bench testing right now on my laptop, which has an i5-3340 quad core. The program will be deployed to a Beckhoff embedded PC running a quad core i7. I had already planned on isolating one of the cores to handle the HMI project only. Not sure what difference, if any, that will make for the multithreading. On the first test of the multithread reading, I continuously clicked on buttons on the GUI just to see if it would hang or hiccup. It didn’t. Of course, none of the buttons really do anything right now. Good idea with the “thread.sleep” thing. I’ll implement that.

Have a good weekend.

Regards,
Don