Python'dan Pixhawk'a görev yüklenmiyor, istek tipine bak
Raspberry Pi'deki Python kodu Pixhawk'a görev yüklerken bekliyorsa ArduPilot satırları eski istek adıyla istiyor ve senin kodun o adı hiç almıyor demektir.
Raspberry Pi'deki Python kodun rotayı Pixhawk'a göndermeye başlıyor ve ilk satırdan sonra donup kalıyor. Hata mesajı yok, imleç yanıp sönüyor. Kabloyu suçlayamazsın: heartbeat geliyor, parametreleri okuyabiliyorsun.
Kod yanlış mesajı bekliyor. Pixhawk'ın satırları hangi adla istediğini ve iki adı da karşılayan düzeltilmiş kodu aşağıda bulacaksın.
Kodun beklediği mesaj hiç gelmiyor
Görev yükleme bir soru-cevap zinciridir. Kod önce kaç satır göndereceğini söyler. Otopilot satırları sıfırdan başlayarak tek tek ister, kod her isteğe o satırla cevap verir ve son satırdan sonra otopilot bir onay mesajı döner.
MAVLink'in güncel belgesi, otopilotun satırları MISSION_REQUEST_INT ile istemesi gerektiğini yazıyor ve eski MISSION_REQUEST mesajını kullanımdan kalkmış sayıyor. İnternetteki örneklerin çoğu bu yüzden yalnızca yeni adı bekler. ArduPilot 4.7.2 ise satırları hâlâ eski adla istiyor; kaynak kodda istek gönderen fonksiyon eski mesajı çağırıyor.
Pixhawk aynı isteği tekrarlıyor, kod başka tip beklediği için hiçbirini almıyor
Şekilde mavi oklar Pixhawk'tan çıkan istekler: hepsi sıfırıncı satırı istiyor ve yaklaşık bir saniye arayla tekrarlanıyor. Kırmızı çubuk senin kodun. İstekler ona ulaşıyor, fakat filtre başka bir ad aradığı için kodun hiçbirini almıyor ve 8. saniyede otopilot yüklemeyi iptal ediyor.
Takılan kodda recv_match çağrısı genellikle yalnızca MISSION_REQUEST_INT tipini bekler ve bir zaman sınırı taşımaz. Otopilot vazgeçtikten sonra bile kod orada beklemeye devam eder.
Yarım kalan görev eski rotayla karışıyor
Asıl risk iptalden sonra başlıyor. Otopilot yeni görevin satır sayısını alır almaz eski listeyi o uzunlukta keser, gelen satırları da tek tek üzerine yazar. Yükleme yarıda kalırsa yazılmamış satırlarda bir önceki rota durur.
Teknofest provasını düşün. Dün 20 metrede uçan beş satırlık bir rota yükledin. Bugün aynı uzunlukta, 30 metrede ve daha geniş bir rotayı Pi'den gönderiyorsun ve yükleme ikinci noktada düşüyor. Geri okuduğunda kalkış satırı 30 metre görünür, sonraki üç nokta ise dünkü koordinatlar ve dünkü 20 metre.
Kod onayı kontrol etmiyorsa bunu fark etmezsin. AUTO'ya geçtiğinde drone bu karışık rotayı uçar. Onay mesajını görmeden ve rotayı geri okumadan AUTO'ya geçme.
Hepsini art arda göndermek de kurtarmıyor
Bir başka yaygın deneme, istekleri hiç beklemeden beş satırı peş peşe yollamak. Paket kaybolmadıkça otopilot satırları sırayla kabul eder. Telemetri radyosunda tek bir paket düşerse otopilot sonraki satırları sıra dışı sayıp atar ve eksik satırı her saniye yeniden ister. Kod artık dinlemediği için 8. saniyede yine iptal gelir.
Kalıcı çözüm, kodu isteklere göre çalıştırmak: otopilot hangi satırı isterse onu göndermek ve iki istek adını da kabul etmek.
Düzeltilmiş kod
Aşağıdaki kod iki istek tipine de cevap veriyor, sıra dışı satır uyarısında beklemeye devam ediyor ve son onayın sonucunu okuyor. Koordinatları tam sayı biçimiyle (MISSION_ITEM_INT) gönderdiği için ondalık kayıp olmuyor. Onaydan sonra rotayı geri okuyup her satırı senin listenle karşılaştırıyor.
import time
from pymavlink import mavutil
# Raspberry Pi'de seri hat için ör.: mavutil.mavlink_connection("/dev/serial0", baud=921600, source_system=255)
m = mavutil.mavlink_connection("tcp:127.0.0.1:5760", source_system=255)
m.wait_heartbeat()
print("Bağlandı: sysid", m.target_system)
M = mavutil.mavlink
# (komut, enlem, boylam, irtifa). 0. satır Home'un yeri, otopilot onu kendi konumuyla doldurur.
GOREV = [
(M.MAV_CMD_NAV_WAYPOINT, 0, 0, 0),
(M.MAV_CMD_NAV_TAKEOFF, 0, 0, 20),
(M.MAV_CMD_NAV_WAYPOINT, 37.1600, 38.7969, 20),
(M.MAV_CMD_NAV_WAYPOINT, 37.1600, 38.7985, 20),
(M.MAV_CMD_NAV_WAYPOINT, 37.1591, 38.7985, 20),
]
def oge_gonder(seq):
cmd, lat, lon, alt = GOREV[seq]
frame = M.MAV_FRAME_GLOBAL if seq == 0 else M.MAV_FRAME_GLOBAL_RELATIVE_ALT
m.mav.mission_item_int_send(
m.target_system, m.target_component, seq, frame, cmd,
0, 1, 0, 0, 0, 0,
round(lat * 1e7), round(lon * 1e7), alt,
M.MAV_MISSION_TYPE_MISSION)
def gorev_yukle(bekleme=10):
m.mav.mission_count_send(m.target_system, m.target_component,
len(GOREV), M.MAV_MISSION_TYPE_MISSION)
son_istek = time.time()
while time.time() - son_istek < bekleme:
msg = m.recv_match(type=["MISSION_REQUEST", "MISSION_REQUEST_INT", "MISSION_ACK"],
blocking=True, timeout=1)
if msg is None or msg.mission_type != M.MAV_MISSION_TYPE_MISSION:
continue
if msg.get_type() == "MISSION_ACK":
if msg.type == M.MAV_MISSION_INVALID_SEQUENCE:
continue # sıra dışı öğe; otopilot eksik olanı yeniden isteyecek
return msg.type
print("İstendi:", msg.get_type(), "seq", msg.seq)
oge_gonder(msg.seq)
son_istek = time.time()
return None
def gorev_oku():
m.mav.mission_request_list_send(m.target_system, m.target_component, M.MAV_MISSION_TYPE_MISSION)
adet = m.recv_match(type="MISSION_COUNT", blocking=True, timeout=5).count
satirlar = []
for seq in range(adet):
m.mav.mission_request_int_send(m.target_system, m.target_component, seq, M.MAV_MISSION_TYPE_MISSION)
o = m.recv_match(type="MISSION_ITEM_INT", blocking=True, timeout=3)
satirlar.append((o.seq, o.command, o.x, o.y, o.z))
m.mav.mission_ack_send(m.target_system, m.target_component, M.MAV_MISSION_ACCEPTED, M.MAV_MISSION_TYPE_MISSION)
return satirlar
sonuc = gorev_yukle()
if sonuc is None:
print("Otopilot yanıt vermedi: hattı ve sysid'i kontrol et")
elif sonuc != M.MAV_MISSION_ACCEPTED:
print("Görev reddedildi:", M.enums["MAV_MISSION_RESULT"][sonuc].name)
else:
print("Görev kabul edildi")
for seq, cmd, x, y, z in gorev_oku()[1:]:
_, lat, lon, alt = GOREV[seq]
tamam = (x, y) == (round(lat * 1e7), round(lon * 1e7)) and z == alt
print("seq", seq, "komut", cmd, "eşleşiyor" if tamam else "FARKLI")Pi'de seri hattan bağlanıyorsan bağlantı satırını yorumdaki gibi kendi portun ve hızınla değiştir. Listenin sıfırıncı satırı Home'un yeridir; otopilot onu kendi konumuyla doldurur, bu yüzden karşılaştırma birinci satırdan başlar.
Ne göreceksin
Kodu çalıştırınca Pixhawk her satırı ayrı ayrı ister, onay gelir ve geri okunan satırlar listenle eşleşir:
Bağlandı: sysid 1
İstendi: MISSION_REQUEST seq 0
İstendi: MISSION_REQUEST seq 1
İstendi: MISSION_REQUEST seq 2
İstendi: MISSION_REQUEST seq 3
İstendi: MISSION_REQUEST seq 4
Görev kabul edildi
seq 1 komut 22 eşleşiyor
seq 2 komut 16 eşleşiyor
seq 3 komut 16 eşleşiyor
seq 4 komut 16 eşleşiyorİsteklerin MISSION_REQUEST adıyla geldiğine dikkat et; düzeltme tam olarak bu satırları yakalamak için. Bir satırda FARKLI görürsen o satır yazılmamış ya da eski rotadan kalmıştır, AUTO'ya geçmeden yüklemeyi tekrarla.
Hata mesajları
Mission upload timeout
Otopilot 8 saniye boyunca beklediği satırı alamadı ve yüklemeyi iptal etti. Bu mesaj yalnızca görevi yükleyen bağlantıya gider; Mission Planner ayrı bir radyodan bağlıysa onun ekranında görünmeyebilir. Kodun STATUSTEXT mesajlarını okursa burada görürsün.
got MISSION_ITEM; GCS should send MISSION_ITEM_INT
Kod satırları ondalıklı eski mesajla gönderiyor. Yükleme yine kabul edilir ama koordinatlar 32 bit ondalığa yuvarlanır. Gönderimi mission_item_int_send ile yap, enlem ve boylamı 10.000.000 ile çarpıp tam sayıya yuvarla.
Flight plan received
Başarı mesajı: otopilot son satırı kabul etti. Kodunda bu noktada gelen onayın sonucu 0 (ACCEPTED) olmalı.
Kursta devamı
Python ile görev yükleme, GUIDED ve AUTO komutları ve yardımcı bilgisayardan kontrol adım adım Python ile Sıfırdan İHA Kontrolü eğitiminde. Yeni eklenen ders aynı yüklemeyi otopilotun kaynak kodundan ve uçuş kaydından izliyor; yarım kalan görevi temizleyip yeniden yükleyen kod da orada.
Bu yazı işinize yaradı mı?
Bu konuyu baştan sona öğrenin
Sezon: altı eğitimin hepsi 9 ay, ayda ₺790. Lise ve üniversite öğrencisine ayda ₺390, üye kodunuzla ilk ay ₺351. İstediğiniz ay bırakırsınız. Sezon'a başlayın · Öğrenciyim