Understanding $FAST_CLOCK, BGLogic, and PULSE

  • I'm trying to create a 2s ON 1s OFF signal that I can use for blinking some lights. I wrote the following code and am running in BGLogic.


    Code
       1:  IF ($FAST_CLOCK MOD (3000)<2900),F[30:2s ON 1s OFF]=PULSE,2.0sec ;
       2:  R[10]=$FAST_CLOCK ;
       3:  R[11]=R[10] MOD 3000    ;


    F[30] is only pulsing for about half of the time commanded. I.e, a 2.0sec pulse goes high for 1 second, but if I set it to 4.0sec, I get a 2 second pulse. Why? This is in roboguide, on a R30iA (v7.7).


    I added lines 2 and 3 to help debug and to make sure that $FAST_CLOCK works how I thought it did, and it does... in the virtual world.


    To check and see if the issue is just in Roboguide, I put the exact same program on an RJ3iB I have out in the plant. On that robot, the pulse is 2 seconds as expected, but R[11] takes 12 seconds to count to 3000.


    I have a working solution (changing the pulse to 4seconds), but I'd really like to understand what's going on with this code and why $FAST_CLOCK on the real robot is running so slow.

  • Thanks. I knew it didn't update every millisecond but I had assumed it added 4 to the count every 4 ms. That explains the behavior on the RJ3iB, but I'm still baffled by why it's affecting the pulse output on the R30iA.

  • If you want to do a pulse, maybe you can also try to set and reset the signal directly instead of using the pulse instruction.

    You can do it through 2 conditionals or using a flag to do a flip-flop logic, inverting the signal each time the condition is met.


    As roboguide is executing a virtual machine with the robot software, the timers are likelly software emulated, and timers that are software emulated usually are slower...

    This problem often happen on microcontrollers if hardware timers are not used because code can take different time to execute on every program loop, and if a register is incremented based on software that "timer" is unreliable.

    That is the most probable cause if you see that it works ok on a real controller.

  • Another different aproach is to temporize the signal change as it's done on microcontrollers in order to not use software delays. Example:


    Code
    1: IF ($FAST_CLOCK >= R[10]), JMP LBL[100] ; jump to the code where pulse is generated
    2: JMP LBL[999] ; jump to end if condition not met
    3: ;
    4: LBL[100] ;
    5: F[30:2s ON 1s OFF]=PULSE,2.0sec ;
    6: R[10]=$FAST_CLOCK ; store the current time
    7: R[10]=R[10] + (3000 DIV 4) ; with this we store on R10 the current time + the time that must pass to trigger the next pulse
    8: LBL[999]

    With this method you will be using a register to track the time elapsed since the last time pulse was sent... if you want to generate more pulses with different periods you must use more registers.


    When $FAST_CLOCK surpasses the time stored on that register it will execute the pulse instruction and store on the register the next time to trigger another pulse, this ensures you are executing this code only one time every 3 seconds.

    On your aproach you are checking if the result value of the MOD instruction is betwheen 0-2899, this will run the PULSE instruction several times while the condition is met and may generate an incorrect behaviour...


    If 1 unit on fast_clock is increased every 4ms, you must DIV the time value you add by 4 as in the example.

    Also, if fastclock works that way it makes sense that the value you have on R[11] take 12 seconds to reach 3000, if it takes 4ms to increase the fastclock 1 unit then to reach 3000 it must pass 3000*4ms=12 seconds.



    FAST_CLOCK assuming its stored on a 32bit unsigned integer should overflow after 198 days... so take care with that if you use values from that variable. I suppose fastclock is reset after every powerup to 0.

    Edited 3 times, last by Shellmer ().

  • I like that method, but if you use subtraction only, it will handle the overflow condition.




    1. Store a timestamp into a register:

    R[10]=$FAST_CLOCK


    2. Compare with only subtraction:

    IF ($FAST_CLOCK - 750 > R[10]), ...



    750 = 3 seconds. When using subtraction it will "roll back" the rollover if it occurs.

  • Its another good way to implement it.

    The idea is to avoid triggering several times the same condition, and to do that its needed a register to track time.


    Problem with fast clock and bglogic is that you cant ensure you will catch only one tick of the fastclock on every bglogic loop, so you cant use a = operator on conditionals.

    Instead it should be used one register and an >= or <= so the condition is executed one time even if you miss 4... 8 or 12ms.


    Since fast_clock is likelly tied to a hardware timer on the real controller his value will be incremented even if the cpu is at full load, and a bglogic task is not something that cpu should priorize and can take more time to be executed than the dcs check... or the motion planner, so you can miss ticks of fastclock.



    I suppose the first thing I would try before using that other approach would be an IF ($FAST_CLOCK MOD 12000 = 0) ... but due to the nature of this timer it will not work as you cant ensure you will catch that tick change.

  • I don't understand something on that logic you wrote:


    You are getting the rest from the operation $FAST_CLOCK MOD 3000, that will give a value betwheen 2999-0.

    Then you are dividing by 1000 with the DIV operator, that will result on a value betwheen 2-0.


    If you equal a register to a flag, 0 value will be false, and 1 or some other positive number will be true.

    I understand this and the logic part seems correct, you will have 1/3 of this time the flag at false and 2/3 on true.


    But... since every tick is 4ms, the value obtained on the MOD operation will increase to 3000 on exactly 12 seconds. So if fast clock increases every 4ms one unit you will have that flag on true 8 seconds, and on false 4 seconds.

    Is this correct?? The remark from that flag says "2sec on 1sec off"... and to do that you should MOD by 750 instead of 3000.


    Also, you can get rid of one register if you want, you can replace the "R[10] register on the second line and use the FAST_CLOCK variable directly.

  • Both of you are correct, as usual. Roboguide fast_clock increments every 1ms, but the real robot (R30iA) increments every 2 ms. I did end up cutting out the registers, so my final code on the robot is F[30] = ($FAST_CLOCK MOD 1500 DIV 500)


    Thanks for helping me understand this.

Advertising from our partners