V tomto díle seriálu o CAN bus skriptech v programu PP2CAN si ukážeme jak simulovat data z joysticku s CAN sběrnicí, který používá protokol SAE J1939. Zároveň si ukážeme funkce pro snadné nastavení dat do CAN zprávy, pokud data nejsou zarovnána na jednotlivé bajty a jejich délka není násobkem 8 bitů.
Aby byl tento příklad funkční, je třeba použít překladač CAN bus skriptů verze 1.90. Tato verze překladače je součástí programu PP2CAN verze 3.041. Novinkou je v ní kromě podpory funkcí pro snadné dekódování dat z CAN zprávy i opačná funkce snadného vkládání dat do CAN zprávy a také obsahuje počáteční podporu formátu dat unsigned64 a int64. Poslední verzi software najdete ke stažení vždy zde.
Pokud si chcete skript otestovat, ale nemáte po ruce joystick, je možné použít softwarový emulátor - virtuální joystick. Jeden takový který bez problému se skriptem funguje najdete zde.
Norma SAE J1939 popisuje zprávu kterou použijeme takto:
PGN 64982 Basic Joystick Message 1
Parameter Group Number: 64982 (0x00FDD6)
- Start Position / Length / Parameter Name SPN
- 1.1 - 2 bits Joystick 1 X-Axis Neutral Position Status 2675
- 1.3 - 2 bits Joystick 1 X-Axis Lever Left Negative Position Status 2670
- 1.5 - 2 bits Joystick 1 X-Axis Lever Right Positive Position Status 2665
- 1.7 - 2 10 bits Joystick 1 X-Axis Position 2660
- 3.1 - 2 bits Joystick 1 Y-Axis Neutral Position Status 2676
- 3.3 - 2 bits Joystick 1 Y-Axis Lever Back Negative Position Status 2671
- 3.5 - 2 bits Joystick 1 Y-Axis Lever Forward Positive Position Status 2666
- 3.7 - 4 10 bits Joystick 1 Y-Axis Position 2661
- 5.5 - 2 bits Joystick 1 Y-Axis Detent Position Status 2681
- 5.7 - 2 bits Joystick 1 X-Axis Detent Position Status 2680
- 6.1 - 2 bits Joystick 1 Button 4 Pressed Status 2688
- 6.3 - 2 bits Joystick 1 Button 3 Pressed Status 2687
- 6.5 - 2 bits Joystick 1 Button 2 Pressed Status 2686
- 6.7 - 2 bits Joystick 1 Button 1 Pressed Status 2685
- 7.1 - 2 bits Joystick 1 Button 8 Pressed Status 2692
- 7.3 - 2 bits Joystick 1 Button 7 Pressed Status 2691
- 7.5 - 2 bits Joystick 1 Button 6 Pressed Status 2690
- 7.7 - 2 bits Joystick 1 Button 5 Pressed Status 2689
- 8.1 - 2 bits Joystick 1 Button 12 Pressed Status 2696
- 8.3 - 2 bits Joystick 1 Button 11 Pressed Status 2695
- 8.5 - 2 bits Joystick 1 Button 10 Pressed Status 2694
- 8.7 - 2 bits Joystick 1 Button 9 Pressed Status 2693
Naším skriptem si budeme simulovat zvýrazněné položky. Celý skript je ke stažení v archivu zip zde. Archiv obsahuje i soubor EYE, který můžeme použít pro zobrazení dat generovaných skriptem na CAN (nebo simulovaných přes virtuální CAN - V2CAN) v nástroji Signal receiver nebo Data view. Při použití nástroje Signál receiver je dle potřeby nutno upravit položku TX - směr dat. Pokud odesíláme data na skutečný CAN, je třeba dekódovat pro zobrazení hodnot směr TX. V režimu V2CAN pak směr RX - data čteme v režimu V2CAN zpět. Nástroj Data view zobrazuje oba směry.
Skript je uveden níže a obsahuje komentáře, které podrobně vysvětlují jeho funkci. Pokud se Vám výpis skriptu nezobrazuje, najeďte na jeho pole myší.
script: //Typ skriptu //Chci data generovat periodicky - tedy periodicky typ skriptu. type = TIMER_SCRIPT; end // Definice promenych variables: unsigned x_neutral; unsigned x_left; unsigned x_right; unsigned y_neutral; unsigned y_back; unsigned y_forward; unsigned64 value; double x; double y; bool button_1; bool button_2; end // Definice objektu // Je definovan jeden objekt a to objekt CAN zpravy. objects: obj_can_msg can_msg; end // Init sekce - tato sekce je volana jednou po spusteni skriptu. // Sekce se pouziva na inicializaci dat. init: logs("Simulace joysticku dle SAE J1939"); log_endl(); //Nastavuji datove bajty na FF, tedy nevyuzite polozky budou signalizovat neznama data. can_msg.set_all(0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF); //Rozsireny - 29 bitovy identifikator. can_msg.stext=true; //Nejedna se o RTR, ale o datovou zpravu. can_msg.rtr=false; //8 datovych bajtu can_msg.size = 8; //29 bitove ID: 0xCFDD6FE=217962238 ,PGN:FDD6 can_msg.set_ID29(217962238); //Skript bude spousten kazdych 100ms a se stejnou periodou se budou generovat data. //Casovani lze ovládat sliderem v okne skriptu, nicmene timto si prednastavim pozadovanou hodnotu. ui_set_timer_script_period (100); end body: //------------------------------------------------------ x_neutral = 0; x_left = 0; x_right = 0; //Ctu hodnotu X pripojeneho joysticku (X-leva/prava). //Ctena hodnota je v rozsahu 0-65535, stred odpovida 32767. //Data dle SAE J1939 maji rozsah 0-1000. Smer neni rozlisovan a udava se //pomoci Left/Right Positive Position Status. x = ui_joy_x(0); //Leva strana if(x>32767) { x_left = 1; x_right = 0; x = x-32767; x = (x/32767.0) * 1000.0; } //Neutral else if(x==32767) { x_left = 0; x_right = 0; x = x-32767; x = 0; } //Prava strana else { x_left = 0; x_right = 1; x = 32768-x; x = (x/32768.0) * 1000.0; } //Okno skriptu obsahuje univerzalni ovladaci a zobrazovaci prvky. //Do prvniho okna pro zobrazeni ciselne hodnoty vypisu vypoctenou hodnotu. ui_set_d0(x); //Osetreni aby maximalni hodnota byla 1000 a bylo ji vzdy dosazeno. //Diky nepresnostem nemusi vypocet zmeny rozsahu koncit presne na hodnote 1000. if(x>999) { x=1000; } //Dle normy by snimani neutralni hodnoty melo byt zajisteno jinym mechanismem //nez je mereni polohy (bezpecnost). //Neutralni polohu budeme signalizovat v rozsahu -10 az 10 od stredu. if(x<10) { x_neutral=1; } //Jelikoz se jedna o konverzi z double na unsigned, nefunguje automaticke pretypovani timto smerem, //provedeme tak nejprve urceni cele casti a prevod do signed a pak konverzi na unsigned. //Konverze unsigned na unsigned64 je automaticka. value = i2u(truncd(x)); //Nastavujeme hodnotu x_neutral jako polozku Neutral Position Status do CAN zpravy. //Metoda set_value objektu CAN zpravy ma parametry: // - index prvniho bitu (0), CAN zprava ma 8 datovych bajtu, tedy 64 bitu, index 0 az 63 // - bitova delka (2 bity) // - data se nastavuji ve formatu little endian (false) // - data nejsou signed (false) //Status je dle SAE J1939 dvoubitovy. My signalizujeme 0/1, stavy neznama data zde neuvazujeme, //jsou vzdy znama, nicmene u dalsich nevyuzitych polozek jsou bity nastaveny na 1 - neznama data. can_msg.set_value(x_neutral,0,2,false,false); //Nastaveni statusu Lever Left Negative Position Status. can_msg.set_value(x_left,2,2,false,false); //Nastaveni statusu Lever Right Positive Position Status. can_msg.set_value(x_right,4,2,false,false); //Nastaveni X-Axis Position. can_msg.set_value(value,6,10,false,false); //------------------------------------------------------ //Identicky kod avsak tentokrat pro osu Y. y_neutral = 0; y_back = 0; y_forward = 0; y = ui_joy_y(0); if(y>32767) { y_back = 1; y_forward = 0; y = y-32767; y = (y/32767.0) * 1000.0; } else if(y==32767) { y_back = 0; y_forward = 0; y = y-32767; y = 0; } else { y_back = 0; y_forward = 1; y = 32768-y; y = (y/32768.0) * 1000.0; } ui_set_d1(y); if(y>1000) { y=1000; } if(y<10) { y_neutral=1; } value = i2u(truncd(y)); can_msg.set_value(y_neutral,16,2,false,false); can_msg.set_value(y_back,18,2,false,false); can_msg.set_value(y_forward,20,2,false,false); can_msg.set_value(value,22,10,false,false); //------------------------------------------------------ //Zobrazeni hodnoty tlacitek joysticku ve tretim a ctvrtem okne pro zobrazeni ciselne hodnoty //v okne skriptu. ui_set_b0(ui_joy_b(0,0)); ui_set_b1(ui_joy_b(0,1)); //Ulozeni hodnoty tlacitek joysticku. button_1 = ui_joy_b(0,0); button_2 = ui_joy_b(0,1); //Vlozeni hodnot tlacitek do CAN zpravy. can_msg.set_value(button_1,46,2,false,false); can_msg.set_value(button_2,44,2,false,false); //------------------------------------------------------ //Odeslani zpravy na CAN sbernici. can_msg.send(); end
Další díly seriálu:
- Díl 1: Periodické generování dat na CAN sběrnici.
- Díl 2: Uživatelské prvky pro řízení skriptu
- Díl 3: Simulace joysticku dle SAE J1939
- Díl 4: Monitorování a zápis událostí do souboru CSV
- Díl 5: Měření periody a zápis do CSV pomocí přiřazení objektu
- Díl 6: Komunikace pomocí TCP
- Díl 7: Komunikace pomocí sériové linky
- Díl 8: PID regulátor
- Díl 9: Výpočet CRC a objekt obj_dataset
- Díl 10: Volání funkce z externí DLL