Kontrola prędkości ruchu (ruchu z końcówką SP)
Ruchy MOVE, MOVEABS, MOVECIRC, MHELICAL, MSPHERICAL posiadają wersje z końcówką SP (tj. MOVESP, MOVEABSSP, MOVECIRCSP, MHELICALSP, MSPHERICALSP), dzięki którym możliwa jest kontrola prędkości ruchu w momencie w którym załączona jest flaga MERGE (MERGE = ON) za pomocą parametrów STARTMOVE_SPEED, FORCE_SPEED, ENDMOVE_SPEED, FORCE_RAMP oraz FORCE_DWELL. Stosowanie komend z końcówką SP nie różni się niczym od stosowania ich podstawowych wersji.
- STARTMOVE_SPEED stanowi wartość początkową prędkości dla komend ruchu. Kontroler przyjmuje jako priorytetową najmniejszą z wartości zdefiniowanych przez użytkownika dla STARTMOVE_SPEED, ENDMOVE_SPEED, FORCE_SPEED.
- FORCE_SPEED stanowi wartość głównej prędkości dla komend ruchu
- ENDMOVE_SPEED stanowi wartość końcową prędkości dla komend ruchu. Kontroler przyjmuje jako priorytetową najmniejszą z wartości zdefiniowanych przez użytkownika dla STARTMOVE_SPEED, ENDMOVE_SPEED, FORCE_SPEED.
- FORCE_RAMP – jest to parametr odpowiedzialny za zmianę, prędkości ze stałym przyspieszeniem, w trakcie wykonywania ruchu. Wartości dodatnie powodują wzrost prędkości natomiast wartości ujemne tego parametru powodują jej stały spadek.
- FORCE_DWELL. – jest to parametr wprowadzający przestój pomiędzy ruchem dla którego jest zdefiniowany oraz kolejnym ruchem w kolejce. Wartość tego parametru określana jest w milisekundach.
Powyższe parametry ładowane są do bufora wraz z komendą ruchu, więc dla każdej komendy w ruchu łączonym możemy ustawić osobne ich wartości. Kontroler zapamiętuje jednak wprowadzone parametry w związku z czym jeśli dla kolejnej komendy z końcówką SP nie zostaną one zmodyfikowane sterowanie prędkością przebiegnie z uwzględnieniem ostatnich ustawień.
Przykład 1.
BASE(0, 1)
UNITS = 1
SPEED = 300
ACCEL = 10000
DECEL = ACCEL
MERGE = ON
MOVE(0, 1800)
FORCE_SPEED = 275
ENDMOVE_SPEED = 275
FORCE_RAMP = –2
MOVECIRCSP(800, 800, 800, 0, 1)
FORCE_SPEED = 250
ENDMOVE_SPEED = 250
FORCE_RAMP = 0
MOVESP(1800, 0)
FORCE_SPEED = 200
ENDMOVE_SPEED = 200
MOVECIRCSP(700, –700, 0, –700, 1)
MOVE(0, –1800)
FORCE_DWELL = 2000
MOVECIRCSP(-700, –700, –700, 0, 1)
MOVE(-1800, 0)
FORCE_SPEED = 250
ENDMOVE_SPEED = 250
FORCE_DWELL = 0
MOVECIRCSP(-800, 800, 0, 800, 1)
WAIT IDLE
MERGE = OFF
Ruchy sekwencyjne
Komendy MOVESEQ, MOVEABSSEQ umożliwiają tworzenie sekwencji ruchów (dla osi w liczbie 2 – 6) przy wykorzystaniu tablicy danych. Poszczególne ruchy mogą być automatycznie łączone ze sobą za pomocą łuków kołowych lub sferycznych o zdefiniowanym promieniu, jednak należy zaznaczyć, że jego wartość zostanie automatycznie zredukowana do maksymalnej możliwej w sytuacji w której punkty ścieżki nie będą leżały od siebie w wystarczającej odległości.
MOVEABSSEQ (MOVESEQ) stanowi sekwencje ruchów MOVEABS (MOVE) → MOVECIRC →… jeśli operujemy na 2 osiach, natomiast w sytuacji w której ich liczba jest większa lub równa 3 składa się ona z ruchów MOVEABS (MOVE) → MSPHERICAL → … . W momencie w którym zdecydujemy się na sterowanie prędkością dla poszczególnych ruchów MOVEABS (MOVE), MOVECIRC, MSPHERICAL ulegną odpowiednio zamianie na MOVEABSSP (MOVESP), MOVECIRCSP, MSPHERICALSP.
Składnia poleceń:
- MOVEABSSEQ(adres_startowy, liczba_osi, liczba_punktow, opcje, promien [, adres_wyjscia [, ta]])
- MOVESEQ(adres_startowy, liczba_osi, liczba_punktow, opcje, promien [, adres_wyjscia [, ta]])
Opis parametrów:
adres_startowy | numer pola tablicy rozpoczynającego blok danych dla polecenia MOEVABSSEQ (MOVESEQ) | |||
Liczba osi | liczba osi biorących udział w ruchu (2 – 6) | |||
liczba_punktow | • MOVEABSSEQ – liczba punktów przez które będzie przebiegał ruch • MOVESEQ – liczba wektorów przemieszczeń z których będzie składał się ruch | |||
opcje | bit_0 | 0 | brak kontroli prędkości (ruchy MOVEABS {MOVE}, MOVECIRC, MSPHERICALSP) | |
1
| kontrola prędkości poszczególnych ruchów (MOVEABSSP {MOVESP}, MOVECIRCSP, MSPHERICALSP) | |||
bit_1 | zastrzeżony | |||
bit_2 | 0 | sekwencja ładowana do kontrolera jako ruchy podstawowe | ||
1 | sekwencja ładowana jako MOVEABSSEQ / MOVEABSSEQSP | |||
bit_8 … 13 | Służą do ustawiania odstępu pomiędzy parametrami dla kolejnych punktów innymi niż wynikające z parametru liczba_osi | |||
promien | promień zaokrągleń (jeśli nie chcemy wykorzystywać łukowych przejść pomiędzy ruchami liniowymi należy ustawić jego wartość na równą 0) | |||
adres_wyjscia | korzystanie z krzywych przejścia
| [parametr opcjonalny]; indeks pierwszej komórki w tabeli do której zostaną wysłane informacje o wyznaczonej krzywej przejścia | ||
bit 2 parametru opcje = 1 | indeks pierwszej komórki bloku danych wykorzystywanych przez kontroler do wyznaczenia krzywej (wielkosc_bloku_danych = 10 * liczba_punktow) – parametr koniecznie musi zostać wprowadzony dla takich ustawień | |||
ta | [parametr opcjonalny]; kąt przejścia w radianach |
Przed przystąpieniem do pierwszego przykładu należałoby wspomnieć jak używać tablicy w języku TrioBASIC. Do operacji na niej służy polecenie TABLE o następującej składni:
wartosc = TABLE(adres [, dane_1 … , dane_35])
Komenda umożliwia nam wykonanie dwóch operacji na tablicy:
- zapis – którego dokonujemy poprzez początkowe podanie adresu pierwszej komórki, do której będziemy wprowadzać wartości, po którym po przecinkach wprowadzamy interesujące nas dane (maksymalnie 35) – wartości będą wprowadzane po kolei do kolejnych komórek w tablicy. Komenda TABLE użyta w takiej formie zwraca wartość ostatnio wprowadzonej danej.
- odczyt – którego dokonujemy poprzez podanie adresu interesującej nas komórki pamięci. Polecenia używamy wtedy w następującej formie: wartosc = TABLE(adres)
W celu wyczyszczenia tablicy używamy komendy NEW „TABLE”.
Przykład 1. Wykonanie ruchu po ścieżce w kształcie litery „O” dwiema metodami:
- za pomocą komend MOVE, MOVECIRC
- za pomocą wartości wprowadzonych do tablicy oraz komendy MOVESEQ
FOR x = 0 TO 3
BASE(x)
UNITS = 1
SPEED = 400
ACCEL = 10000
DECEL = ACCEL
NEXT x
BASE(0, 1)
‘ Rysowanie O za pomocą komend MOVE, MOVECIRC
MOVE(0, 600) ‘ ruch A1 -> B1
MOVECIRC(300, 300, 300, 0, 1) ‘ ruch B1 -> C1
MOVE(200, 0) ‘ ruch C1 -> D1
MOVECIRC(300, –300, 0, –300, 1) ‘ ruch D1 -> E1
MOVE(0, –600) ‘ ruch E1 -> F1
MOVECIRC(-300, –300, –300, 0, 1) ’ruch F1 -> G1
MOVE(-200, 0) ‘ ruch G1 -> H1
MOVECIRC(-300, 300, 0, 300, 1) ‘ ruch H1 -> A1
BASE(2, 3)
‘ rysowanie O za pomocą komendy MOVESEQ
TABLE(1000, 0, 900) ‘ wektor A2 B2
TABLE(1002, –800, 0) ‘ wektor B2 C2
TABLE(1004, 0, –1200) ‘ wektor C2 D2
TABLE(1006, 800, 0) ‘ wektor D2 E2
TABLE(1008, 0, 300) ‘ wektor E2 A2
adres_startowy = 1000
liczba_osi = 2
liczba_punktow = 5
opcje = 0
promien = 300
MOVESEQ(adres_startowy, liczba_osi, liczba_punktow, opcje, promien)
Jak widać na powyższej symulacji ruch po ścieżce w kształcie litery „O” osi 2 i 3 (ścieżka zielona, MOVESEQ) nie został rozpoczęty w tym samym czasie co ruch osi 0 i 1 (ścieżka czerwona, MOVE, MOVECIRC) co może wydawać się dziwne po spojrzeniu na powyższy kod. Jednak wynika to z limitu buforowanych ruchów (domyślna wartość LIMIT_BUFFERED = 1) w danej chwili o czym była mowa we wcześniejszych częściach kursu. Z zaistniałą sytuacją możemy sobie poradzić w bardzo prosty sposób zwiększając wartość parametru LIMIT_BUFFERED.
Komendy ruchów sekwencyjnych posiadają możliwość skorzystania z powyżej omawianego mechanizmu kontroli prędkości dla poszczególnych łączonych ruchów (komendy z końcówką SP). Jeśli zdecydujemy się na to, będziemy zobligowani do zdefiniowania w tablicy (kolejno po polach odpowiadających za pozycje {MOVEABSSQE} lub przemieszczenia {MOVESEQ}) czterech parametrów:
- FORCE_SPEED – dla ruchu liniowego
- ENDMOVE_SPEED – dla ruchu liniowego
- FORCE_SPEED – dla łuku
- ENDMOVE_SPEED – dla łuku
Należy tutaj podkreślić, że parametry FORCE_SPEED oraz ENDMOVE_SPEED, dla elementów łukowych ścieżki ruchu, w momencie decyzji o korzystaniu z ruchów o zaawansowanej kontroli prędkości (bit 0 parametru opcje ustawiony na 1) i rezygnacji z łukowych przejść pomiędzy ruchami interpolowanymi liniowo (parametr promień równy 0 lub bit 2 parametru opcje ustawiony na 1) nadal należy definiować. Brak stosowania się do powyższego może prowadzić do nieoczekiwanego zachowania się urządzenia (wykonywanie ruchów do pozycji innych niż zdefiniowane z prędkościami innymi niż zdefiniowane).
Przykład 2. Ruch po ścieżce w kształcie litery „O” przy pomocy komendy MOVEABSSEQ z prędkością na łukach równą połowie prędkości w ruchu liniowym.
BASE(0, 1)
UNITS = 1
SPEED = 400
ACCEL = 1000
DECEL = ACCEL
lin_force_sp = SPEED ‘ prędkosc glowna ruchu liniowego (FORCE_SPEED)
lin_end_sp = SPEED * 0.5 ‘ predkosc koncowa ruchu liniowego (ENDMOVE_SPEED)
luk_force_sp = SPEED * 0.5 ‘ predkosc glowna w ruchu po luku (FORCE_SPEED)
luk_end_sp = SPEED * 0.5 ‘ predkosc koncowa w ruchu po luku (ENDMOVE_SPEED)
TABLE(1000, 0, 900, lin_force_sp, lin_end_sp, luk_force_sp, luk_end_sp)
TABLE(1006, 800, 900, lin_force_sp, lin_end_sp, luk_force_sp, luk_end_sp)
TABLE(1012, 800, –300, lin_force_sp, lin_end_sp, luk_force_sp, luk_end_sp)
TABLE(1018, 0, –300, lin_force_sp, lin_end_sp, luk_force_sp, luk_end_sp)
TABLE(1024, 0, 0, lin_force_sp, lin_end_sp, luk_force_sp, luk_end_sp)
MERGE = ON
adres_startowy = 1000
liczba_osi = 2
liczba_punktow = 5
opcje = 1
promien = 300
MOVEABSSEQ(adres_startowy, liczba_osi, liczba_punktow, opcje, promien)
WAIT IDLE
MERGE = OFF
Ruch w powyższym przykładzie oczywiście wykonywany jest przez dwie osie natomiast wykres został przedstawiony w przestrzeni trójwymiarowej, gdzie za współrzędną Z traktowana jest prędkość układu w celu przedstawienia zmian prędkość na różnych etapach ruchu w jak najbardziej obrazowy sposób.
Utworzenie pojedynczej ścieżki ruchu z dużej liczby punktów pomiędzy którymi ruch jest bardzo krótki wprowadza konieczność przetwarzania bardzo dużej liczby komend ruchu w krótkim czasie, co może prowadzić do problemów z profilem prędkości:
- kontroler ruchu może załadować tylko jedną komendę ruchu w czasie definiowanym przez parametr SERVO_PERIOD
- przy bardzo krótkich ruchach prędkość może się obniżać w celu osiągnięcia bieżącej końcowej pozycji z opóźnieniem zgodnym ze zdefiniowanym parametrem DECEL (dotyczy to korzystania z mechanizmu łączenia ruchów za pomocą flagi MERGE, nie korzystanie z niej prowadzi do oczywistych spadków prędkości do wartości równej zero pomiędzy poszczególnymi ruchami)
Komendy ruchów sekwencyjnych posiadają rozwiązanie powyższego problemu ponieważ umożliwiają one ładowanie ruchów do bufora w dwojaki sposób:
- jako sekwencje ruchów podstawowych
- jako ruch typu MOVESEQ lub MOVEABSSEQ
Istotną kwestią związaną z powyższym jest to, że w trakcie ładowania ruchów do bufora jako MOVESEQ lub MOVEABSSEQ pozbawiamy się możliwości korzystania z łukowych przejść pomiędzy liniowymi elementami ścieżki ruchu oraz mechanizmu zaawansowanego sterowania prędkością.
Przykład 3. Ruch po ścieżce eliptycznej zdefiniowanej przez grupę punktów wyznaczoną z równania parametrycznego przy parametrze zmieniającym się co 1 stopień.
BASE(0, 1)
UNITS = 1
SPEED = 1500
ACCEL = 15000
DECEL = ACCEL
DEFPOS(1000,0) ‘ zdefiniowanie punktu startowego ruchu
a = 1000 ‘ wielka polos elipsy
b = 500 ‘ mala polos elipsy
FOR d=0 TO 360
x = a * COS(d * PI / 180)
y = b * SIN(d * PI / 180)
TABLE(1000 + d * 2, x, y)
NEXT d
adres_startowy = 1000
liczba_osi = 2
liczba_punktow = 361
opcje = 4
promien = 0
adres_wyjscia = 2000
MOVEABSSEQ(adres_startowy, liczba_osi, liczba_punktow, opcje, promien, adres_wyjscia)
W celu zobrazowania przydatności zabiegu ładowania wszystkich ruchów do bufora jako jednej komendy dokonamy modyfikacji powyższego kodu poprzez wyłączenie opcji ładowania ruchów jako pojedynczej komendy MOVEABSSEQ (bit 2 parametru opcje równy 0) oraz załączenie flagi MERGE = ON. Kontroler posiada ustawienie parametru SERVO_PERIOD = 1ms. Efekt tego zabiegu (należy podkreślić, że poniższe animacje oraz wykres są zniekształcone co wynika z czasu próbkowania narzędzia do zbierania danych równego 100ms, jednak istotą jest tutaj zobrazowanie idei na co pozwalają poniższe materiały):
- przy ACCEL = DECEL = A (stosunkowo niewielka wartość):
- przy ACCEL = DECEL = 3 * A:
Jak widać na powyższych animacjach mechanizm łączenia ruchów (flaga MERGE) nie jest w takich przypadkach wystarczający.
Powyższy wykres przedstawia zmiany w czasie następujących parametrów:
- wykres czerwony – parametr IDLE (parametr jest równy false jeśli w danej chwili oś nie posiada w buforach załadowanych komend ruchu oraz true w przeciwnym wypadku) osi 1 (parametr opcje = 4 – ładowanie ruchów jako MOVEABSSEQ)
- wykres jasnoniebieski – prędkości (parametr opcje = 4)
- wykres zielony – parametr IDLE osi 1 (parametr opcje = 0, flaga MERGE = ON, ACCEL = DECEL = 3 * A)
- wykres żółty – prędkość (parametr opcje = 0, flaga MERGE = ON, ACCEL = DECEL = 3 * A)
- wykres fioletowy – parametr IDLE osi 1 (parametr opcje = 0, flaga MERGE = ON, ACCEL = DECEL = A)
- wykres ciemnoniebieski – prędkość (parametr opcje = 0, flaga MERGE = ON, ACCEL = DECEL = A)
Wykres oprócz efektów takich jak:
- brak utrzymywania stałej wartości prędkościami
- wydłużenie czasu trwania ruchu
- zależność wartości średniej jak i skoków prędkości (wysokości „górek” na wykresie) zależą od wartości przyspieszenia oraz opóźnienia pokazuje również wpływ odległości pomiędzy poszczególnymi punktami na stopień radzenia sobie z komendami ruchu przez kontroler – średnia wartość prędkości w odcinkach ruchu o większym zagęszczeniu punktów jest zdecydowanie mniejsza (zjawisko szczególnie widoczne na żółtym wykresie; przedstawiony wcześniej sposób wyznaczania punktów na elipsie wiąże się ze zmianami gęstości ich występowania w zależności od promienia krzywizny – im mniejszy promień tym więcej punktów).
Przykład 4. Użycie komendy MOVEABSSEQ dla 6 osi.
TABLE(1000, 0, 0, 0, 0, 1200, 0)
TABLE(1010, 300, 0, 0, 300, 1200, 0)
TABLE(1020, 300, 300, 0, 300, 300, 300)
TABLE(1030, 600, 300, 0, 600, 300, 0)
TABLE(1040, 600, 0, 0, 600, 1200, 0)
TABLE(1050, 600, 0, 450, 600, 1200, 450)
BASE(0, 1, 2, 3, 4, 5)
UNITS = 1
SPEED = 75
ACCEL = 5000
DECEL = ACCEL
‘ wyzerowanie parametru przechowującego liczbę komend załadowanych do bufora MTYPE
MOVE_COUNT = 0
‘ definicja pozycji startowej
DEFPOS(0, 300, 0, 0, 300, 0)
‘ ustawienie odstepu pomiedzy blokami danych dla kolejnych pozycji na 10
‘ liczba 256 pojawia sie tutaj poniewaz do ustawiania odstepu słuza bity 8 – 13
‘ a mnozenie przez 256 uwzglednia przesuniecie o pierwszych 8 bitow
opcje = 10 * 256
adres_startowy = 1000
liczba_osi = 6
liczba_punktow = 6
promien = 80
MERGE = ON
MOVEABSSEQ(adres_startowy, liczba_osi, liczba_punktow, opcje, promien)
‘ ruch MOVEABS który zostanie połączony (MERGE = ON) z MOVEABSSEQ
MOVEABS(800, –200, 200, 800, 1300, 200)
WAIT IDLE
MERGE = OFF
Pojawiający się w kodzie parametr MOVE_COUNT przechowuje liczbę komend załadowanych do bufora MTYPE danej osi. Parametr ten jest inkrementowany wraz z załadowaniem komendy ruchu lub przeładowaniem jej w przypadku ruchów samopowtarzalnych.
Rezultat wywołania powyższego kodu:
Powyższa symulacja została skonfigurowana w taki sposób, aby ruch grup osi 0, 1, 2 oraz 3, 4, 5 prezentowany był przez osobne trajektorie w przestrzeni 3D. Czerwona ścieżka odpowiada za ruch osi 0, 1, 2 natomiast żółta za ruch osi 3, 4, 5.
W trakcie przyglądania się symulacji możemy dostrzec dziwne zachowanie objawiające się ruchem osi 3, 4, 5 tylko w niektórych momentach ruchu pierwszych trzech. W celu zbadania co się tak naprawdę dzieje podczas wykonywania całego ruchu spójrzmy na zachowanie bufora MTYPE dla poszczególnych osi.
W momencie w którym na pierwszych trzech osiach wykonywany jest ruch MSPHERICAL na trzech pozostałych widnieje tajemniczy ruch MOVE. Prześledźmy teraz na trzech wykresach (wartości poszczególnych parametrów na wykresach zostały wyskalowane w taki sposób aby ułatwić analizę) jak zachowują się następujące parametry:
- parametry MTYPE osi 0 (w buforze MTYPE każdej komendzie ruchu odpowiada wartość liczbowa dlatego jesteśmy w stanie na wykresie badać jakie komendy w danej chwili były wykonywane)
- parametr MTYPE kolejno osi 3, 4, 5
- parametr MOVE_COUNT osi 0 (tylko dla osi 0 ponieważ liczba załadowanych komend do bufora MTYPE dla każdej osi w tym przypadku będzie równa)
- parametr ENDMOVE (przechowujący absolutną końcową pozycję będącą wynikiem wykonania aktualnie załadowanej komendy do bufora MTYPE) kolejno dla osi 3, 4 oraz 5
- parametr DPOS (przechowujący informację o aktualnej wyznaczonej pozycji osi) kolejno dla osi 3, 4 oraz 5
- linia czerwona – parametr MTYPE osi 0 (zmiany pomiędzy MOVEABS = 2, a MSPHERICAL = 31)
- linia jasnoniebieska – parametr MTYPE osi 3 (zmiany pomiędzy MOVEABS = 2, a MOVE = 1)
- linia czarna – parametr MOVE_COUNT
- linia zielona – parametr ENDMOVE osi 3
- linia żółta – parametr DPOS osi 3
- linia czerwona – parametr MTYPE osi 0 (zmiany pomiędzy MOVEABS = 2, a MSPHERICAL = 31)
- linia jasnoniebieska – parametr MTYPE osi 3 (zmiany pomiędzy MOVEABS = 2, a MOVE = 1)
- linia czarna – parametr MOVE_COUNT
- linia fioletowa – parametr ENDMOVE osi 4
- linia ciemnoniebieska – parametr DPOS osi 4
- linia czerwona – parametr MTYPE osi 0 (zmiany pomiędzy MOVEABS = 2, a MSPHERICAL = 31)
- linia jasnoniebieska – parametr MTYPE osi 3 (zmiany pomiędzy MOVEABS = 2, a MOVE = 1)
- linia czarna – parametr MOVE_COUNT
- linia pomarańczowa – parametr ENDMOVE osi 5
- linia miętowa – parametr DPOS osi 5
Stworzone wykresy pokazują, że ruch osi 3, 4, 5 wykonywany jest wyłącznie w chwilach w których osie 0, 1, 2 wykonują ruch MSPHERICAL i kryje się on właśnie pod tajemniczymi komendami MOVE (ruchy MOVEABS nie prowadzą do wykonania żadnego ruchu). Związane jest z tym pewnego rodzaju zagrożenie ponieważ w sytuacji w której promień łuku jest mały, a my zdecydujemy się na rezygnacje z uwzględniania ruchu osi 3, 4, 5 w interpolacji (czego można dokonać za pomocą parametru INTERP_FACTOR dla komend MOVE, MOVEABS, MHELICAL {tylko dla trzeciej osi} oraz ich wersji z końcówką SP; MOVEASBSEQ składa się właśnie z komend MOVEABS / MOVEABSSP) może dojść do sytuacji w której w bardzo krótkich odcinkach czasu osie 3, 4, 5 (w tym momencie pracujące jako nadążne) będą chciały pokonać duże dystanse.
W chwili używania komendy MOVEABSSEQ bez łukowych przejść sytuacja normuje się i pozostaje w zgodzie z intuicją jak pokazuje poniższa animacja.
Autor: Artur Sobas
Świeżo upieczony Inżynier, student II stopnia Inżynierii Mechatronicznej na Akademii Górniczo – Hutniczej im. Stanisława Staszica w Krakowie. Związany z firmą od czasów szkoły średniej poprzez uczestnictwo w szkoleniach i późniejsze praktyki. Obecnie Doradca Techniczny na co dzień zajmujący się projektowaniem stanowisk szkoleniowych oraz demonstracyjnych. Od wielu lat w kręgu jego zainteresowań miejsce znajduje szeroko pojęta automatyka.