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
- Softwarový projekt - příklad využití senzoru Grid-Eye