Tarasik (Customer) asked a question.

BRX and Arrays.

Hello everyone, I have built a graph on my PC based on two values from the AI of the BRX controller. The communication between the BRX and my PC is established through Modbus, and the pool rate is 10Hz. I'm satisfied with the results so far, but now I need to increase the speed of obtaining values by ten times. This means that I need the time between points on my graph to be 10mS instead of the current 100mS. To accomplish this, I intend to transfer two arrays, each containing 10 input values, from the BRX to the PC. The idea is to increment the index and update the MHR registers with the latest values every 10mS. I'm familiar with how to do this in LabVIEW or "C" language, but I'm not sure how to do it in the controller. Can anyone provide me with some examples of how to work with arrays? Maybe I am asking for too much from the BRX controller, but I would appreciate any guidance or advice. Thank you


  • HOST_franji1 (HOST Engineering)

    Array indexes are V memory locations, so say you use V42 as your array index, MHR[V42] would reference the MHR location of the value in V42. So if V42 equaled 99, then MHR[V42] would be MHR99, or Modbus Holding Register 40099.

     

    Have V42 start at 1 (so Holding Register 40001) and go to 10 (40010) (or whatever range you think you need)

     

    Have an auto-resetting 10ms TMR that increments V42 every time it is .Done and copies the AI value into MHR[V42]. When V42 goes to 11, set it to 1.

     

    Not sure how you synchronize the Master polling - you will lose or duplicate entries. Possibly have 2 buffers that you pingpong between, with a MI that you toggle every time one of the buffers is "done". Then your PC just monitors that Modbus Input bit, and when it changes, read the buffer related to its state (e.g. MI1 equal to OFF means 40001 thru 40010 is done, ON means 40011 thru 40020 is done). It complicates the logic a little bit on both ends. You may have already thought this out, so just ignore this if you know you're ok.

     

    If you don't need to monitor "real time", look at FILELOG with the RAMDRIVE file system - it can probably keep up with logging every 10ms in "bulk". You probably would want to pingpong 2 files for the same reason you need to pingpong 2 arrays.

    Expand Post
    Selected as Best
  • HOST_franji1 (HOST Engineering)

    Array indexes are V memory locations, so say you use V42 as your array index, MHR[V42] would reference the MHR location of the value in V42. So if V42 equaled 99, then MHR[V42] would be MHR99, or Modbus Holding Register 40099.

     

    Have V42 start at 1 (so Holding Register 40001) and go to 10 (40010) (or whatever range you think you need)

     

    Have an auto-resetting 10ms TMR that increments V42 every time it is .Done and copies the AI value into MHR[V42]. When V42 goes to 11, set it to 1.

     

    Not sure how you synchronize the Master polling - you will lose or duplicate entries. Possibly have 2 buffers that you pingpong between, with a MI that you toggle every time one of the buffers is "done". Then your PC just monitors that Modbus Input bit, and when it changes, read the buffer related to its state (e.g. MI1 equal to OFF means 40001 thru 40010 is done, ON means 40011 thru 40020 is done). It complicates the logic a little bit on both ends. You may have already thought this out, so just ignore this if you know you're ok.

     

    If you don't need to monitor "real time", look at FILELOG with the RAMDRIVE file system - it can probably keep up with logging every 10ms in "bulk". You probably would want to pingpong 2 files for the same reason you need to pingpong 2 arrays.

    Expand Post
    Selected as Best
  • Tarasik (Customer)

    Got it! I understand this part. Thank you! Now, I'm trying to figure out how to synchronize everything. The BRX sends the data immediately after receiving a request from the PC, without checking whether the data is ready or not. I'm wondering if there is any way I can control the transmission through software. For instance, if the data is ready, I can set a flag. If the request from the PC comes and the flag is not set, I can wait a couple of milliseconds till it is ready. After the data is sent, I can reset the flag. I use a similar approach in my projects when programming ARM controllers to achieve synchronization. However, this is in the C language where there is more control.

    Expand Post
    • HOST_franji1 (HOST Engineering)

      That was my point about the bit and 2 buffers.

       

      C pseudo code

      1. // buffer indicator (Modbus Input 10001) is a bit where 0 means buffer is 40001 thru 40010, 1 means 40011 thru 40021
      2. //
      3. int iLastBuffer = -1;
      4. while (true)
      5. {
      6. int iCurrentBuffer; // read the bit as an integer?
      7. ReadModbusInput(10001, &iCurrentBuffer);
      8. if (iCurrentBuffer != iLastBuffer)
      9. {
      10. unsigned short usHoldingAddr = (iCurrentBuffer == 0) ? 40001 : 40011;
      11. unsigned short wValues[10];
      12. ReadMultipleModbusHoldingRegisters(usHoldingAddr, wValues, 10);
      13. // process wValues
      14. iLastBuffer = iCurrentBuffer;
      15. }
      16. Sleep(10);
      17. }

       

      Expand Post
      • HOST_franji1 (HOST Engineering)

        The "current buffer" from the C program (client) means the one that is ALREADY FILLED. While in the PLC, the "current buffer" meaning the one that it is CURRENTLY FILLING is the "other" buffer. You may want to change my terminology from "current" to "filled" vs. "pending" (same meaning on both client and server).

  • Tarasik (Customer)

    I looked at the code and read your first message more carefully and now I understand everything. You made my day! Thanks!

  • Tarasik (Customer)

    Hello Everyone,

    I have implemented the double buffer technique, which has been working well, except for one issue. I have two independent double buffers and two channels connected in parallel for experimentation. Quick change of the input signal. The kinks in the graph are clearly visible every 10ms for the first channel (built-in BX-DM1E-10 ED 13). However, for the second channel (connected to BX-16AD-2B), the kinks follow after 30-50ms. Although, in the end, the graphs match.

    I have swapped the buffers and connected both channels to the BX-16AD-2B, and I have concluded that digitization in the module is slower than in the PLC. I hope this conclusion is wrong, but the experimental results show otherwise.

    I have a question: Does the speed of digitization depend on the number of "slots" in which the analog module is installed? In my configuration, two analog modules are installed: PLC BX-DM1E-10ED-13 then BX-08DA-2B then BX-16AD-2B.

     

    P.S. I need to measure the time between the supply of power to the solenoid (pressure supply) and the start of the actuator movement. The time frame is 10-30 mS That's why the requirements are so strict. I'm trying to assign this task to a PLC instead of equipment from National Instrument

    Thank you.

    Expand Post
  • Tarasik (Customer)

    Thank you for your explanation.

    You're right. To confirm, here is a screenshot of the real graph that I mentioned in the previous post, where two channels are connected in parallel.

     

    Graph zoomCh1 - Blue line (PLC)

    Ch2 - Red line (BX-16AD-2B)

     

    In the future, I will need to read the specification carefully... It's just that initially such tasks were not set. For now, I decided to use a digital input instead of the analog signal of the second channel (solenoid), connect the button to the analog input, and use the released digital for the graph. I think it should work. The average scan time is around 1mS max - 2.2mS. By the way, it would be interesting to read somewhere which operations are the most time-consuming. (PID, Publish math? etc.) Also when creating a new Code-block, the default yield value is set to 100uS. I do not understand which number is optimal for different tasks.

     

    Expand Post
    • HOST_franji1 (HOST Engineering)

      You mentioned PID, so tuning your .TimeSlice is kind of like tuning a PID. It's trade offs between I/O Logic scan times (control) vs. Calendar Time of the looping algorithm. The more time you spend inside a loop every PLC scan, the faster the loop will finish (but the slower PLC logic I/O scan).

       

      I wrote a sample Bubble Sort program that sorts 1,000 values. Bubble Sort is SLOW, using two nested FOR/NEXT loops (so 1,000,000 comparisons on non-optimized Bubble Sort algorithm).

       

      You can tweak the .TimeSlice to 0 where the Bubble Sort tasks out EVERY PLC scan. That means it will take 1,000,000 PLC scans (say 1msec PLC scan, that's 1,000 seconds in "calendar" time to finish the "sort" code block). Sure, you have a "fast" scan at 1ms, but your algorithm is SLOW. Bump the .TimeSlice up to 100uSec, what's the trade off? 1.1ms PLC scan, but now your inner loop is executing a BUNCH of times every logic scan so the Calendar Time is reduced greatly. Set .TimeSlice to 50ms (50,000uSec) and the Calendar Time is practically minimized, but your scan time just went to 51ms!

       

      Here's a link to that sample program so you can get a feel for how it works. I recommend trying it on real hardware - the Simulator "scan times" (multi gigahertz processor on a PC) doesn't provide the best test case.

      Example: Perform Bubble Sort on numeric data (hosteng.com)

       

      *** EDIT *** My example of 100ms can't be done - the .TimeSlice is an UNSIGNED 16 BIT WORD, so max value is 65K (not 100K), so I changed the example .TimeSlice to 50mSec (50,000 uSec).

      Expand Post
  • Tarasik (Customer)

    Thank you for providing me with a detailed explanation. I am interested in checking out your example, but it seems that downloading it requires registration. I have already filled out the registration form, but I haven't received any email yet to validate my email (I have checked my spam folder as well). It has been several hours since I submitted the form, and I am still waiting for the confirmation email.