Ondras8_CZ
Cestující
Ahoj všem,
mám joystick thrustmaster hotas x a podařilo se mi ho rozchodit na open rails, včetně plynulé regulace výkonu.
Koho nezajímá backstory, nechť pokračuje na další odstavec.
Přišla mi škoda, že mám doma thrustmaster hotas x a nelze ho využít pro ovládání open rails. Procházel jsem fóra, googlil, ptal se AI ale řešení nenalezeno. Pouze program Joy2Key, kterým se ale nedá ovládat výkon, jelikož hodnoty předává jako klávesy. Musel jsem si tedy poradit sám. Po chvíli bádání jsem zjistil, že při spuštění open rails se spustí lokální server http://localhost:2150/ kde je mimo jiné možné ovládat soupravu přes webové rozhraní. Zjistil jsem, že to jsou jen jednoduché HTTP post požadavky na API openrails. Shodou náhod firmware od thrustmaster umí ukládat log z joysticku do textového souboru ve fortmátu osa - hodnota - čas. Vytvořil jsem tedy za pomocí AI (jelikož nejsem programátor, umím jen základy) první verzi, která četla textový soubor, ten poté převedla na správné hodoty co OR očekává a světe div se - mohl jsem lokomotivu ovládat přes joystick, včetně plynulého ovládání.
Ale je zde problém limitace na jednoho výrobce, takže po mnoha hodinách trápení ( a minus jedné klávesnici) je na světe program, který detekuje připojené joysticky (i jiných výrobců), data průběžně čte a odesílá jako POST na API open rails. Ne vše je však možné přes api, proto API využívám jen na regulaci výkonu, vlakové brzdy a rekuperace.
Pro běh je nutné mít na PC nainstalovaný Python (včetně PATH), poté nainstalovat pygame requests a psutil a program joytokey https://joytokey.net/en/
Po spuštění program zkontroluje, jestli běží joytokey, a pokud ne, spustí ho. Jelikož třeba houkačka v Olomoucké T3 šla, ale ne na ELL 193. To samé pantografy. Proto mám na zbytek kláves na joysticku nastavení přes joytokey
Před spuštěním kódu je nutné mít načtenou mapu v openrails!
Poté program průběžně čte hodnoty z os a posílá je na server.
Ještě zasílám krátké video jako ukázku Video na Youtube
Kdo by měl zájem, může kód níže využít, ale bez jakékoliv záruky a podpory.
mám joystick thrustmaster hotas x a podařilo se mi ho rozchodit na open rails, včetně plynulé regulace výkonu.
Koho nezajímá backstory, nechť pokračuje na další odstavec.
Přišla mi škoda, že mám doma thrustmaster hotas x a nelze ho využít pro ovládání open rails. Procházel jsem fóra, googlil, ptal se AI ale řešení nenalezeno. Pouze program Joy2Key, kterým se ale nedá ovládat výkon, jelikož hodnoty předává jako klávesy. Musel jsem si tedy poradit sám. Po chvíli bádání jsem zjistil, že při spuštění open rails se spustí lokální server http://localhost:2150/ kde je mimo jiné možné ovládat soupravu přes webové rozhraní. Zjistil jsem, že to jsou jen jednoduché HTTP post požadavky na API openrails. Shodou náhod firmware od thrustmaster umí ukládat log z joysticku do textového souboru ve fortmátu osa - hodnota - čas. Vytvořil jsem tedy za pomocí AI (jelikož nejsem programátor, umím jen základy) první verzi, která četla textový soubor, ten poté převedla na správné hodoty co OR očekává a světe div se - mohl jsem lokomotivu ovládat přes joystick, včetně plynulého ovládání.
Ale je zde problém limitace na jednoho výrobce, takže po mnoha hodinách trápení ( a minus jedné klávesnici) je na světe program, který detekuje připojené joysticky (i jiných výrobců), data průběžně čte a odesílá jako POST na API open rails. Ne vše je však možné přes api, proto API využívám jen na regulaci výkonu, vlakové brzdy a rekuperace.
Pro běh je nutné mít na PC nainstalovaný Python (včetně PATH), poté nainstalovat pygame requests a psutil a program joytokey https://joytokey.net/en/
Po spuštění program zkontroluje, jestli běží joytokey, a pokud ne, spustí ho. Jelikož třeba houkačka v Olomoucké T3 šla, ale ne na ELL 193. To samé pantografy. Proto mám na zbytek kláves na joysticku nastavení přes joytokey
Před spuštěním kódu je nutné mít načtenou mapu v openrails!
Poté program průběžně čte hodnoty z os a posílá je na server.
Ještě zasílám krátké video jako ukázku Video na Youtube
Kdo by měl zájem, může kód níže využít, ale bez jakékoliv záruky a podpory.
Python:
import pygame
import requests
import time
import psutil
import subprocess
from datetime import datetime # Import pro časové razítko
# Konfigurace
SERVER_URL = 'http://localhost:2150/API/CABCONTROLS' # URL serveru s portem 2150
POLL_INTERVAL = 0.2 # Interval mezi jednotlivými kontrolami (v sekundách)
WAIT_TIME = 0.05 # Čas čekání mezi jednotlivými instrukcemi (v sekundách)
JOY2KEY_PATH = r"C:\Program Files (x86)\JoyToKey\JoyToKey.exe" # Cesta k programu JoyToKey
# Mappings
KEY_MAPPINGS = {
'Button4': 'dynamic_brake',
'Slider0': 'dynamic_brake',
'Z': 'throttle_train_brake'
}
# Dynamické proměnné s počátečními hodnotami
previous_values = {
'throttle': None,
'train_brake': None,
'dynamic_brake': None,
}
# Funkce pro spuštění JoyToKey, pokud neběží
def check_and_start_joytokey():
joytokey_process_name = "JoyToKey.exe"
is_running = any(proc.name() == joytokey_process_name for proc in psutil.process_iter())
if not is_running:
subprocess.Popen([JOY2KEY_PATH])
print(f"{joytokey_process_name} nebyl spuštěn. Spouštím...")
def process_joystick_data(joystick):
global previous_values
# Načtení hodnot os
x_axis = joystick.get_axis(0)
y_axis = joystick.get_axis(1)
z_axis = joystick.get_axis(2)
rz_axis = joystick.get_axis(3)
slider0 = joystick.get_axis(4)
button_states = [joystick.get_button(i) for i in range(12)] # Předpokládáme, že joystick má 12 tlačítek
# Inicializace změn
throttle_value, brake_value = None, None
dynamic_brake = None
# Zpracování tlačítek
for i, state in enumerate(button_states):
if state:
button_name = f'Button{i+1}'
action = KEY_MAPPINGS.get(button_name)
if action == 'dynamic_brake':
dynamic_brake = previous_values['dynamic_brake']
# Zpracování os
if z_axis is not None:
# THROTTLE a TRAIN_BRAKE výpočty
if z_axis <= 0:
# Invertování hodnoty pro THROTTLE, pokud je v rozmezí -1.0 až 0.0
throttle_value = round(-z_axis, 3)
throttle_value = min(max(throttle_value, 0.0), 1.0) # Ošetření rozsahu 0.0 až 1.0
else:
throttle_value = None
if z_axis >= 0:
# Ošetření hodnoty pro TRAIN_BRAKE, pokud je v rozmezí 0.0 až 1.0
brake_value = round(z_axis, 3)
brake_value = min(max(brake_value, 0.0), 1.0) # Ošetření rozsahu 0.0 až 1.0
else:
brake_value = None
if slider0 is not None:
# Zpracování slider0
if slider0 <= -0.9:
# Pokud je hodnota -1 až -0.9, odečítej po 0.1
dynamic_brake = round(max(0.0, (previous_values['dynamic_brake'] - 0.1)), 3) if previous_values['dynamic_brake'] is not None else 0.0
elif -0.9 < slider0 <= -0.08:
# Pokud je hodnota -0.9 až -0.08 (mimo), odečítej po 0.05
dynamic_brake = round(max(0.0, (previous_values['dynamic_brake'] - 0.05)), 3) if previous_values['dynamic_brake'] is not None else 0.0
elif 0.08 < slider0 < 0.9:
# Pokud je hodnota 0.08 až 0.9 (mimo), přičítej po 0.05
dynamic_brake = round(min(1.0, (previous_values['dynamic_brake'] + 0.05)), 3) if previous_values['dynamic_brake'] is not None else 0.05
elif slider0 >= 0.9:
# Pokud je hodnota 0.9 až 1.0, přičítej po 0.1
dynamic_brake = round(min(1.0, (previous_values['dynamic_brake'] + 0.1)), 3) if previous_values['dynamic_brake'] is not None else 0.1
else:
dynamic_brake = previous_values['dynamic_brake'] if previous_values['dynamic_brake'] is not None else 0.0
# Porovnání a uložení změn
changes = {}
for key, value in {
'throttle': throttle_value,
'train_brake': brake_value,
'dynamic_brake': dynamic_brake,
}.items():
if value is not None and value != previous_values[key]:
changes[key] = value
previous_values[key] = value
return changes
def send_data_to_server(changes):
if not changes:
return
json_data = []
for key, value in changes.items():
type_name = {
'throttle': 'THROTTLE',
'train_brake': 'TRAIN_BRAKE',
'dynamic_brake': 'DYNAMIC_BRAKE'
}[key]
json_data.append({"TypeName": type_name, "Value": value})
if json_data:
try:
response = requests.post(SERVER_URL, json=json_data)
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
print(f"[{current_time}] Odesláno: {json_data}, Odezva: {response.status_code}, Text: {response.text}")
except requests.RequestException as e:
print(f"Chyba při odesílání dat na server: {e}")
def main():
pygame.init()
pygame.joystick.init()
if pygame.joystick.get_count() == 0:
print("No joystick detected. Please connect a joystick and restart the program.")
return
joystick = pygame.joystick.Joystick(0)
joystick.init()
print("Joystick initialized: " + joystick.get_name())
check_and_start_joytokey()
try:
while True:
pygame.event.pump() # Zpracování událostí (aby se joystick aktualizoval)
changes = process_joystick_data(joystick)
send_data_to_server(changes)
time.sleep(POLL_INTERVAL)
except KeyboardInterrupt:
print("Program byl ukončen uživatelem.")
finally:
pygame.quit()
if __name__ == "__main__":
main()