Sample programs 24.02.2021 10:04 24.02.2021 10:04

Here you can read more detailed information about the sensor itself, and in the article Using the C-IF-6400R sensor to detect the position of people you can read one of the examples of using the sensor.

This article will describe a program for an example of using a sensor with another way of processing data from sensors, from which an averaged temperature map is then created, or using the sensor to count people who entered or left the room.

1 prgMain

Data processing from the sensor, averaging the temperature map and counting people passed is each implemented as its own function block, which are called in the main program 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 Data processing from the sensor

Data processing from the sensor takes place in the function block fbGridEye whose source code is as follows:

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
            column := MOD(IN1 := j-1, IN2 := 8) + 1; // The function MOD gives the integer remainder of division which corresponds to the number of the column - only 0 means the 8th column
            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

The map is divided into 3 horizontal and 3 vertical zones, with the middle zones extending into the extreme zones. Such a division may be suitable for various purposes, or may be replaced by a completely different approach, such as defining your own zone in the form of a square or rectangle as shown in the Sensor Use example.

 

1.1.1 VAR_INPUT

Variable

Type

Description

sensor_data

TCIB_GRIDEYE_DATA

Reference to the entire sensor structure

temperature_offset

REAL

Offset of measured temperatures, which is added to the values from the sensors

temperature_trigger

REAL

The temperature above which the presence of an object is indicated

 

1.1.2 VAR_OUTPUT

Variable

Type

Description

temperature_difference_matrix

ARRAY [1..64] of REAL

Field of values of differences of individual sensors in the map against the reference temperature

temperature_matrix

ARRAY [1..64] of REAL

Field of measured absolute temperatures of individual sensors (reference + measured value + offset)

presence_matrix

ARRAY [1..64] of BOOL

Field indicating which sensors measured the temperature exceeding the defined temperature temperature_trigger

left_side_active

BOOL

Indication of the active left zone in the temperature map

center_horizontal_active

BOOL

Indication of the active middle horizontal zone in the temperature map

right_side_active

BOOL

Indication of the active right zone in the temperature map

top_active

BOOL

Indication of the active upper zone in the temperature map

center_vertical_active

BOOL

Indication of the active middle vertical zone in the temperature map

bottom_active

BOOL

Indication of the active lower zone in the temperature map

 

 1.2 Averaging

The function returns the average, which is always updated with the newly measured value (in the example, when calling the function from the main program prgMain, a timer is used, according to which the new value is measured every 10 s and not according to the frequency of reading data from the sensor). For this method of averaging, it is not necessary to remember the field of previous values, but only the number of values from which it is averaged. As the amount of data increases, the variable n becomes high, which means that sudden changes in the measured data will have an ever smaller effect the longer the averaging takes place. However, this can also be a disadvantage, and there are a number of solutions and approaches to the issue of averaging in general, depending on the type of application. For example, an hourly or daily average could be calculated for values measured every 10 s, etc.

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 People counter

The counting of people depends on the orientation of the sensor. The example defines from which side the people who entered the space are counted, and vice versa, therefore, the people who came out of the space are counted. The variables are named specifically for the left side, the horizontal center, and the right side, but the same principle would be used when counting in a vertical orientation. 

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

Variable

Type

Description

left_to_right

BOOL

Count from left to right - the entrance is on the left

right_to_left

BOOL

Count from right to left - the entrance is on the right

right_side_active

BOOL

Active right part of the sensor map - information from the function block for data processing from the sensor

center_horizontal_active

BOOL

Active middle part of the sensor map - information from the function block for data processing from the sensor

left_side_active

BOOL

Active left part of the sensor map - information from the function block for data processing from the sensor

reset

BOOL_R_EDGE

The calculated values are reset to the leading edge of the reset signal

 

1.3.1 VAR_OUTPUT

Variable

Type

Description

people_counter

INT

The number of people currently inside

people_in

INT

The total number of people that entered the space during the measurement

people_out

INT

The total number of people who left the room during the measurement