Mapa placu w module Yard Management

W Studio VSS.net wizualizacja zajętości miejsc parkingowych należy do modułu Yard Management. Podkładem mapy jest zdjęcie terenu z góry, na którym narysowano prostokąty stanowisk postojowych. Każde stanowisko ma kod w konwencji 01M, 02M, 03M i kolejne. Dyspozytor i pracownik ochrony posługują się więc tym samym oznaczeniem, które widnieje na tablicy przy placu.

Menu modułu grupuje funkcje placu w jednym miejscu. Mapa odpowiada na pytanie o stan w tej chwili, a lista „Parkowanie” podaje te same dane w tabeli, którą da się filtrować i sortować. Słowniki przewoźników i kontrahentów pochodzą z kartotek systemu VSS.net, więc ikona na mapie prowadzi do pełnych danych transportu.

Pozycja menu Yard ManagementZastosowanie
Konteneryewidencja kontenerów przebywających na terenie obiektu
Parkowanielista zajętych miejsc wraz z pojazdami albo naczepami, które na nich stoją
Wizualizacjamapa placu z kodami stanowisk i ikonami pojazdów
Transporty wg statusówtransporty pogrupowane według etapu obsługi
Historiazakończone pobyty i zdarzenia na placu
Bramyobsługa wjazdów i wyjazdów
Miejsca parkingowekonfiguracja stanowisk: kod stanowiska i jego położenie na mapie
Transport wewnętrznyprzestawienia pojazdów między strefami zakładu

Ikony i numeracja stanowisk

Na zajętym stanowisku pojawia się ikona pojazdu. Ciągnik siodłowy ma inny symbol niż odstawiona naczepa, dzięki czemu widać, czy na miejscu stoi kompletny zestaw, czy sama naczepa czekająca na rozładunek. Stanowisko bez ikony jest wolne i można na nie skierować kolejny pojazd.

Numeracja z sufiksem „M” oddziela miejsca postojowe od ramp, które w tym samym systemie mają własne kody. Ma to znaczenie w dyspozycji: pracownik bramy wybiera osobno planowane miejsce parkingowe i osobno planowaną rampę. Pomyłka między tymi dwoma słownikami jest niemożliwa, bo pola korzystają z różnych list.

Źródła danych dla systemu monitorowania zajętości parkingu

Mapa pokazuje tylko to, co zapisano w bazie. Jakość obrazu zależy od tego, które zdarzenie zmienia stan stanowiska i jak szybko trafia ono na serwer. System monitorowania zajętości parkingu łączy zwykle kilka źródeł o różnej wiarygodności i różnym opóźnieniu.

Odprawa na bramie i dyspozycja

Najprostszym źródłem jest odprawa. Pracownik w roli „Brama i ochrona” otwiera zestawienie transportów wjazd/wyjazd, a w oknie „Dyspozycja” wskazuje planowane miejsce parkingowe oraz planowaną rampę magazynową. W tym samym oknie zmienia się status awizacji, na przykład na „Awizacja oczekuje na realizację”. Kierowca zna numer stanowiska, zanim minie szlaban.

Zestawienie transportów wjazd/wyjazd w roli Brama i ochrona z otwartym oknem Dyspozycja zawierającym pola Status, Plan. miejsce parkingowe, Plan. rampa magazynowa oraz Flaga
Okno dyspozycji przy odprawie na bramie. Wybór planowanego miejsca parkingowego jest pierwszym zdarzeniem, które zmienia stan mapy placu.

Kamery ANPR na wjeździe

Kamera odczytująca tablice rejestracyjne (ANPR, w menu programu pozycja LPR) porównuje numer z listą awizowanych wizyt. Zgodny odczyt zapisuje czas wjazdu bez udziału ochrony. Kamera przy bramie potwierdza jednak tylko wjazd na teren zakładu. Nie wie, na które stanowisko pojazd trafił.

Ilustracja: trzy ciągniki siodłowe z naczepami jadące nocą po mokrej nawierzchni, na pierwszym planie przód pojazdu z oświetloną atrapą i miejscem na tablicę rejestracyjną
Pojazdy zbliżające się do bramy. Odczyt tablicy przez ANPR potwierdza tożsamość pojazdu i czas wjazdu, ale nie wskazuje stanowiska na placu.

Czujniki na stanowiskach

Czujnik magnetyczny w nawierzchni albo czujnik ultradźwiękowy nad stanowiskiem zgłasza stan zajęty lub wolny niezależnie od wpisów ochrony. Czujnik wykrywa obecność obiektu, lecz go nie identyfikuje. Wie, że stanowisko 05M jest zajęte, ale nie wie przez kogo. Jego odczyt trzeba więc zestawić z dyspozycją albo z odczytem kamery obejmującej plac.

Źródło zdarzeniaCo potwierdzaCzego nie wieOpóźnienie zapisu
Dyspozycja na bramieplanowane stanowisko i rampęczy kierowca faktycznie tam stanąłzależne od operatora
Kamera ANPR na wjeździetożsamość pojazdu i czas wjazdustanowisko na placusekundy
Czujnik na stanowiskufizyczne zajęcie miejscaktóry pojazd stoi na miejscusekundy, zależnie od bramki komunikacyjnej
Transport wewnętrznyprzestawienie pojazdu między stanowiskamistan stanowisk nieobjętych zleceniemchwila zatwierdzenia zlecenia

Reguła: stan „zajęte” ustala zdarzenie fizyczne, stan „zarezerwowane” wynika z planu. Nie zapisuje się ich w jednej kolumnie.

Statusy stanowisk i przejścia między nimi

Stan stanowiska zmieniają zdarzenia zapisywane przez bramę oraz przez urządzenia na placu. Przy projektowaniu wizualizacji wygodnie jest opisać go czterema stanami i dozwolonymi przejściami. Taki opis porządkuje kolory mapy oraz reguły walidacji w bazie danych.

StanZdarzenie wejścioweZdarzenie wyjścioweZnaczenie dla dyspozytora
Wolnezamknięcie pobytu albo zdjęcie blokadydyspozycja lub zajęcie bez dyspozycjimożna kierować pojazd
Zarezerwowanedyspozycja z planowanym stanowiskiemwjazd na stanowisko albo wygaśnięcie rezerwacjistanowisko czeka na konkretny pojazd
Zajętepotwierdzenie z czujnika albo od operatorawyjazd ze stanowiskapojazd lub naczepa na miejscu
Zablokowanedecyzja administratorazdjęcie blokadystanowisko wyłączone z planowania

Rezerwacja ma sens tylko z terminem ważności. Jeżeli pojazd nie stanie na wskazanym miejscu w określonym czasie, stanowisko wraca do puli wolnych. Bez tej reguły mapa pokazuje plac pełny, choć część stanowisk stoi pusta. Podobny mechanizm opisuje zarządzanie slotami czasowymi, gdzie niewykorzystana rezerwacja blokuje rampę dla innych przewoźników.

Rozbieżność planu i stanu faktycznego

Kierowca, który stanął na 05M zamiast na wskazanym 03M, tworzy dwa błędy naraz. Stanowisko 03M pozostaje zarezerwowane, a czujnik zgłasza zajęcie 05M bez dyspozycji. Taki przypadek system powinien pokazać jako konflikt, a nie cicho nadpisać plan. Ochrona koryguje wtedy dane w module transportu wewnętrznego w VSS.net albo odsyła kierowcę na właściwe miejsce.

Konflikty tego rodzaju warto liczyć. Duża liczba zajęć bez dyspozycji na jednym fragmencie placu zwykle oznacza nieczytelne oznakowanie w terenie, a nie błąd kierowców.

Model miejsc i zdarzeń w SQL Server

Pod mapą leżą dwie tabele: słownik stanowisk i dziennik pobytów. Słownik zmienia się rzadko, najczęściej przy przebudowie placu. Dziennik rośnie z każdym wjazdem, dlatego zajętość liczy się z otwartych pobytów, a nie z kolumny statusu w słowniku. Poniższy schemat ma charakter przykładowy, nazwy tabel nie odpowiadają rzeczywistej bazie produktu.

-- Przykładowy schemat (nazwy poglądowe)
CREATE TABLE dbo.ParkingPlace (
    PlaceId    int IDENTITY(1,1) PRIMARY KEY,
    Code       varchar(10) NOT NULL UNIQUE,   -- np. 01M
    ZoneCode   varchar(10) NOT NULL,
    IsBlocked  bit NOT NULL DEFAULT 0
);

CREATE TABLE dbo.ParkingStay (
    StayId        bigint IDENTITY(1,1) PRIMARY KEY,
    PlaceId       int NOT NULL REFERENCES dbo.ParkingPlace(PlaceId),
    PlateNumber   varchar(15) NOT NULL,
    Source        tinyint NOT NULL,        -- 1 brama, 2 ANPR, 3 czujnik, 4 operator
    OccupiedFrom  datetime2(0) NOT NULL,
    OccupiedTo    datetime2(0) NULL,
    RowVer        rowversion
);

-- jeden otwarty pobyt na stanowisko
CREATE UNIQUE NONCLUSTERED INDEX UX_ParkingStay_Open
    ON dbo.ParkingStay (PlaceId)
    WHERE OccupiedTo IS NULL;

Unikalny indeks filtrowany z warunkiem WHERE OccupiedTo IS NULL obejmuje wyłącznie otwarte pobyty. Baza sama odrzuci drugie zajęcie tego samego stanowiska, nawet jeśli dwóch operatorów zatwierdzi je w tej samej sekundzie. Indeks pozostaje mały, bo zamknięte pobyty do niego nie trafiają.

CREATE PROCEDURE dbo.usp_OccupyPlace
    @PlaceId     int,
    @PlateNumber varchar(15),
    @Source      tinyint
AS
BEGIN
    SET NOCOUNT ON;
    SET XACT_ABORT ON;

    BEGIN TRANSACTION;

    -- zamknięcie poprzedniego pobytu pojazdu (przestawienie)
    UPDATE dbo.ParkingStay
       SET OccupiedTo = SYSDATETIME()
     WHERE PlateNumber = @PlateNumber
       AND OccupiedTo IS NULL;

    INSERT INTO dbo.ParkingStay (PlaceId, PlateNumber, Source, OccupiedFrom)
    VALUES (@PlaceId, @PlateNumber, @Source, SYSDATETIME());

    COMMIT TRANSACTION;
END;

Procedura działa w jednej transakcji z SET XACT_ABORT ON. Naruszenie indeksu unikalnego (błąd 2601) wycofuje całość, więc pojazd nie zostanie zdjęty z poprzedniego stanowiska bez zajęcia nowego. Aplikacja przechwytuje ten błąd i pokazuje operatorowi komunikat o konflikcie.

Zapytanie zasilające mapę

Mapa potrzebuje jednego wiersza na każde stanowisko. Wiersz niesie dane ze słownika i ewentualny otwarty pobyt. Złączenie zewnętrzne ze słownikiem gwarantuje, że wolne stanowiska też trafią do wyniku, tyle że z pustym numerem rejestracyjnym.

SELECT p.Code,
       p.ZoneCode,
       p.IsBlocked,
       s.PlateNumber,
       s.OccupiedFrom
FROM dbo.ParkingPlace AS p
LEFT JOIN dbo.ParkingStay AS s
       ON s.PlaceId = p.PlaceId
      AND s.OccupiedTo IS NULL
ORDER BY p.Code;

Warunek OccupiedTo IS NULL umieszczony w klauzuli ON, a nie w WHERE, zachowuje wolne stanowiska w wyniku. Optymalizator może przy tym użyć indeksu filtrowanego, bo predykat złączenia pokrywa się z jego filtrem. Plan zapytania nie zależy więc od liczby archiwalnych pobytów, które przez lata gromadzą się w dzienniku.

Odczyty bez blokowania zapisów

Mapa czyta dane często, a brama i czujniki zapisują je w tym samym czasie. W domyślnym trybie READ COMMITTED zapytanie mapy zakłada blokady współdzielone i może czekać na transakcję zapisu, która trzyma blokadę wiersza. Opcja READ_COMMITTED_SNAPSHOT przełącza odczyty na wersje wierszy, więc odczyt nie czeka na zapis. Zasady opisuje dokumentacja SET TRANSACTION ISOLATION LEVEL w Microsoft Learn.

ALTER DATABASE YardDemo
    SET READ_COMMITTED_SNAPSHOT ON
    WITH ROLLBACK IMMEDIATE;

Zmiana wymaga wyłącznego dostępu do bazy, stąd klauzula WITH ROLLBACK IMMEDIATE, która przerywa otwarte sesje. Wykonuje się ją w oknie serwisowym, a nie w trakcie pracy bramy.

Odświeżanie wizualizacji w przeglądarce

Widok w przeglądarce nie musi przeładowywać całej strony. Skrypt co kilkanaście sekund pyta serwer o zmiany i przerysowuje tylko te stanowiska, których stan się zmienił. Poniższy fragment pokazuje ten mechanizm na przykładzie funkcji jQuery.ajax. Adres usługi jest przykładowy.

// Odświeżanie mapy placu (przykład poglądowy)
var lastVersion = 0;

function refreshYard() {
  if (document.visibilityState !== 'visible') {
    setTimeout(refreshYard, 15000);
    return;
  }
  $.ajax({
    url: '/api/yard/changes',
    data: { since: lastVersion },
    dataType: 'json',
    cache: false
  }).done(function (res) {
    $.each(res.changes, function (i, c) {
      $('#place-' + c.code)
        .attr('data-state', c.state)
        .attr('title', c.plate || '');
    });
    lastVersion = res.version;
  }).always(function () {
    setTimeout(refreshYard, 15000);
  });
}

refreshYard();

Parametr since przenosi wersję ostatnio otrzymanych danych. Serwer może ją wyznaczyć z kolumny typu rowversion, która zmienia wartość przy każdym INSERT i UPDATE wiersza. Odpowiedź zawiera wtedy tylko zmienione stanowiska, a nie cały plac. Warunek na document.visibilityState wstrzymuje zapytania z kart przeglądarki, których nikt nie ogląda.

MechanizmOpóźnienie widokuKoszt po stronie serweraTypowe zastosowanie
Polling AJAXdo jednego interwałustała liczba zapytań na każde otwarte oknostanowisko ochrony, ekran dyspozytora
Long pollingbliskie zeruotwarte żądanie HTTP na klientakilka równoległych widoków
WebSocket (np. SignalR)bliskie zeruutrzymanie trwałych połączeńekrany ścienne w centrum dyspozytorskim

Na placu z kilkudziesięcioma stanowiskami polling z interwałem kilkunastu sekund wystarcza. Pojazd nie zmienia miejsca częściej, a ochrona i tak potwierdza wjazd ręcznie. Mechanizm push opłaca się dopiero wtedy, gdy ten sam plac ogląda wiele ekranów naraz.

Wizualizacja zajętości miejsc parkingowych w pracy ochrony

Ochrona korzysta z mapy przy każdym wjeździe. Kierowca bez awizacji trafia do ścieżki „Wjazd nieawizowany”, a pracownik bramy od razu widzi, czy na placu jest miejsce, żeby go wpuścić. Pojazd awizowany dostaje stanowisko z dyspozycji. Proces zgłaszania takich wizyt opisuje artykuł o module awizacji Studio VSS.net.

Dyspozytor patrzy na mapę z innej strony. Zestawia zajęte stanowiska z kolejką do ramp, opisaną w tekście o zarządzaniu dokami w magazynie, i decyduje, którą naczepę podstawić jako następną. Pojazd, który przyjechał przed swoim oknem czasowym, czeka na stanowisku, a nie na drodze dojazdowej.

Ilustracja: ciągnik siodłowy z białą naczepą stojący na mokrym placu przed oświetloną halą magazynową o kolorowej elewacji
Zestaw ciągnik z naczepą na placu przed magazynem. Na mapie taki zestaw ma inną ikonę niż sama naczepa odstawiona na stanowisko.

Wskaźniki z dziennika pobytów

Dziennik pobytów daje więcej niż bieżący obraz placu. Z tych samych wierszy liczy się wskaźniki, które pokazują, gdzie plac traci przepustowość:

  • Czas pobytu na stanowisku - różnica między otwarciem a zamknięciem pobytu, liczona osobno dla zestawów i dla samych naczep.
  • Obłożenie placu w godzinach - odsetek zajętych stanowisk w każdej godzinie doby, pokazujący szczyty przyjazdów.
  • Pobyty bez dyspozycji - zajęcia zgłoszone przez czujnik lub kamerę bez wcześniejszego wskazania z bramy.
  • Rezerwacje wygasłe - stanowiska zarezerwowane, na których pojazd nie stanął w terminie.

Długi czas pobytu naczep przy krótkim czasie pobytu zestawów oznacza, że naczepy czekają na wolną rampę, a nie na kierowcę. Takie dane są też materiałem do prognoz opisanych w artykule o cyfrowym bliźniaku magazynu i zatorach przed rampami. Sterowanie samym ruchem między bramą a rampą omawia tekst o sterowaniu ruchem pojazdów na placu.

Zasada: naczepa odstawiona bez ciągnika to osobny pobyt z własnym czasem, a nie część wizyty kierowcy.

Konfiguracja stanowisk przy wdrożeniu

Wdrożenie wizualizacji zaczyna się od słownika w pozycji „Miejsca parkingowe”. Każde stanowisko dostaje kod i obrys na podkładzie mapy. Administrator w module Administrator programu VSS.net przypisuje do bram dostępne rampy i ustala reguły automatycznego przypisywania miejsca postojowego zależnie od typu transportu. W tym samym module bramę łączy się z czytnikiem tablic rejestracyjnych albo z terminalem samoobsługowym.

  • Podkład mapy - aktualne zdjęcie terenu z góry albo plan sytuacyjny w skali, na którym obrysy stanowisk pokrywają się z malowaniem na placu.
  • Numeracja w terenie - kody na mapie muszą odpowiadać tablicom przy stanowiskach, bo tylko wtedy kierowca trafi na miejsce z dyspozycji.

Wymagania serwerowe są takie same jak dla całego systemu VSS.net: Windows Server z IIS oraz baza SQL Server w edycji Express albo Standard. Edycja Express ogranicza plik danych bazy do 10 GB. Przy dzienniku pobytów, który rośnie z każdym wjazdem, oznacza to potrzebę archiwizacji zamkniętych pobytów, na przykład zadaniem uruchamianym w nocy.

Moduł działa na danych, które powstają przy przyjęciu towaru. Awizacja wskazuje, jaki pojazd przyjedzie, a przyjęcie dostawy do magazynu zamyka jego pobyt na placu. Opis funkcji na stronie producenta zawiera strona wizualizacja zajętości miejsc parkingowych w Studio VSS.net, a platformę YMS w modelu usługowym przedstawia serwis YMS24.