Trigger by encoder suggestions

andepand

Member
Join Date
Jan 2017
Location
Amsterdam
Posts
72
Hi.

I'm programming proffesionally for a couple of years now but every now and then I run in to the following issue of which I'm not sure I'm solving it correctly, or at least in the best way.

I have to trigger a vision camera once every machine cycle, the trigger position changes per production run and can be set within the whole machine cycle. To make adjustments easy for the machine operator I'm using an encoder.
The pulse counter counts up to 100 and is reset by the encoder's Z pulse.
The trigger is set when the pulse counter reaches a value that is set once per production run by the operator.

This way the vision system will take a photo at the required position within the machine cycle.

I use the following (simplified code)

Code:
[COLOR="SeaGreen"](*Set current encoder value to selected trigger variable*)[/COLOR]	
[COLOR="Blue"]IF[/COLOR] Set_mode [COLOR="blue"]AND[/COLOR] Set_pb_oneshot [COLOR="blue"]THEN[/COLOR]
   Trigger_val:= HS_cntrPV; 
   Set_mode:= [COLOR="blue"]FALSE[/COLOR];
[COLOR="blue"]END_IF[/COLOR];

[COLOR="SeaGreen"](*Trigger out*)[/COLOR]
[COLOR="blue"]IF[/COLOR] HS_cntrPV >=Trigger_val [COLOR="blue"]AND[/COLOR] HS_cntrPV <(Trigger_val +10)THEN
  Trigger:= [COLOR="blue"]TRUE[/COLOR]; 
  [COLOR="blue"]ELSE[/COLOR] Trigger:=[COLOR="blue"]FALSE[/COLOR];
[COLOR="blue"]END_IF[/COLOR];

This way there are 10 pulses to evaluate the trigger statement so it can not be missed falling in between scans. (scan time being about 8ms)

The problem with this method is that if the Trigger value is set at, for example, encoder_PV 98 (again, out of 100) then there are only 2 pulses left to evaluate the trigger statement before the pulse counter resets to zero. This can be a problem, since I want to make it as user friendly as possible.

Ofcourse I can put in a whole bunch of IF statements and use a different statement for when the trigger value is set >90 but I feel there must be a better way.


Thanks in advance for the input

Kind regards,
Andy
 
You haven't said what piece of equipment you are programming. If I was doing this on a PLC I wouldn't do it in software, I would us a High Speed Counter and adjust the setpoint of the counter to run an Interrupt when the counter reached its set value. In the interrupt I would trigger the camera.


If I was doing it in software I wouldn't reset the counter every Z pulse, I would let the counter keep counting and store the value at each trigger point, then compare current value plus trigger value to the target value. Using the Z input to check that the encoder is counting correctly.
 
Hi Bryan, thanks for your reply.

Indeed I forgot to mention; currently I'm working with an Omron CP2E brick plc, using CX programmer to program it. Vision system is a Keyence CV-X420 which communicates with the Omron over ethernet/ip.

If you can find the time, could you explain in some more detail how your non-software solution would work?

Also for the software solution: "store the value at each trigger point" how would be determined if the trigger point is reached? Also, what would happen when the counter adress reaches it's maximum value?

Regards,
Andy
 
Last edited:
Code:
Trigger_val := whatever;     [COLOR=blue][B](* e.g. 10, or 95 *)[/B][/COLOR]

[COLOR=Blue][B](* Create one range upward from Trigger_val *)[/B][/COLOR]

Trigger_val_p10 = Trigger_val + 10   [COLOR=blue][B](* e.g. 20, or 105 *)[/B][/COLOR]

[COLOR=blue][B](* Create second range downward, starting with upper limit *)[/B][/COLOR]

Trigger_val_high := Trigger_val_p10;   [COLOR=blue][B](* 20, or 105 or ... *)[/B][/COLOR]

IF Trigger_val_p10 > 99 then
  Trigger_val_high := Trigger_val_p10 - 100;  [COLOR=blue][B](* ... 5 *)[/B][/COLOR]
END_IF;[COLOR=blue][B]

(* Lower limit of second range *)[/B][/COLOR]

Trigger_val_high_m10 := Trigger_val_high - 10;  [B][COLOR=blue](* 10, or -5 *)[/COLOR][/B][COLOR=blue][B]

(* if Trigger_val is 20, then test against [10:20) OR [10:20) *)
(* if Trigger_val is 95, then test against [95:105) OR [-5:5) *)[/B][/COLOR]

Trigger := (HS_cntrPV >= Trigger_val AND HS_cntrPV < Trigger_val_p10)
           OR
           (HS_cntrPV >= Trigger_val_high_m10 AND HS_cntrPV < Trigger_val_high);
 
I checked the manual and the CP2E does have High Speed Counters
https://assets.omron.eu/downloads/manual/en/v5/w614_cp2e_software_users_manual_en.pdf
Section 10 covers Interrupts, section 11 cover High Speed Counters



There is a tutorial on setting up a High Speed Counter:
https://www.youtube.com/watch?v=jWGlXCa7DLs


I haven't used the CP2E or CX Programmer so I can only speak in general terms. A High Speed Counter (HSC) works outside of the normal program loop, so it can count inputs a lot more quickly than a normal counter, it is designed for use with Encoders. Once the HSC reaches a Set Point it calls an Interrupt. An Interrupt is exactly how it sounds, it interrupts the normal program loop, runs some software and then returns control to the main loop. I don't know if the CP2E allows you to alter the HSC target value whilst the program is running. But for a Siemens PLC I would set up a HSC, it would reach its Set Point, Interrupt the main program loop and pass control to an Interrupt sub routine. In the Interrupt routine I would tell the camera to operate, calculate the new Set Point for the HSC, transfer the new Set Point and Reset the Current Value. Then return control to the main loop.


Using a software system you will always be limited by the speed of your main program loop. At a camera trigger value you would store the current value, add the number of counts for the next triggering point which would give you the next target value. Yes it can be a problem if you go beyond the counters maximum value, but in a real world situation it isn't usually too much of an issue. If you use an unsigned 32 bit Integer value it has a maximum value of 2,147,483,647. If your process triggered with a 100 count every second that would still be 357,913 minutes before you hit maximum, or 248 hours, or 10 days. So you just need to make sure that you reset the system before that happens, often a factory gets powered down at the weekends, which would solve it for you, otherwise you just need to catch it a trigger point.


You don't have to use the Z input to reset the counter, you can reset the counter at your trigger point through software. I would use the Z input with another interrupt so that you can check that the counter is counting correctly.


The Z channel doesn't have to be used to Zero a count:
https://www.usdigital.com/news/post...MIwI3gjtiC7wIVkt_tCh3xsQeFEAAYASAAEgLdyvD_BwE
 
Last edited:
Assuming your rollover value is 100 as it seems, then if your trigger_pos is > 100 then just minus 100 from trigger_pos, if it isn't then trigger_pos = trigger_pos.

If actual_pos >= triger_pos then TRIGGER!!!!
 
Code:
Trigger_val := whatever;     [COLOR=blue][B](* e.g. 10, or 95 *)[/B][/COLOR]

[COLOR=Blue][B](* Create one range upward from Trigger_val *)[/B][/COLOR]

Trigger_val_p10 = Trigger_val + 10   [COLOR=blue][B](* e.g. 20, or 105 *)[/B][/COLOR]

[COLOR=blue][B](* Create second range downward, starting with upper limit *)[/B][/COLOR]

Trigger_val_high := Trigger_val_p10;   [COLOR=blue][B](* 20, or 105 or ... *)[/B][/COLOR]

IF Trigger_val_p10 > 99 then
  Trigger_val_high := Trigger_val_p10 - 100;  [COLOR=blue][B](* ... 5 *)[/B][/COLOR]
END_IF;[COLOR=blue][B]

(* Lower limit of second range *)[/B][/COLOR]

Trigger_val_high_m10 := Trigger_val_high - 10;  [B][COLOR=blue](* 10, or -5 *)[/COLOR][/B][COLOR=blue][B]

(* if Trigger_val is 20, then test against [10:20) OR [10:20) *)
(* if Trigger_val is 95, then test against [95:105) OR [-5:5) *)[/B][/COLOR]

Trigger := (HS_cntrPV >= Trigger_val AND HS_cntrPV < Trigger_val_p10)
           OR
           (HS_cntrPV >= Trigger_val_high_m10 AND HS_cntrPV < Trigger_val_high);

Thanks, this would work Indeed. I used something similar earlier but it seemed a bit cumbersome to me.
 
I checked the manual and the CP2E does have High Speed Counters
https://assets.omron.eu/downloads/manual/en/v5/w614_cp2e_software_users_manual_en.pdf
Section 10 covers Interrupts, section 11 cover High Speed Counters



There is a tutorial on setting up a High Speed Counter:
https://www.youtube.com/watch?v=jWGlXCa7DLs


I haven't used the CP2E or CX Programmer so I can only speak in general terms. A High Speed Counter (HSC) works outside of the normal program loop, so it can count inputs a lot more quickly than a normal counter, it is designed for use with Encoders. Once the HSC reaches a Set Point it calls an Interrupt. An Interrupt is exactly how it sounds, it interrupts the normal program loop, runs some software and then returns control to the main loop. I don't know if the CP2E allows you to alter the HSC target value whilst the program is running. But for a Siemens PLC I would set up a HSC, it would reach its Set Point, Interrupt the main program loop and pass control to an Interrupt sub routine. In the Interrupt routine I would tell the camera to operate, calculate the new Set Point for the HSC, transfer the new Set Point and Reset the Current Value. Then return control to the main loop.


Using a software system you will always be limited by the speed of your main program loop. At a camera trigger value you would store the current value, add the number of counts for the next triggering point which would give you the next target value. Yes it can be a problem if you go beyond the counters maximum value, but in a real world situation it isn't usually too much of an issue. If you use an unsigned 32 bit Integer value it has a maximum value of 2,147,483,647. If your process triggered with a 100 count every second that would still be 357,913 minutes before you hit maximum, or 248 hours, or 10 days. So you just need to make sure that you reset the system before that happens, often a factory gets powered down at the weekends, which would solve it for you, otherwise you just need to catch it a trigger point.


You don't have to use the Z input to reset the counter, you can reset the counter at your trigger point through software. I would use the Z input with another interrupt so that you can check that the counter is counting correctly.


The Z channel doesn't have to be used to Zero a count:
https://www.usdigital.com/news/post...MIwI3gjtiC7wIVkt_tCh3xsQeFEAAYASAAEgLdyvD_BwE

I am using a high speed counter, Omron calls it the PRV instruction. That's what writes the present high speed counter value to a desired adress.
After reading your post I remembered something about comparison tables/Interrupts. I have to find the manual and read into that.

I never considered that letting the counter run without cyclic reset would be a better option, that's definitely something to check


About Interrupts, I kinda stopped using those, but perhaps for all the wrong reasons.
I work with machines which have 30+ stations on them, each with their own differently rotated shaft and functions happening at certain shaft positions. It has one base encoder as a reference for all these shafts.
Interrupting the program so many times will push the scan time quite a bit.

For example, this is just a small part of what's going on:
Code:
(*7.4 Feeder shaft positions*)

            FOR L_15:=  1 TO 31 DO

                        

                        IF Machine_running AND Feeder_aut_in[L_15] THEN

                                    

                                    IF Fdr_cycle[L_15] THEN Fdr_zero_pos[L_15]:= HS_cntr_pv;  (*Current main encoder position at feeder cycle sensor*)             

                                    END_IF;

                                    

                                    (*Curent feeder shaft position: main encoder counts from fdr 1pp/c*)

                                    IF (HS_cntr_pv -Fdr_zero_pos[L_15]) >=0 THEN                                   

                                               Fdr_shaft_pos[L_15]:= (HS_cntr_pv -Fdr_zero_pos[L_15]);        

                                    ELSIF (HS_cntr_pv -Fdr_zero_pos[L_15]) <0 THEN

                                               Fdr_shaft_pos[L_15]:= ((HS_cntr_pv +100) -Fdr_zero_pos[L_15]);         

                                    END_IF;

                                    

                                    (*Feeder product detect window*)

                                    IF (Fdr_shaft_pos[L_15] >=Detect_start_set[L_15]) AND (Fdr_shaft_pos[L_15] <(Detect_start_set[L_15] +10)) THEN                

                                               Detect_win[L_15]:= TRUE;

                                    ELSE Detect_win[L_15]:= FALSE;

                                    END_IF;

                                    

                                    (*Feeder product detect end*)

                                    IF (Fdr_shaft_pos[L_15] >(Detect_start_set[L_15] +10)) AND (Fdr_shaft_pos[L_15] <(Detect_start_set[L_15] +20)) THEN

                                               Detect_end[L_15]:= TRUE;

                                    ELSE Detect_end[L_15]:= FALSE; 

                                    END_IF;

                        END_IF;

            

            END_FOR;

Sorry for the messed up alignment
 
Last edited:
Thanks, this would work Indeed. I used something similar earlier but it seemed a bit cumbersome to me.


d'Oh! I just realized that can all be done with a far simpler, one-statement equivalent implementation:



Code:
[COLOR=Blue][B](* Assumes HS_cntrPV will always be in the range [0:99] *)[/B][/COLOR]

Trigger := (HS_cntrPV >= trigger_val && HS_cntrPV < (trigger_val+10))
           OR
           (HS_cntrPV < (trigger_val-90));
 
Interrupting the program so many times will push the scan time quite a bit.
You probably need to think about your logic here. If something already happens a number of times within a program scan, why would an interrupt make the scan longer. If things don't happen every scan then running the code in an interrupt means it only happens when needed, saving you scan time. Unless you need to keep to a fixed scan time it is better to just run the bits of a program that need to run. That doesn't have to be using Interrupts, it can also be using conditional calls to subroutines.


The code in an Interrupt can be as simple and quick as setting a Flag, then you pass control back to the main loop, and it runs code when it sees the flag is set. In fact Interrupts should always be as simple as possible.
 
If you trigger on a range of counts it will be possible to trigger more than once. This may be OK but I would use a one shot approach where the trigger is armed until it counts exceed the trigger counts but then the trigger armed is cleared. This way the is only one trigger event instead of multiples when the encoder is moving slowly.
 
HSC with hardware interrupt is the approach I would take without any hesitation.
Scan Time is not sacrosanct; it whould be weighed against the objective/performance you want to achiev. As Bryan stated, the logic could be as short as a a couple of microseconds(probably plus the overhead of block execution), that's negligible.
 
I keep thinking about this. Any chance you could share a scenario to clarify what you meant. Doesn't have to be in the context of this thread (hijack!); a scenario where "context switching" and its effects is best explained.


Thanks
Every time there is an interrupt, the interrupts are turned off and all the CPU registers will be used by the interrupt must stored on the stack. When the interrupt is done the original values of the registers that we used are restored from the stack ( popped ). Usually restoring the flags registers will enable the interrupts again. Using this method there is no possibility of getting another interrupt during an interrupt. However it is possible to get one interrupt after another with no time left to do normal work. If there are multiple events that get triggered by the same encoder count it would be best to process them all in the same interrupt.

This is not a context switch. It is a simple store and restore.

A context switch occurs when an interrupt enables a waiting higher priority task.
This is not the case with most PLCs.

The handling interrupts is tricky. PLC programmers don't see the complexity.
If the interrupt is long then it may be wise to enable higher priority interrupts within the interrupt routine so a higher priority interrupt may occur. This open the possibility of getting interrupts inside of other interrupts. Each time the registers are stored on the stack. The must be enough stack space allocated to handle many levels of interrupts.

BTW
Code:
      if armed then
            if counts >= trigger_counts then
                  trigger := true;
                  armed := false
      else
           trigger := false;
           if count < trigger_counts then
                 armed := true;
      end_if
This method makes sure the trigger is set only once per revolution. I don't see the need for check for counts over 100 when they are reset by the z pulse so the range of counts is 0-99.
 

Similar Topics

I am running into some problems trying to trigger a camera to take a picture every 15 degrees when I spin the part I am looking at one full...
Replies
6
Views
3,613
Hi i would like to ask! Im using Omron CP1E PLC May i know how to use one input to trigger two outputs alternatively? Meaning press X0 on, Y0...
Replies
11
Views
389
Hi all, I use e won for my OPCUA to back up my PLC (B&R X20 system) data. Whenever e won does maintenance updates, I need to reboot the e won in...
Replies
2
Views
466
Hello ladies and gents I’ve hit a road block on a project, it’s AB for preface this is a converting line including Winder tailsealer and...
Replies
4
Views
762
Hi, I'm using CX Programmer and just seeing what the best way to trigger an output from the plc clock time would be. I need this to come on at 9am...
Replies
4
Views
1,729
Back
Top Bottom