Trigger by encoder suggestions

Thanks andepand.
...
You stated a line speed of 20,000 parts per hour and the distance between parts is 1000 Pulses which is equivalent to one encoder revolution. (These are amazingly *square* numbers).
That would give you roughly 5 pulses per millisecond.
What is you scan cycle?

From Post #28: 5ms, so ~28pulses/scan

Also from the same post:
...
I have to add that the camera trigger doesn't have to be accurate to a single encoder pulse. The vision system has a wide image and can look for the code in sort of a big area.
>20 pulses might become a problem though.

Hmmm.
 
Random musings. TL;DR:

In an earlier post, OP provided this sample (variable names have been shortened):
Code:
[COLOR=blue](* 7.4 Feeder shaft positions *)

(* Hcp is HS_cnt_pv *)
(* Fzp is Fdr_zero_pos *)
(* Fsp is Fdr_shaft_pos *)
(* Dss is Detect_start_set *)
[/COLOR]
FOR L_15 := 1 TO 31 DO

  IF Machine_running AND Feeder_aut_in[L_15] THEN

    [COLOR=Blue](* Current main encoder position at feeder cycle sensor *)[/COLOR]
    IF Fdr_cycle[L_15] THEN
      Fzp[L_15] := Hcp;
    END_IF;

    (* Curent feeder shaft position: main encoder counts from fdr 1pp/c *)
    IF (Hcp - Fzp[L_15]) >= 0 THEN
      Fsp[L_15] := (Hcp - Fzp[L_15]);
    ELSIF (Hcp - Fzp[L_15]) < 0 THEN
      Fsp[L_15] := ((Hcp + 100) - Fzp[L_15]);
    END_IF;

[COLOR=blue]    (* Feeder product detect window *)[/COLOR]
    IF (Fsp[L_15] >= Dss[L_15]) AND (Fsp[L_15] < (Dss[L_15] + 10)) THEN
      Detect_win[L_15] := TRUE;
    ELSE
      Detect_win[L_15] := FALSE;
    END_IF;

[COLOR=blue]    (* Feeder product detect end *)[/COLOR]
    IF (Fsp[L_15] > (Dss[L_15] + 10)) AND (Fsp[L_15] < (Dss[L_15] + 20)) THEN
      Detect_end[L_15] := TRUE;
    ELSE
      Detect_end[L_15] := FALSE;
    END_IF;

  END_IF;

END_FOR;
First of all, the ELSEIF...THEN should be ELSE, because
if the main IF clause is FALSE,
then the ELSIF clause *must* be TRUE

Then, each of those IF...END_IF statements can be reduced to one line,
resulting in the following equivalent cleaner code:

Code:
[COLOR=blue](* 7.4 Feeder shaft positions *)

(* Hcp is HS_cnt_pv *)
(* Fzp is Fdr_zero_pos *)
(* Fsp is Fdr_shaft_pos *)
(* Dss is Detect_start_set *)[/COLOR]

FOR L_15 := 1 TO 31 DO

  IF Machine_running AND Feeder_aut_in[L_15] THEN

[COLOR=blue]    (* Current main encoder position at feeder cycle sensor *)[/COLOR]
    IF Fdr_cycle[L_15] THEN
      Fzp[L_15] := Hcp;
    END_IF;

[COLOR=blue]    (* Current feeder shaft position: main encoder counts from fdr 1pp/c *)[/COLOR]
    Fsp[L_15] := ((Hcp + 100) - Fzp[L_15]) MOD 100;

[COLOR=blue]    (* Feeder product detect window *)[/COLOR]
    Detect_win[L_15] := (Fsp[L_15] >= Dss[L_15]) AND (Fsp[L_15] < (Dss[L_15] + 10));

[COLOR=blue]    (* Feeder product detect end *)[/COLOR]
    Detect_end[L_15] := (Fsp[L_15] > (Dss[L_15] + 10)) AND (Fsp[L_15] < (Dss[L_15] + 20));
[COLOR=blue]    (* N.B. the previous > above should probably be >= *)[/COLOR]

  END_IF;

END_FOR;
But that is all beside the point, because I want to focus on these statements:
Code:
[COLOR=Blue][COLOR=blue](* Hcp is HS_cnt_pv *)[/COLOR][/COLOR][COLOR=Blue][COLOR=blue]
(* Fzp is Fdr_zero_pos *)[/COLOR][/COLOR]
[COLOR=Blue][COLOR=blue](* Fsp is Fdr_shaft_pos *)[/COLOR][/COLOR]
[COLOR=Blue][COLOR=blue]...[/COLOR][/COLOR][COLOR=Blue]

    (* Current main encoder position at feeder cycle sensor *)[/COLOR]
    IF Fdr_cycle[L_15] THEN
      Fzp[L_15] := Hcp;
    END_IF;

[COLOR=blue]    (* Current feeder shaft position: main encoder counts from fdr 1pp/c *)[/COLOR]
    Fsp[L_15] := ((Hcp + 100) - Fzp[L_15]) MOD 100;
It appears that, when Fdr_cycle is TRUE, that is the time to get define a zero offset - Fzp (Feeder zero position?) - for the Fzp-relative calculation of Fdr_shaft_pos (Feeder shaft position?) that follows.

It appears that Fdr_cycle is analogous to a Z-pulse in an encoder, triggering the assignment of the value, on this scan when Fdr_cycle is TRUE, of HS_cntr_pv (present value of High-speed counter?) to be used as a reference for future calculations.

That raises two possible problems:

  1. What if Fdr_cycle is TRUE for two scans in a row?
  2. or, What if Fdr_cycle being TRUE is missed?
Both of those cases could cause a drift in the calculations. The solution for problem #1 is to use a one-shot derived from the rising edge of Fdr_Cycle (maybe it already is; we don't see the rest of the code). The solution for problem #2 is more problematic. It would help if we knew what each of these variables represents.
 
Last edited:
Code:
FOR loop0:= 0 TO 4 DO
    
    IF hs_cntr_pv >=encVal_array[loop0] THEN 
        
        trigger_array[loop0]:= TRUE; [COLOR=Red](*set trigger output*)[/COLOR]
        encVal_array[loop0]:= (hs_cntr_pv + pulse_per_rev); [COLOR=Red](*set next trigger at (current pulse count +one revolution)*)[/COLOR]
    END_IF;
    
    IF hs_cntr_pv >=encVal_array[loop0] -(pulse_per_rev /2) THEN 
        trigger_array[loop0 +1]:= FALSE; [COLOR=Red](*reset trigger output after 1/2 revolution*)[/COLOR]
    END_IF;
END_FOR;




The main error in this code is where he adds the target distance to current counter value. That's why the error is accumulating.

Code:
encVal_array[loop0]:= (hs_cntr_pv + pulse_per_rev);
If that is fixed there will be varying degree of error but not cumulative.
 
Code:
That raises two possible problems:

[LIST=1]
[*]What if Fdr_cycle is TRUE for two scans in a row?
[*]or, What if Fdr_cycle being TRUE is missed?
[/LIST]
Both of those cases could cause a drift in the calculations.  The solution for problem #1 is to use a one-shot derived from the rising edge of Fdr_Cycle (maybe it already is; we don't see the rest of the code).  The solution for problem #2 is more problematic.  It would help if we knew what each of these variables represents.[/QUOTE]


Yes, there should be a rising edge, or it may be is reset somewhere withing the same scan. We don't know the origin of this tag, sensor or something else. There's a lot we don't know.


So what I gathered is that the line has 5 cameras and they are spaced as stated before so:


At count equal:


0 > Assume product entered at counter value := 0 (and one more every 1000)

1000 > Camera 1 := ON
2000 > Camera 1 & 2 := ON
3000 > Camera 1,2&3 := ON
4000 > Camera 1,2,3& 4 := ON
5000 > Camera 1,2,3,4 & 5 := ON
every 1000 more > All turn ON


What are the cameras doing, are they tracking the products for quality? Are the camera images supposed to be grouped together?
 
that will have cumulative error
Maybe I am misunderstanding, story of my life :), I would have thought that the method using High Speed Counter interrupts will be least likely to cause a cumulative error.

Going right back to the OPs first post, he was allowing 10 pulses in case the target was received part way through a machine cycle. A High Speed Counter raising an interrupt will catch the moment that the counter reaches the set point, so there is no need to have the 10 pulse range. Eliminating that allows him to count all the way up to 99 and still allows him to reset the count using the Z input.

If this isn't a solution then I think we have reached the point where the OP needs to look at whether using an encoder is the best solution. Perhaps a sensor that registers the presence of the thing that needs to be photographed.
 
Interrupts in PLCs do not necessarily have the low-latency response to capture and reset the counter in software without losing pulses (at this pace). A high-speed counter with a hardware store-count-and-continue operating mode is usually necessary. And never reset. Just let the counter roll over. Do all "resets" virtually in software.
 
Interrupts in PLCs do not necessarily have the low-latency response to capture and reset the counter in software without losing pulses (at this pace).
The OP has said he is getting about 5.5 pulses per millisecond, 181us seconds per pulse, I don't see this as a particularly high speed. An Interrupt would only need to set a 'Take Picture' flag, set the High Speed Counter and then return control to the main program. The interrupt would be microsconds (us). I am going to use execution times from an old Siemens S7-200 manual that I have, but I found them for the Omron CP2E.
https://assets.omron.eu/downloads/manual/en/v3/cp2e_cp1e_instructions_reference_manual_en.pdf
I am not using the Omron times because I am not confident about what the PLC needs to do for each function. However if I look at giving the High Speed Counter a new set point, for Siemens it is 30us, for the Omron it is 8.3us. So I am happy that my numbers should be very much on the high side.

Calling and returning from an Interrupt took 24us, to set a value for the High Speed Counter was 30us, and setting a bit was 2.8us, so that is 56.8us per Interrupt, well within the 181us per pulse. I thought I understood that there were 30 lines each with a camera, but elsewhere he said that there could be 4 cameras needed per cycle. So that is 227us or 0.227ms to perform 4 interrupts, so his cycle time goes up from 6ms to 6.227ms.

Having four interrupts off one encoder does complicate the High Speed Counter Interrupt setting. He said there is one Master encoder for all the cameras. If you had one camera to trigger at 505, one at 520, one at 600 and one at 602, you would have to first set the HSC Interrupt for 505, then 15, then 80 and then 2. Finally Z signal to reset the count.
 
Thanks Bryan. I hope I did not hijack the thread as I often do.
I agree with you on use of interrupts and I am basically splitting hair on the issue of adding to counter current value not on the use or interrupts.



Your feedback was much appreciated.


Cheers
 
OP is using a high-speed counter (HSC; cf. Post #8). Do we know if their HSC can generate interrupts?

For no interrupts and monitoring the HSC value in the continuous task, with the raw counter value rolling over once per product (per Post #28) and changing by a few dozen per scan (again per Post #28), there has to be a comparison between the raw counter value and a range of target values.

The original post was primarily looking for a "better" way to deal with comparing the un-modified counter value and the target value range when rollover was a possibility i.e. when a simple

Code:
IF (pv >= targetval) AND (pv < (targetval+10) THEN ...
which would not work if targetval was within 10 of the counts-per-product rollover value.

There have been several methods proposed to do this, which break down into two groups:

  • some that modify the raw and target values in parallel in order to use a cleaner in-range check of the modified values i.e. cleaner in that the rollover does not need to be considered as part of the in-range check, and the simple code above works as-is;
  • some that use the raw and target range values as-is and compensate for possible rollover as part of the in-range check;
The former group handles rollover by pushing its messiness to code executed before a simple in-range check; the latter group handles rollover messiness as part of a more complex in-range check; all should work equally well, and "better" is in the eye the beholder, I suppose.

If implemented properly, and assuming OP's claim that the shaft, encoder, chain, product pushers, etc., are indeed all in perfect synchrony, then any of the proposed methods should work without drift.

Since the OP says they are experiencing drift, something is not as assumed i.e. the model as implemented is wrong. There are two causes of drift that I can think of offhand:

  1. The code resets the HSC phase with respect to the shaft encoder e.g. as a response to the Z pulse.
  2. The OP has the wrong number of counts per rollover. The original post used 100; later it was 1000, presumably from a different encoder; what if it's actually 1024?
Anyway, this has been today's edition of "Our Story So Far."
 
Just to stir the pot a bit more, here is another first-group approach that seems pretty clean, readable, and simple, uses only the HSC present value, and doesn't need the Z-pulse.



VAR
HSC_rollover : INT = 1000; (* 1 more than maximum raw value from HSC *)
HSC_pv : INT; (* raw HSC count, runs from 0 to (HSC_Rollover-1), then back to 0 *)
Op_set_target_PB : BOOL; (* TRUE when operator sets target value; moves HSC_pv into HSC_target *)
HSC_zero : INT; (* raw HSC count when HSC_offset-based value is interpreted as 0 *)
HSC_offset_pv : INT; (* counts from HSC_zero foward to HSC_pv *)
HSC_offset_target_lo : INT = 500; (* counts from HSC_zero forward to low end of target range *)
HSC_offset_target_hi : INT = 550; (* counts from HSC_zero forward to high end of target range *)
Trigger : BOOL; (* true when HSC_offset_pv is in range [HSC_offset_target_lo,HSC_offset_target_hi) *)
END_VAR

...

(* Operator presses button to set current shaft position as start of target range *)

IF (Op_set_target_PB) THEN

(* Offset raw "zero" so rollover is not a problem when checking range *)

HSC_zero = (HSC_pv + HSC_rollover - HSC_target_lo) MOD HSC_rollover;

END_IF;

IF (Running) THEN

(* Shift raw PV position to PV offset from raw "zero" *)

HSC_offset_pv = (HSC_pv + HSC_rollover - HSC_zero) MOD HSC_rollover;

(* Check if offset PV is in offset target range *)

Trigger = (HSC_offset_pv >= HSC_offset_target_lo) AND (HSC_offset_pv < HSC_offset_target_hi);

END_IF;

 
Last edited:
The main error in this code is where he adds the target distance to current counter value. That's why the error is accumulating.

Code:
encVal_array[loop0]:= (hs_cntr_pv + pulse_per_rev);
If that is fixed there will be varying degree of error but not cumulative.

Exactly. that should be

Code:
encVal_array[loop0]:= (encVal_array[loop0] + pulse_per_rev);
 
OP is using a high-speed counter (HSC; cf. Post #8). Do we know if their HSC can generate interrupts?


The original post was primarily looking for a "better" way to deal with comparing the un-modified counter value and the target value range when rollover was a possibility i.e. when a simple

Code:
IF (pv >= targetval) AND (pv < (targetval+10) THEN ...
which would not work if targetval was within 10 of the counts-per-product rollover value.


Yes it is capable of hardware interrupts for CV=RV, but that discussion is mostly academic and one that interests me; the OP has opted to not use interrupts, or so it seems.



The code snippet you posted was changed, I believe, to this:
Code:
FOR loop0:= 0 TO 4 DO
    
    IF hs_cntr_pv >=encVal_array[loop0] THEN 
        
        trigger_array[loop0]:= TRUE; [COLOR=Red](*set trigger output*)[/COLOR]
        encVal_array[loop0]:= (hs_cntr_pv +pulse_per_rev); [COLOR=Red](*set next trigger at (current pulse count +one revolution)*)[/COLOR]
    END_IF;
    
    IF hs_cntr_pv >=encVal_array[loop0] -(pulse_per_rev /2) THEN 
        trigger_array[loop0 +1]:= FALSE; [COLOR=Red](*reset trigger output after 1/2 revolution*)[/COLOR]
    END_IF;
END_FOR;
It looks like he has an array of counter values (targets) to evaluate, which he does in a loop. Let's take just take one.


diHSC_PresentValue : Dint; // the current counter value
diTarget_Value1 : DInt; // counter value to evaluate
diDistance_ToCamera : Dint := 1000; // distance between parts and cameras (same distance)

bTrigger_Camera1 : Bool; // Tag to turn on camera/output


IF diHSC_Present_Value >= diTrigger_Value1 THEN

bTrigger_Camera1:= TRUE; // turn on camera
diTarget_Value1:= (diHSC_Present_Value + pulse_per_rev); (*set next trigger at (current pulse count +one revolution)*) This is a mistake
END_IF;


Assume we started right on zero meaning first camera will trigger on 1000 then 2000 then 3000 and so on.


Say at the time the code evaluates the values diHSC_PresentValue is 1005 and diTarget_Value1 is 1000 then the condition is true:


Now we set up the next target value for the same Camera1 (which really should be at 2000) the flowing way:


diTarget_Value1:= 1005 (diHSC_Present_Value) + 1000 (diDistance_ToCamera) which gives us a target value of 2005 for Camera1, or 5 pulses more than it should be. You do this 20,000 times an hour and bob's your uncle, or not, who knows.
 

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
393
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
469
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
765
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,732
Back
Top Bottom