Vzorové programy programování, teplota 24.02.2021 10:04 24.02.2021 10:04

Zde je možné si přečíst podrobnější informace o samotném senzoru a v článku Využití senzoru C-IF-6400R pro detekci polohy osob je možné se dočíst jeden z příkladů použití senzoru.

V tomto článku bude popsán program pro příklad využití senzoru s jiným způsobem zpracování dat ze senzorů ze kterých se následně vytvoří průměrovaná teplotní mapa, anebo využití senzoru k počítání lidí, kteří vešli do prostoru nebo z něj odešli.

1 prgMain

Zpracování dat ze senzoru, průměrování teplotní mapy a počítání prošlých lidí je každé realizováno jako vlastní funkční blok, které jsou volány v hlavním programu prgMain. 

VAR_GLOBAL RETAIN
    count_people_from_left_to_right : BOOL := 0;
    count_people_from_right_to_left : BOOL := 1;
    SamplingPeriod : TIME := T#10s;
    temperature_matrix_average : ARRAY [1..64] of REAL;
    n : UDINT;
    people_inside_now : INT := 0;
    sum_people_in : INT := 0;
    sum_people_out : INT := 0;
END_VAR

PROGRAM prgMain
  VAR
      GridEye : fbGridEye;
      //temperature_trigger_difference : REAL := 2.0;
      temperature_trigger : REAL := 20.0;
      temperature_offset : REAL := 0.0;
      
      i : INT;
      SamplingTimer : TON;
      
      people_counter_fb : fbPeopleCounter;
  END_VAR

  (* - The GridEye function block needs the whole DATA structure from the sensor C-IF-6400R 
       passed to the input sensor_data
     - The function block has three output arrays/matrices :
       the temperature difference matrix gives 64 values of temp. diff. to the reference 
       temperature for each point
     - the temperature matrix gives 64 values of measured temperatures for each point, 
       temperature at each point is calculated as reference + temp. difference
     - the presence_matrix gives 64 BOOL values, each point activates when the temperature
       difference at such point is higher than the defined temperature_trigger_difference 
       in the VAR_INPUT  *)

    GridEye(
        sensor_data := r4144_p0_IN.DATA,
        temperature_trigger := temperature_trigger,
        temperature_offset := temperature_offset
    );

// Averaging the heat map
    SamplingTimer(
          IN := NOT SamplingTimer.Q,
          PT := SamplingPeriod);

    IF SamplingTimer.Q THEN
        FOR i := 1 to 64 DO
            IF n > 0 THEN
                temperature_matrix_average[i] := fAverage(
                    mean := temperature_matrix_average[i],
                    NewValue := GridEye.temperature_matrix[i],
                    n := n);
            END_IF;
        END_FOR;
        n := n+1;
    END_IF;
    
// People counting
    people_counter_fb(
        left_to_right := count_people_from_left_to_right,
        right_to_left := count_people_from_right_to_left,
        right_side_active := GridEye.right_side_active,
        center_horizontal_active := GridEye.center_horizontal_active,
        left_side_active := GridEye.left_side_active);

    people_inside_now := people_counter_fb.people_counter;
    sum_people_in := people_counter_fb.people_in;
    sum_people_out := people_counter_fb.people_out;

END_PROGRAM

 

1.1 Zpracování dat ze senzoru

Zpracování dat ze senzoru probíhá ve funkčním bloku fbGridEye jehož zdrojový kód je následovný:

FUNCTION_BLOCK fbGridEye
  VAR_INPUT
      sensor_data : TCIB_GRIDEYE_DATA; // The GridEye function block needs the whole DATA structure from the sensor C-IF-6400R passed to the input sensor_data
      //temperature_trigger_difference : REAL := 4.0;
      temperature_offset : REAL := 0.0;
      temperature_trigger : REAL := 22.0;
  END_VAR
  VAR_OUTPUT
  (* The function block has three output arrays/matrices :
       - the temperature difference matrix gives 64 values of temp. diff. 
         to the reference temperature for each point
       - the temperature matrix gives 64 values of measured temperatures for each point, 
         temperature at each point is calculated as reference + temp. difference
       - the presence_matrix gives 64 BOOL values, each point activates when the temperature 
         difference at such point is higher than the defined temperature_trigger_difference 
         in the VAR_INPUT *)

      temperature_difference_matrix : ARRAY [1..64] of REAL;
      temperature_matrix : ARRAY [1..64] of REAL;
      presence_matrix : ARRAY [1..64] of BOOL;

      left_side_active : BOOL := 0;
      center_horizontal_active : BOOL := 0;
      right_side_active : BOOL := 0;

      top_active : BOOL := 0;
      center_vertical_active : BOOL := 0;
      bottom_active : BOOL := 0;
  END_VAR
  VAR_IN_OUT
  END_VAR
  VAR
      index_matrix : INT;
      index : USINT;
      ref : REAL;
      temp : TCIB_GRIDEYE_TEMP;
      
      column : INT;
      row : INT;
      i : INT;
      j : INT;
  END_VAR
  VAR_TEMP
  END_VAR
    index := sensor_data.INDEX;
    ref := sensor_data.REF;
    temp := sensor_data.TEMP;

    right_side_active := 0;
    center_horizontal_active := 0;
    left_side_active := 0;
    
    top_active := 0;
    center_vertical_active := 0;
    bottom_active := 0;

    IF index > 0 THEN
       FOR i := 1 to 8 DO
           index_matrix := ((USINT_TO_INT(index))-1)*8 + i;
           temperature_matrix[index_matrix] := SINT_TO_REAL(temp[8-i])/10.0 + ref + temperature_offset;
           temperature_difference_matrix[index_matrix] := SINT_TO_REAL(temp[8-i])/10.0;
       END_FOR;
    END_IF;

    FOR j := 1 to 64 do
        // Finding points where temperature difference is higher than the defined trigger value
        (*
        IF temperature_difference_matrix[j] >= temperature_trigger_difference then
            presence_matrix[j] := 1;
        ELSIF temperature_difference_matrix[j] < temperature_trigger_difference then
            presence_matrix[j] := 0;
        END_IF;
        *)
        
        // Finding point where measured temperature is higher than the defined trigger temperature
        IF temperature_matrix[j] >= temperature_trigger then
            presence_matrix[j] := 1;
        ELSIF temperature_matrix[j] < temperature_trigger then
            presence_matrix[j] := 0;
        END_IF;
        
        // When a point in the presence matrix is 1 then the column number to which the point belongs is found
        // This column is used to calculate which of the three zones the active point belongs to
        IF presence_matrix[j] THEN
            // Column and row can be calculated via MOD and DIV for a zero-based indexing so a 1  
            // needs to be added after the calculation of MOD and DIV

            // The function MOD gives the integer remainder of division which corresponds 
            // to the number of the column - only 0 means the 8th column
            column := MOD(IN1 := j-1, IN2 := 8) + 1; 
            row := DIV(IN1 := j-1, IN2 := 8) + 1; // Row is calculated from the index number divided by the number of columns
            
            // left, center or right side activation
            IF  column = 8 OR column = 7 OR column = 6 THEN
                right_side_active := 1;
            END_IF;
            
            IF column = 6 OR column = 5 OR column = 4 OR column = 3 THEN
                center_horizontal_active := 1;
            END_IF;
            
            IF column = 3 OR column = 2 OR column = 1 THEN
                left_side_active := 1;
            END_IF;
            
            // top, center or bottom side activation
            IF row = 1 OR row = 2 OR row = 3 THEN
                top_active := 1;
            END_IF;
            
            IF row = 3 OR row = 4 OR row = 5 OR row = 6 THEN
                center_vertical_active := 1;
            END_IF;
            
            IF row = 6 OR row = 7 OR row = 8 THEN
                bottom_active := 1;
            END_IF;
        END_IF;

    END_FOR;

    
END_FUNCTION_BLOCK

Mapa je rozdělena na 3 zóny horizontální a 3 vertikální s tím, že střední zóny zasahují i do krajních zón. Takové rozdělení může být vhodné pro různé účely, anebo je možné je nahradit úplně jiným přístupem jako je například definování vlastní zóny formou čtverce nebo obdélníku jak je uvedeno v příkladu Využití senzoru.

 

1.1.1 VAR_INPUT

Proměnná

Typ

Popis

sensor_data

TCIB_GRIDEYE_DATA

Odkaz na celou senzorovou strukturu

temperature_offset

REAL

Offset měřených teplot, který se přičte k hodnotám ze senzorů

temperature_trigger

REAL

Teplota nad kterou se indikuje přítomnost objektu

 

1.1.2 VAR_OUTPUT

Proměnná

Typ

Popis

temperature_difference_matrix

ARRAY [1..64] of REAL

Pole hodnot diferencí jednotlivých senzorů v mapě vůči referenční teplotě

temperature_matrix

ARRAY [1..64] of REAL

Pole měřených absolutních teplot jednotlivých senzorů (reference + naměřená hodnota + offset)

presence_matrix

ARRAY [1..64] of BOOL

Pole indikující které senzory naměřily teplotu přesahující definovanou teplotu temperature_trigger

left_side_active

BOOL

Indikace aktivní levé zóny v teplotní mapě

center_horizontal_active

BOOL

Indikace aktivní střední horizontální zóny v teplotní mapě

right_side_active

BOOL

Indikace aktivní pravé zóny v teplotní mapě

top_active

BOOL

Indikace aktivní horní zóny v teplotní mapě

center_vertical_active

BOOL

Indikace aktivní střední vertikální zóny v teplotní mapě

bottom_active

BOOL

Indikace aktivní dolní zóny v teplotní mapě

 

1.2 Průměrování

Funkce vrací průměr, který se aktualizuje vždy s nově naměřenou hodnotou (v příkladu při volání funkce z hlavního programu prgMain se používá časovač, podle kterého se nová hodnota měří každých 10 s a ne podle frekvence čtení dat ze senzoru). Pro tento způsob průměrování není potřeba si pamatovat pole předchozích hodnot, ale jen počet hodnot ze kterých se průměruje. Se zvyšujícím se množstvím dat nabývá proměnná n vysokých hodnot což způsobí, že náhlé změny v naměřených datech budou mít stále menší vliv čím déle průměrování probíhá. To ale může být i nevýhoda a celkově k problematice průměrování existuje řada řešení a přístupů a záleží na typu aplikace. Například by se dal počítat hodinový nebo denní průměr pro hodnoty naměřené každých 10 s apod.

FUNCTION fAverage : REAL
  VAR_INPUT
      mean : REAL;
      NewValue : REAL;
      n : UDINT;
  END_VAR
  VAR_IN_OUT
  END_VAR
  VAR
      ignoreData : BOOL := FALSE;
  END_VAR
  VAR_TEMP
  END_VAR
      
    IF System_S.S2_3 OR System_S.S2_4 THEN
        ignoreData := TRUE;
        mean := NewValue;
    END_IF;

    IF NOT ignoreData THEN
        mean := mean + (NewValue - mean)/UDINT_TO_REAL(n);
    END_IF;

    ignoreData := FALSE;

    fAverage := mean;
END_FUNCTION

 

1.3 Počítání lidí

Počítání lidí závisí na orientaci senzoru. V příkladu se definuje ze které strany se počítají lidé, kteří vstoupili do prostoru a opačně se tedy počítají lidé, kteří vystoupili z prostoru ven. Proměnné jsou pojmenované konkrétně pro levou stranu, horizontální střed a pravou stranu, ale stejný princip by se využil i při počítání ve vertikální orientaci. 

FUNCTION_BLOCK fbPeopleCounter
  VAR_INPUT
      left_to_right : BOOL := 0;
      right_to_left : BOOL := 1;
      right_side_active : BOOL := 0;
      center_horizontal_active : BOOL := 0;
      left_side_active : BOOL := 0;
      reset : BOOL R_EDGE;
  END_VAR
  VAR_OUTPUT
      people_counter : INT := 0;
      people_in : INT := 0;
      people_out : INT := 0;
  END_VAR
  VAR_IN_OUT
  END_VAR
  VAR
      right_side_r_edge : R_TRIG;
      right_side_f_edge : F_TRIG;
      left_side_r_edge : R_TRIG;
      left_side_f_edge : F_TRIG;

      entrance_initiated : BOOL := 0;
      exit_initiated : BOOL := 0;
  END_VAR
  VAR_TEMP
  END_VAR

// Detection of edges for initiation of entrance and exit
    right_side_r_edge(CLK := right_side_active);
    right_side_f_edge(CLK := right_side_active);
    left_side_r_edge(CLK := left_side_active);
    left_side_f_edge(CLK := left_side_active);

// From right to left
    IF right_to_left AND NOT left_to_right THEN
    // Entrance
        IF right_side_r_edge.Q AND NOT exit_initiated THEN
            entrance_initiated := TRUE;
        END_IF;

        IF entrance_initiated AND left_side_f_edge.Q AND NOT (center_horizontal_active OR right_side_active)THEN
            people_counter := people_counter + 1;
            people_in := people_in + 1;
        END_IF;

    // Exit
        IF left_side_r_edge.Q AND NOT entrance_initiated THEN
            exit_initiated := TRUE;
        END_IF;

        IF exit_initiated AND right_side_f_edge.Q  AND NOT (center_horizontal_active OR left_side_active) THEN
            people_counter := people_counter - 1;
            people_out := people_out + 1;
        END_IF;


        IF NOT (right_side_active OR center_horizontal_active OR left_side_active) THEN
            entrance_initiated := FALSE;
            exit_initiated := FALSE;
        END_IF;
    END_IF;

// From left to right
    IF left_to_right AND NOT right_to_left THEN
    // Entrance
        IF left_side_r_edge.Q AND NOT exit_initiated THEN
            entrance_initiated := TRUE;
        END_IF;

        IF entrance_initiated AND right_side_f_edge.Q AND NOT (center_horizontal_active OR left_side_active)THEN
            people_counter := people_counter + 1;
            people_in := people_in + 1;
        END_IF;

    // Exit
        IF right_side_r_edge.Q AND NOT entrance_initiated THEN
            exit_initiated := TRUE;
        END_IF;

        IF exit_initiated AND left_side_f_edge.Q  AND NOT (center_horizontal_active OR right_side_active) THEN
            people_counter := people_counter - 1;
            people_out := people_out + 1;
        END_IF;


        IF NOT (right_side_active OR center_horizontal_active OR left_side_active) THEN
            entrance_initiated := FALSE;
            exit_initiated := FALSE;
        END_IF;
    END_IF;

// Reset
    IF reset THEN
        people_counter := 0;
        people_in := 0;
        people_out := 0;
    END_IF;
    
END_FUNCTION_BLOCK

 

1.3.1 VAR_INPUT

Proměnná

Typ

Popis

left_to_right

BOOL

Počítat zleva doprava - vstup je vlevo

right_to_left

BOOL

Počítat zprava doleva - vstup je vpravo

right_side_active

BOOL

Aktivní pravá část mapy senzoru - informace z funkčního bloku pro zpracování dat ze senzoru

center_horizontal_active

BOOL

Aktivní střední část mapy senzoru - informace z funkčního bloku pro zpracování dat ze senzoru

left_side_active

BOOL

Aktivní levá část mapy senzoru - informace z funkčního bloku pro zpracování dat ze senzoru

reset

BOOL_R_EDGE

Na náběžnou hranu signálu reset se vynulují napočítané hodnoty

 

1.3.1 VAR_OUTPUT

Proměnná
Typ
Popis
people_counter
INT
Počet lidí aktuálně uvnitř
people_in
INT
Celkový počet lidí, který za dobu měření vešel do prostoru
people_out
INT
Celkový počet lidí, který za dobu měření odešel z prostoru

Připojené dokumenty