Bir robot kol dijital ikizi, hazır bir animasyonla değil eklem açısı telemetrisiyle yönetilen ve gerçek kol nasıl hareket ediyorsa tam olarak öyle hareket eden canlı bir 3D kopyadır. Bu rehberde eklem açılarını MQTT üzerinden aktaracak, tarayıcıda Three.js ile eklemli bir 3D modeli canlandıracak ve onaylarla birlikte kola hareket komutları göndereceksiniz. Her şey birkaç dakika içinde gerçek bir broker'a karşı çalışır.
Önce daha geniş bağlamı görmek istiyorsanız dijital ikiz teknolojisi rehberi, bu tür bir 3D ikizin diğer ikiz türleri arasında nereye oturduğunu açıklıyor.
Robot Kol Neden İdeal İlk 3D İkizdir?
Robot kollar 3D ikizler için mükemmel bir başlangıç noktasıdır, çünkü durumları küçük ve iyi tanımlıdır. Altı eksenli bir kol; altı eklem açısı ile tutucu durumu, çalışan program ve hata kodu gibi birkaç bayrakla tamamen tanımlanır. Bu çok küçük bir payload'dur; ancak bu açıları 3D'de bir kinematik zincire uyguladığınızda sonuç, ekranın önünden geçen herkes için anında anlaşılırdır: ikiz tıpkı sahadaki hücre gibi uzanır, döner ve kavrar.
Bu kompaktlık, veri taşıma açısından önemlidir. Tam pozu ağı zorlamadan MQTT üzerinden saniyede birkaç kez yayınlayabilirsiniz ve ister 3D görüntüleyici, ister historian, ister analitik script'i olsun her abone broker'dan aynı akışı alır.
Robot Kol Dijital İkizinin Mimarisi
Tasarım, tek bir broker üzerinden bağlanan üç rol kullanır:
- Robot gateway'i: eklem konumlarını kontrolörden okur (veya simüle eder) ve pozu yayınlar. Ayrıca komut topic'lerine abone olur ve kabul edilen komutları kontrolöre iletir.
- 3D görüntüleyici: pozlara Secure WebSocket üzerinden abone olan ve her eklem açısını bir 3D modelin ilgili node'una uygulayan bir tarayıcı sayfası.
- Operatör veya uygulama: "poza git" veya "tutucuyu aç" gibi komutlar yayınlar ve onayları dinler.
| Topic | Yön | Payload | QoS | Retained |
|---|---|---|---|---|
.../robot1/joints |
Gateway'den görüntüleyicilere | {"j1":12.5,...,"j6":-3.0,"ts":...} |
0 | Hayır |
.../robot1/state |
Gateway'den görüntüleyicilere | {"mode":"auto","gripper":"closed"} |
1 | Evet |
.../robot1/status |
Gateway (Last Will) | online / offline |
1 | Evet |
.../robot1/cmd/move |
Operatörden gateway'e | {"id":"c-42","target":{...}} |
1 | Hayır |
.../robot1/cmd/ack |
Gateway'den operatöre | {"id":"c-42","result":"accepted"} |
1 | Hayır |
Eklem telemetrisi QoS 0 kullanır, çünkü yeni bir poz her zaman eskisinin yerini alır; bir kareyi kaybetmek zararsızdır. Komutlar ve onaylar en az bir kez iletilmeleri için QoS 1 kullanır ve komut id değeri, gateway'in tekrarları yok saymasını sağlar. Bu dengeyi hatırlamak isterseniz MQTT QoS seviyeleri yazımıza bakın.
Bu eğitimde benzersiz bir topic prefix'iyle broker.connectmq.com adresindeki public MQTT test broker'ını kullanıyoruz. Public alanın herkes tarafından okunabildiğini unutmayın; oraya asla gerçek üretim verisi göndermeyin.
Adım 1: Gateway'den Eklem Açılarını Yayınlayın
Aşağıdaki script, hedef açılara doğru yumuşakça ilerleyen altı eksenli bir kolu simüle eder, pozunu saniyede beş kez yayınlar, retained bir durum mesajı tutar ve hareket komutlarını kabul eder. ra-7f3k yerine kendi rastgele ID'nizi kullanın.
import json
import random
import time
import paho.mqtt.client as mqtt
BROKER = "broker.connectmq.com"
PREFIX = "connectmq/demo/ra-7f3k/cell1/robot1"
CLIENT_ID = f"ra-7f3k-gateway-{random.randint(1000, 9999)}"
joints = {f"j{i}": 0.0 for i in range(1, 7)}
targets = dict(joints)
LIMITS = {"j1": (-170, 170), "j2": (-90, 90), "j3": (-120, 120),
"j4": (-180, 180), "j5": (-110, 110), "j6": (-360, 360)}
seen_commands = set()
def on_connect(client, userdata, flags, reason_code, properties):
print("Connected:", reason_code)
client.publish(f"{PREFIX}/status", "online", qos=1, retain=True)
client.publish(f"{PREFIX}/state", json.dumps({"mode": "auto", "gripper": "open"}),
qos=1, retain=True)
client.subscribe(f"{PREFIX}/cmd/move", qos=1)
def on_message(client, userdata, msg):
try:
cmd = json.loads(msg.payload)
cmd_id = cmd["id"]
except (ValueError, KeyError):
return
if cmd_id in seen_commands:
return # QoS 1 duplicate, already handled
seen_commands.add(cmd_id)
result = "accepted"
for name, value in cmd.get("target", {}).items():
low, high = LIMITS.get(name, (0, 0))
if name not in LIMITS or not low <= float(value) <= high:
result = f"rejected: {name} out of range"
break
if result == "accepted":
targets.update({k: float(v) for k, v in cmd["target"].items()})
client.publish(f"{PREFIX}/cmd/ack", json.dumps({"id": cmd_id, "result": result}), qos=1)
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id=CLIENT_ID,
protocol=mqtt.MQTTv5)
client.will_set(f"{PREFIX}/status", "offline", qos=1, retain=True)
client.on_connect = on_connect
client.on_message = on_message
client.connect(BROKER, 1883, keepalive=30)
client.loop_start()
try:
while True:
for name in joints:
joints[name] += (targets[name] - joints[name]) * 0.15
payload = {k: round(v, 2) for k, v in joints.items()}
payload["ts"] = int(time.time() * 1000)
client.publish(f"{PREFIX}/joints", json.dumps(payload), qos=0)
time.sleep(0.2) # 5 Hz keeps us well under the public broker rate limit
except KeyboardInterrupt:
client.publish(f"{PREFIX}/status", "offline", qos=1, retain=True)
client.loop_stop()
client.disconnect()
Kütüphaneyi pip install "paho-mqtt>=2.0" ile kurun ve script'i çalıştırın. Akışı başka bir terminalden izleyin:
mosquitto_sub -h broker.connectmq.com -p 1883 -i ra-7f3k-watch -t "connectmq/demo/ra-7f3k/cell1/robot1/#" -v
Gerçek bir hücrede yumuşatma döngüsünü, robot üreticinizin sağladığı kontrolör arayüzünden yapılan okumalarla değiştirin ve kabul edilen komutları ona iletin. Her durumda aralık kontrolünü gateway'de tutun: bir ekseni limitinin ötesine iten şey asla ikiz olmamalıdır.
Adım 2: Tarayıcıda 3D Robot Kol Dijital İkizini Oluşturun
Three.js'te bir robot kol, iç içe geçmiş gruplardan oluşan bir zincirdir. Her eklem tek bir eksen etrafında dönen bir gruptur ve her alt öğe üst öğelerinin transform'larını devralır; ileri kinematik tam olarak böyle çalışır. Basit şekiller yerine CAD'den dışa aktarılmış bir glTF modeli yüklerseniz aynı fikir geçerlidir: her eklemin node'unu adıyla bulun ve döndürün. IoT verisini bir 3D modele bağlama rehberi bu node'lar için adlandırma kurallarını ele alıyor.
npm install three mqtt ve Vite gibi bir bundler ile bir proje oluşturun, ardından bu modülü giriş noktası olarak kullanın:
import * as THREE from "three";
import mqtt from "mqtt";
const PREFIX = "connectmq/demo/ra-7f3k/cell1/robot1";
const scene = new THREE.Scene();
scene.background = new THREE.Color(0x1e1f24);
const camera = new THREE.PerspectiveCamera(50, innerWidth / innerHeight, 0.1, 100);
camera.position.set(3, 2.5, 3);
camera.lookAt(0, 1, 0);
const renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(innerWidth, innerHeight);
document.body.appendChild(renderer.domElement);
scene.add(new THREE.HemisphereLight(0xffffff, 0x444444, 2.5));
const mat = new THREE.MeshStandardMaterial({ color: 0xf28c28 });
function link(length, radius = 0.08) {
const mesh = new THREE.Mesh(new THREE.CylinderGeometry(radius, radius, length), mat);
mesh.position.y = length / 2;
return mesh;
}
// Kinematic chain: each joint is a Group nested inside its parent.
const joints = {};
const axes = { j1: "y", j2: "z", j3: "z", j4: "y", j5: "z", j6: "y" };
const lengths = { j1: 0.4, j2: 0.9, j3: 0.7, j4: 0.2, j5: 0.2, j6: 0.1 };
let parent = scene;
for (const name of Object.keys(axes)) {
const g = new THREE.Group();
g.add(link(lengths[name]));
parent.add(g);
joints[name] = g;
const tip = new THREE.Group();
tip.position.y = lengths[name];
g.add(tip);
parent = tip;
}
const target = {};
const client = mqtt.connect("wss://broker.connectmq.com:8084/mqtt", {
clientId: "ra-7f3k-viewer-" + Math.random().toString(16).slice(2, 8),
protocolVersion: 5,
});
client.on("connect", () => client.subscribe(`${PREFIX}/#`, { qos: 1 }));
client.on("message", (topic, payload) => {
if (topic.endsWith("/joints")) Object.assign(target, JSON.parse(payload.toString()));
if (topic.endsWith("/status")) document.title = "Robot1: " + payload.toString();
});
const toRad = THREE.MathUtils.degToRad;
renderer.setAnimationLoop(() => {
for (const [name, axis] of Object.entries(axes)) {
if (target[name] === undefined) continue;
const g = joints[name];
g.rotation[axis] += (toRad(target[name]) - g.rotation[axis]) * 0.3; // smooth between frames
}
renderer.render(scene, camera);
});
Render döngüsündeki enterpolasyon önemlidir. Telemetri 5 Hz'de gelirken ekran 60 Hz'de render eder; bu yüzden her yeni açıya doğrudan atlamak kesik kesik görünür. En son hedefe doğru yumuşakça ilerlemek, gerçek poz hakkında yanıltmadan aradaki boşluğu gizler. Sahneler, kameralar ve yükleyiciler hakkında daha ayrıntılı bir anlatım için Three.js dijital ikiz eğitimine ve resmi Three.js dokümantasyonuna bakın.
Adım 3: Döngüyü Komutlarla Kapatın
Yalnızca dinleyen bir ikiz bir dijital gölgedir. Onu çift yönlü hâle getirmek için bir komut yayınlayın ve ilgili onayı bekleyin:
mosquitto_pub -h broker.connectmq.com -p 1883 -i ra-7f3k-operator -q 1 \
-t "connectmq/demo/ra-7f3k/cell1/robot1/cmd/move" \
-m '{"id":"c-42","target":{"j1":45,"j2":-30,"j3":60,"j5":20}}'
Gateway limitleri kontrol eder, hedeflerini günceller ve cmd/ack üzerinde {"id":"c-42","result":"accepted"} yayınlar. Ardından 3D model yeni poza döner, çünkü komutu değil telemetriyi takip eder. Bu ayrım, bir robot kol dijital ikizinin en önemli tasarım kuralıdır: görüntüleyici her zaman robotun bildirdiğini render eder, asla birinin istediğini değil. Kontrolör bir hareketi reddederse ikiz yerinde kalır ve operatör reddetme nedenini görür.
Üretimde şu güvenlik önlemlerini ekleyin:
- Komutları kontrolör tarafındaki kilitlemelerin ve robotun kendi güvenlik sisteminin arkasına koyun. MQTT komutları hareket talep etmeli, güvenliği atlatmamalıdır.
- Gecikmiş bir mesajın geç yürütülmemesi için komutlara bir son kullanma süresi ekleyin. MQTT 5 ile yayında message expiry interval değerini ayarlayın; MQTT 5 özellikleri rehberi bunun nasıl yapılacağını gösteriyor.
- Görüntüleyiciler ve operatörler için ayrı kimlik bilgileri kullanın ve her komutu ve onayı loglayın.
Demodan Üretime Geçiş
Public broker denemeler içindir: client'ları saniyede 10 mesaj ve mesaj başına 64 KB ile sınırlar ve oraya yayınladığınız her şey başkaları tarafından görülebilir. Gerçek bir hücre için özel kimlik bilgileri ve TLS içeren bir yönetilen MQTT broker'a geçin. ConnectMQ üzerinde portalda bir broker oluşturur, üretilen kullanıcı adını, şifreyi ve client ID'yi kopyalar ve kodda iki şeyi değiştirirsiniz: 8883 portunda TLS ile (veya tarayıcı için 8084'te WSS ile) bağlanmak ve kimlik bilgilerini iletmek.
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, client_id="YOUR_CLIENT_ID",
protocol=mqtt.MQTTv5)
client.username_pw_set("YOUR_USERNAME", "YOUR_PASSWORD")
client.tls_set() # system CA store validates the Let's Encrypt certificate
client.connect("YOUR_BROKER_HOST", 8883, keepalive=30)
ConnectMQ'da client ID'ler verilen kimlik bilgilerine bağlı olduğundan, gateway'e ve her görüntüleyiciye tek bir kimliği paylaştırmak yerine kendi kimliklerini verin. Portalın canlı topic gezgini devreye alma sırasında kullanışlıdır: ek araç yazmadan eklem akışını ve onayları yan yana izleyebilirsiniz.
Sorun Giderme Kontrol Listesi
| Belirti | Olası neden | Çözüm |
|---|---|---|
| Model yanlış yönde hareket ediyor | Eksen işareti kontrolör ile 3D model arasında farklı | Görüntüleyici eşlemesinde o eklemin açısının işaretini ters çevirin |
| Kol parçaları yanlış nokta etrafında dönüyor | Pivot eklem orijininde değil | Her mesh'i grup orijini eklem ekseninde olacak şekilde konumlandırın |
| Görüntüleyici donmuş, gateway hâlâ çalışıyor | İki client aynı client ID'yi paylaşıyor ve birbirini düşürüyor | Her sekme ve cihaz için benzersiz bir client ID üretin |
| Komutlar iki kez yürütülüyor | Tekrar ayıklaması olmadan QoS 1 yeniden iletimi | Gateway'de komut ID'lerini takip edin |
| Yeniden bağlandıktan sonra poz sıçrıyor | Görüntüleyicinin bir sonraki kareye kadar durumu yok | Retained bir durum topic'i yayınlayın ve ondan enterpolasyon yapın |
| Yüksek kare hızlarında bağlantı kopuyor | Public broker hız sınırı | 5 Hz veya daha düşük hızda yayınlayın ya da ücretli bir plana geçin |
Robot Kol İkizinizi ConnectMQ'da Çalıştırın
Artık çalışan bir robot kol dijital ikiziniz var: eklem açılarını aktaran bir gateway, onları takip eden bir 3D görüntüleyici ve onaylı bir komut yolu. broker.connectmq.com üzerinde prototip geliştirin, ardından hücre devreye girdiğinde aynı kodu özel bir ConnectMQ broker'ına taşıyın. Kredi kartı gerekmeden ücretsiz bir Serverless broker oluşturun; birkaç dakika içinde TLS uç noktalarına ve kimlik bilgilerine sahip olursunuz.
Sık Sorulan Sorular
Bir robot kol dijital ikizi ne sıklıkta güncellenmeli?
Görüntüleyici kareler arasında enterpolasyon yaptığında saniyede beş ile on poz güncellemesi genellikle akıcı görünür. Daha yüksek hızlar, çoğu izleme senaryosu için görünür bir fayda olmadan yük ekler.
Basit şekiller yerine bir CAD modeli kullanabilir miyim?
Evet. Kolu her eklem için bir node olacak şekilde glTF'ye aktarın, GLTFLoader ile yükleyin ve bu node'ları bu eğitimdeki gruplarla tamamen aynı şekilde döndürün. Her node'un pivotunun eklem ekseni üzerinde olduğundan emin olun.
Gerçek bir robotu MQTT üzerinden kontrol etmek güvenli mi?
MQTT hareket taleplerini taşıyabilir, ancak güvenlik robot kontrolöründe ve onun güvenlik sisteminde kalmalıdır. Limitleri gateway'de doğrulayın, süresi dolan komutlar ve kimliği doğrulanmış client'lar kullanın ve ikizin kilitlemeleri atlatmasına asla izin vermeyin.
Görüntüleyici neden komutlar yerine telemetriyi takip ediyor?
Komutlar reddedilebilir, gecikebilir veya kısmen yürütülebilir. Yalnızca bildirilen pozu render etmek ikizi doğru tutar; dijital ikizin bütün amacı da budur.



