İçeriğe geç
TREN
Atlıhan Harita

Lixel OpenAPI Kullanım Kılavuzu · Python

Hızlı Başlangıç

Bölüm 08.1 / 09Kılavuz sürümü v1.1.0Türkçe

Bu sayfa, en kısa yolla tek bir istek-yanıt döngüsünü adım adım gösterir: cihaza bağlanma → mesaj kodlayıcıyı hazırlama → istek gönderme → yanıt alma. Örnekler projenin Python istemci sarmalayıcısını kullanır ve arayüze bağlı değildir.

Ön Koşullar

Başlamadan önce şunlardan emin olun:

  1. Cihaz açık ve ana bilgisayarınızla aynı ağda (USB veya Wi-Fi, bkz. Bağlantı ve Kimlik Doğrulama).
  2. Bir OpenAPI Key anahtarınız var (nasıl alınacağı: Bağlantı ve Kimlik Doğrulama · OpenAPI Key Talep Etme).
  3. Ana bilgisayarda örnek proje ile bağımlılıkları yüklü bir Python ortamı var (aşağıya bakın).

Ortam ve bağımlılıklar

ÖğeGereksinim
İşletim sistemiLinux, Windows (arayüz sırasıyla PySide2 ve PySide6 kullanır)
Python3.8 veya üzeri
MQTT istemcisipaho-mqtt, 2.0.0 veya üzeri
Codecprotobuf, grpcio-tools (proto dosyasını derlemek için)
Nokta bulutu açma (isteğe bağlı)lz4, zstandard (yalnızca gerçek zamanlı nokta bulutuna abone olurken gerekir)

Örnek projeyi alma ve bağımlılıkları yükleme

Örnek proje, herkese açık Lixel_OpenAPI deposudur. Aşağıdaki komutlar Ubuntu 22.04 içindir; Windows için depodaki README.md dosyasına bakın:

sudo apt-get update
sudo apt-get install -y python3-pip python3-venv git
git clone --branch 1.1.0 https://github.com/xgrids/Lixel_OpenAPI.git
cd Lixel_OpenAPI                    # repository root
python3 -m venv venv
source venv/bin/activate            # after activation you can use python and pip directly
unset PYTHONPATH                    # needed on machines with ROS installed, to avoid ROS packages leaking in
pip install --upgrade pip
pip install -r python/requirements.txt     # includes paho-mqtt, protobuf, grpcio-tools
pip install lz4 zstandard           # install when you need the real-time point cloud

Şunlara dikkat edin:

  • Sistemin Python paketlerini değil, bir sanal ortam kullanın: Ubuntu 22.04, python/requirements.txt dosyasının gerektirdiği 5.26.0 sürümünün altında olan python3-protobuf 3.12.4 ile gelir.
  • Ubuntu 22.04'te varsayılan olarak pip, python3-venv veya python komutu yoktur. Önce yukarıdaki paketleri yükleyin ve python komutunu yalnızca sanal ortamı etkinleştirdikten sonra kullanın.
  • Aşağıdaki tüm Python kod parçaları python/ dizininde çalıştırılmalıdır (önce cd python yapın, örneğin kod parçasını python/quick.py olarak kaydedip python quick.py çalıştırın). Aksi halde from example.core import … ifadesi example paketini bulamaz. src/generate_proto.py gibi python/ önekli komutlar depo kök dizininden çalıştırılır.
  • python/requirements.txt arayüz bağımlılıklarını içermez; arayüzü çalıştırmak için ayrıca python/requirements-linux.txt (PySide2) veya python/requirements-windows.txt (PySide6) dosyasını yükleyin.

Adım 1: Protobuf Modülünü Hazırlama

Tüm iş mesajları Protobuf kullanır. Önce proto tanımını bir Python modülüne derleyin:

python python/src/generate_proto.py

Not: Derleme, geçerli ortamın grpc_tools.protoc aracını kullanır; böylece gencode sürümü çalışma zamanındaki protobuf sürümüyle uyumlu kalır. Çalışma zamanında, ortamlar arası C uzantısı uyumsuzluklarını önlemek için PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION=python ayarlanması önerilir.

Adım 2: Cihaza Bağlanma

Bağlanmak için istemci sarmalayıcısını kullanın. Kablolu bağlantıda cihazın varsayılan adresi 192.168.55.1, MQTT portu 1883'tür. Aşağıdaki örnek L2PRO için geçerlidir; MQTTS kullanan modeller için Bağlantı ve Kimlik Doğrulama bölümüne bakın. Bu modeller use_tls=True, port=8883 ve üretici tarafından verilen kimlik bilgilerini gerektirir:

from example.core import ClientOptions, OpenApiClient

opts = ClientOptions(
    host="192.168.55.1",
    port=1883,
    openapi_key="<provided by XGRIDS>",
)

with OpenApiClient(opts) as client:
    print("connected:", client.is_connected)

with ifadesi girişte bağlanır, çıkışta bağlantıyı keser. Başarısız bir bağlantı istisna oluşturur: erişilemeyen bir adres veya kapalı port OSError oluşturur (ConnectionRefusedError dahil; Python 3.10+ sürümünde ağ zaman aşımı TimeoutError olur). TCP bağlantısı kurulmuş ancak 10 saniye içinde başarılı bir CONNACK gelmemişse (broker'ın bağlantıyı reddetmesi dahil) TimeoutError oluşur; zaman aşımı süresi ClientOptions.connect_timeout ile ayarlanır.

Adım 3: İlk İsteğinizi Gönderme

En basit "cihaz bilgisi sorgulama" isteğini gönderin ve yanıtı bekleyin. İstek-yanıt, senkron bir çağrıdır: önce yanıt konusuna abone olur, ardından isteği yayınlar, sonra yanıt gelene kadar bekler:

from example.core import ClientOptions, OpenApiClient

opts = ClientOptions(host="192.168.55.1", openapi_key="<provided by XGRIDS>")

with OpenApiClient(opts) as client:
    rsp = client.request(
        req_topic="lixel/application/request/device_info",
        req_message="DeviceInfoRequest",
        payload={},                                   # an empty payload is fine
        rsp_topic="lixel/application/response/device_info",
        rsp_message="DeviceInfoResponse",
    )
    print(rsp)                                        # already decoded into a dict

request() işlevi OpenAPI Key anahtarını başlığa otomatik olarak ekler. Dönüş değeri; cihaz modeli, firmware sürümü, kamera listesi gibi bilgileri içeren çözülmüş bir sözlüktür (dict).

Adım 4: Raporlara Abone Olma

İstek-yanıtın yanı sıra birçok veri cihaz tarafından kendiliğinden bildirilir. Saniyede bir alınan cihaz durumuna abone olun:

import time
from example.core import ClientOptions, OpenApiClient


def on_status(topic, data):      # data is already decoded into a dict
    print(topic, data)


opts = ClientOptions(host="192.168.55.1", openapi_key="<provided by XGRIDS>")
with OpenApiClient(opts) as client:
    client.subscribe(
        "lixel/application/report/device_status",
        "DeviceStatusReport",
        on_status,
    )
    time.sleep(5)                # keep the connection alive to receive reports

subscribe() hemen döner; bu nedenle geri çağırmanın (callback) tetiklenmesi için programı çalışır durumda tutun. Geri çağırmada oluşan bir istisna kaydedilir (Python varsayılan olarak terminale yazdırır) ve diğer abonelikleri kesintiye uğratmaz.

Not: OpenAPI tarafından sunulan arayüzler arasında yalnızca kalp atışı (heartbeat) JSON metni kullanır. Kalp atışına abone olurken message için boş bir dize geçin; geri çağırma sözlük (dict) değil, bir dize alır.

Not: Kalp atışının alınması yalnızca cihazın ağa bağlı olduğunu gösterir, işlemler için hazır olduğunu göstermez. Açılıştan hemen sonra port açıktır ve kalp atışı gönderilir, ancak device_info gibi isteklere bir süre yanıt verilmeyebilir. Açılıştan sonra önce device_info isteğini yeniden deneyin, başarılı olduktan sonra diğer istekleri gönderin.

Tam Örnek: Tek Bir Tarama

Tipik bir uçtan uca akış şöyledir: bağlanma → bekleme durumunu doğrulama → taramayı başlatma → cihazın gerçekten tarama yaptığını bekleme → bir süre tarama → taramayı durdurma → bekleme durumunu bekleme.

connect → subscribe device_status → confirm standby → AC_START → wait for scanning → scan → AC_STOP → wait for standby → disconnect

Başlatma ve durdurma işlemlerinin ikisi de asenkrondur. AC_START yanıtı yalnızca cihazın isteği aldığını gösterir; ardından cihaz sırasıyla bekleme → başlıyor → tarama durumlarına geçer. AC_START komutundan 14-15 saniye sonra taramaya geçildiği ölçülmüştür. Tarama başlamadan gönderilen AC_STOP ertelenir ve cihaz taramaya girmez. AC_STOP sonrasında cihaz durduruluyor durumundan geçerek beklemeye döner; durduruluyor durumuna girişten itibaren bekleme durumuna dönüş 43-46 saniye sürmüştür (3 çalıştırma). AC_STOP gönderildiği andan itibaren tek bir çalıştırmada 52,1 saniye ölçülmüştür (Lixel L2Pro, firmware V3.2.1, durum saniyede bir bildirilir, 1 saniye hassasiyet). Bu nedenle örnek, report/device_status konusuna abone olur, modeling_state değerini okur ve sabit bir sleep yerine hedef durumu bekler. modeling_state değerleri için Hata Kodları · Scan status codes bölümüne bakın.

import threading
import time
from example.core import ClientOptions, OpenApiClient

SCAN_READY = 0x1204012C      # EC_ScanReady, standby
SCAN_MODELING = 0x1204012E   # EC_ScanModeling, scanning

state = {"modeling_state": None}
cond = threading.Condition()


def on_status(topic, data):
    with cond:
        state["modeling_state"] = data["modeling_state"]
        cond.notify_all()


def wait_for(target, timeout):
    deadline = time.monotonic() + timeout
    with cond:
        while state["modeling_state"] != target:
            remaining = deadline - time.monotonic()
            if remaining <= 0:
                return False
            cond.wait(remaining)
    return True


def modeling(client, payload):
    return client.request(
        req_topic="lixel/application/request/modeling",
        req_message="ModelingRequest",
        payload=payload,
        rsp_topic="lixel/application/response/modeling",
        rsp_message="ModelingResponse",
    )


opts = ClientOptions(host="192.168.55.1", openapi_key="<provided by XGRIDS>")
with OpenApiClient(opts) as client:
    client.subscribe("lixel/application/report/device_status",
                     "DeviceStatusReport", on_status)
    if not wait_for(SCAN_READY, 10):
        raise SystemExit("device not in standby: 0x%X" % (state["modeling_state"] or 0))   # values: see scan status codes on page 07
    rsp = modeling(client, {"action": "AC_START", "project_name": "demo",
                            "record_mode": "RM_RECORD_CALC", "scan_mode": "SM_PCL",
                            "mount_type": "MT_HAND"})
    code = rsp.get("error", {}).get("code")
    if code not in (0x12040001, 0x12040002):   # EC_Success / EC_SuccessAndReboot
        raise SystemExit("device did not accept the start request: %s" % rsp.get("error"))
    if wait_for(SCAN_MODELING, 90):      # measured: scanning 14 to 15 s after AC_START
        time.sleep(10)                   # scan for 10 s
    else:
        print("timed out waiting for scanning")
    modeling(client, {"action": "AC_STOP"})
    wait_for(SCAN_READY, 180)            # measured: up to 52 s back to standby after AC_STOP, 180 s is margin

Bu örnek, depodaki python/example/usage/modeling.py dosyasının sadeleştirilmiş sürümüdür: akış aynıdır, ancak Ctrl-C işleme, bekleme zaman aşımından sonra gönderilen ek AC_STOP ve çıkış kodları yoktur. Başlatma isteğinin reddedilmesi genellikle yanlış bir anahtardan veya hatalı biçimlendirilmiş bir mesajdan kaynaklanır; cihaz yalnızca bekleme durumunda olmadığı için isteği bir dönüş koduyla reddetmez, bu yüzden örnek önce modeling_state değerini kontrol eder. Gerçek kullanımda doğrudan modeling.py dosyasını çalıştırın. 1.0.1 sürümünden itibaren cihazın gerçekten taramaya geçmesini bekler, istek kabul edilmezse çıkar ve Ctrl-C ile kesildiğinde ya da bekleme zaman aşımında durdurma komutu gönderir: python python/example/usage/modeling.py --host 192.168.55.1 --key <provided by XGRIDS> --project demo. Tam bir çalıştırma bir dakika veya daha uzun sürer. 1.0.0 sürümündeki modeling.py, cihaz taramaya girmeden önce durdurmadan yalnızca birkaç saniye sabit süre bekler; 1.0.1 veya daha yeni bir sürüm kullanın.

Bekleme durumunda poz verisine abone olunduğunda 3 saniye içinde hiçbir veri alınmamıştır (ölçülmüştür); poz ve nokta bulutu yalnızca tarama sırasında kullanılabilir. Tarama sırasında bunları almak için cihaz taramaya girdikten sonra abone olun; örneğin wait_for(SCAN_MODELING, 90) başarılı olduktan sonra client.subscribe("lixel/application/report/lio_pose", "LioPoseReport", callback) satırını ekleyin.

Not: Tarama parametreleri (kayıt modu, tarama modu, montaj türü vb.) için Arayüz Kataloğu · Scan mapping bölümüne bakın. Gerçek zamanlı nokta bulutu ek açma işlemi gerektirir, bkz. Gerçek Zamanlı Veri.

Sonraki Adımlar

Bu bölüm XGRIDS'in resmî kullanım kılavuzundan Türkçeye çevrildi; ekran görüntüleri ve arayüz adları özgün haliyle İngilizcedir. İngilizce aslı (yeni sekmede açılır) · Güncelleme:

XGRIDS Türkiye

Kurulumda ve Sahada Yanınızdayız

Atlıhan Harita; cihaz kurulumu, firmware güncellemesi, yazılım kullanımı ve saha uygulamalarında eğitim ve teknik destek verir. Sorunuzu iletin, uzmanımız size dönsün.

+90 216 546 0804