Documentació d'Asset Core

Documentació del motor d'estat del món determinista i referències de l'API.

Decision Gate docs

Cèl·lula de Robòtica: Classificació per Conveyor amb Estat Determinista

Un sol robot rastreja articles en un transportador mòbil, reconcilia actualitzacions de sensors i realitza recollides/col·locacions en contenidors de graella amb reproducció determinista.

Si esteu llegint això en fred, aquest és un flux de treball de selecció i col·locació determinista amb correcció de sensors i recuperació de conflictes. Cada pas és un compromís auditable amb metadades i claus d’idempotència perquè pugueu reproduir o diagnosticar execucions sense especulacions.

El Problema: Quan els Sensors i els Planificadors No Coincideixen

En la robòtica de producció, el vostre sistema de visió informa d’una posició, el vostre encoder en diu una altra i el vostre planificador assumeix una tercera. Quan una recollida falla, teniu tres registres contradictoris i cap font única de veritat. Va ser:

  • Deriva del sensor durant el moviment del transportador?
  • Una posició obsoleta en el planificador de moviments?
  • Una condició de competència entre l’actualització de visió i la comanda de recollida?

Sense un estat determinista, la depuració es converteix en arqueologia. Amb AssetCore, cada canvi d’estat és un compromís amb caràcter temporal i auditable. Les correccions de sensors, les actualitzacions del planificador i els comandaments d’execució flueixen a través d’un registre autoritatiu. Quan alguna cosa falla, es reprodueix la seqüència exacta i es veu què ha passat - sense especulacions.

Aquest escenari demostra patrons de qualitat de producció: seguiment continu del transportador, reconciliació de sensors basada en visió, detecció de conflictes amb replanificació automàtica i reproducció determinista per a la depuració.

Per què això és important

Les piles de robòtica fallen quan els planificadors, sensors i execució no estan d’acord sobre la veritat fonamental. Asset Core fa que l’estat sigui autoritari tractant cada canvi com una transacció determinista i reproduïble.

Model de sistema

  • Transportador: col·locacions contínues 1D amb coordenades de punt fix.
  • Bins: contenidor de graella que imposa regles d’ocupació.
  • Gripper: contenidor de ranures perquè els moviments de recollida siguin deterministes.
  • Posició del robot: contenidor 2D continu per a la posició i la rotació.
  • Classes i formes: registrades perquè es facin complir les regles de col·lisió i col·locació.
  • Unitats: mm (fixed_point_scale=1000).

Visió general del flux de treball

  1. Configuració - Registrar classes/formes i crear contenidors.
  2. Semença - Crear la posició del robot, l’element entrant i el contenidor bloquejat.
  3. Avanç del transportador - Mou l’element en funció de la velocitat del transportador i dels clics de l’encoder.
  4. Conveyor Reconcile - Aplicar la correcció del sensor a la posició de l’element.
  5. Moviment del Robot - Actualitzar la posició del robot en 2D continu.
  6. Agafa - Mou l’element del transportador a la pinça.
  7. Blocjat - El contenidor bloquejat retorna POSITION_OCCUPIED.
  8. Reixeta Lliure - Troba l’ancoratge de reixeta disponible més proper.
  9. Col·locar - Col·locar l’element en l’ancoratge de la graella lliure.
  10. Col·locar Repetició - Repetir la col·locació per confirmar la idempotència.

Disseny del Sistema: Què Vam Escollir i Per Què

Aquest escenari fa eleccions de disseny específiques que reflecteixen el model d’estat determinista d’AssetCore. Aquí teniu el que hem optimitzat i el que hem intercanviat.

Elecció: Coordenades de Punt Fixe

L’Elecció: Totes les posicions utilitzen enters de punt fix (fixed_point_scale=1000 significa 1 unitat = 1mm).

  • Per què: L’aritmètica de punt flotant és no determinista entre CPUs - la reproducció podria divergir a causa de diferències de redondeig. El punt fix garanteix una reproducció idèntica en bytes.
  • Compensació: Heu de triar la precisió per avançat (1000 = 0.001mm de resolució). Per a la majoria de la robòtica, la precisió en mil·límetres és suficient.
  • Quan és important: La depuració de viatges en el temps, la recuperació de desastres i les auditories de compliment depenen de la reproducció determinista.

Elecció: Reconciliació de Sensors com a Commits Separats

L’Elecció: Pas 3 (actualització de l’encoder) i Pas 4 (correcció de visió) són commits separats.

  • Per què: Cada canvi d’estat és una decisió explícita amb la seva pròpia metadada. Si la confiança en la visió és baixa, podeu consultar quines correccions s’han aplicat i reproduir sense elles.
  • Compensació: Dos commits en comptes d’un (sobrecost de latència menor, típicament <1ms per commit).
  • Quan és important: Depuració del desplaçament del sensor, validació de l’exactitud del sistema de visió, demostració de compliment.

Elecció: Detecció de Conflictes Abans del Canvi d’Estat

La Elecció: El pas 7 detecta POSITION_OCCUPIED en el moment de la validació (L2), abans de qualsevol mutació d’estat.

  • Per què: No hi ha compromisos parcials, no hi ha neteja, no hi ha “transaccions compensatòries.” Les fallades de validació són barates (sense I/O), i l’estat es manté net.
  • Compensació: El planificador ha de consultar les posicions lliures (Pas 8) després del conflicte. El bloqueig optimista fallaria menys sovint però requeriria lògica de retrocés.
  • Quan és important: Cèl·lules multi-robot amb recollides/col·locacions concurrentes. El sistema d’un sol escriptor per espai de noms d’AssetCore garanteix que els conflictes es detectin de manera determinista.

Elecció: Clau d’idempotència per a la resiliència de la xarxa

La tria: Les claus d’idempotència són opcionals però, quan estan presents, dedupliquen les reintents basant-se en un hash canònic de la càrrega útil completa de la sol·licitud.

  • Per què: La mateixa clau + la mateixa càrrega útil retorna la resposta emmagatzemada; la mateixa clau + càrrega útil diferent és rebutjada. Això evita compromisos de moviment duplicats sota reintents.
  • Compensació: El servei autoritzat ha de generar o derivar claus estables per interacció i no ha de reenvair claus de clients no fiables.
  • Quan és important: lliurament almenys una vegada, reintents a través de connexions inestables, treballadors de cua i recuperació multi-regió.

Què No Gestionem (i Per Què)

  • Planificació de moviments: AssetCore registra actualitzacions de posicions, però no calcula trajectòries. Integra’t amb el teu planificador de moviments (MoveIt, OMPL, personalitzat) i compromet les posicions planificades.
  • Control en temps real: AssetCore és per a l’autoritat estatal, no per a bucles de control de 1kHz. Utilitzeu-lo per coordinar plans d’alt nivell i enregistrar els resultats de l’execució.
  • Fusió de sensors: AssetCore emmagatzema correccions de sensors (Pas 4), però no les calcula. El vostre sistema de visió proporciona la correcció; AssetCore la fa autoritativa i reproduïble.

Aquests són límits de l’abast deliberats: AssetCore proporciona una gestió d’estat determinista i deixa els algoritmes específics del domini (planificació de moviments, fusió de sensors) a eines especialitzades.

Semàntica d’idempotència

Les claus d’idempotència són opcionals i només controlen la desduplicació de reintents. Quan hi ha una clau present, Asset Core fa un hash de la càrrega completa de la sol·licitud i utilitza (namespace, key, hash) per decidir:

  • Mateix clau + mateix càrrec: retorna la resposta emmagatzemada (sense re-execució).
  • Mateix clau + càrrega útil diferent: rebutjar amb 409 Conflict.
  • La validació fallida no reserva la clau; la reutilització després de la correcció és vàlida.
  • No key: request executes normally, retries re-run. Sense clau: la sol·licitud s’executa normalment, els reintents es tornen a executar. En les implementacions de robòtica, el servei d’orquestració genera o deriva claus i no hauria de reenvair claus de clients no fiables.

Com llegir la guia pas a pas

  • Les lectures/flux de validació es llisten per separat després dels passos.
  • Els passos d’una sola operació utilitzen helpers d’acció per a la llegibilitat.
  • Els passos de múltiples operacions es mantenen com a crides de compromís per preservar l’atomicitat.
  • Rust HTTP sempre utilitza el punt final de commit amb una o més operacions.

Artifacts de l’escenari

Última verificació

  • ID d’execució: 2026-01-19T18-43-00Z-robotics_cell
  • Status: Aprovat
  • Hash arrel d’integritat: 53624642c9af8f6caf0e4138541c948e0f5bd09b95d480e5e9e233d7416c3d32
  • Checks:
    • {‘kind’: ‘invariants estructurals’}: aprovat
    • {‘kind’: ‘world_seq_monotonic’}: aprovat
    • {‘kind’: ‘global_seq_monotonic’}: aprovat
    • {‘kind’: ‘replay_idempotent’}: passat
    • {'kind': 'commit_log_integrity', 'expected_chain_hash': 'db3c030f7451ac6b5c4abfe5af7f08f3df463f6991cd19adb0beeb643781f455', 'expected_prev_chain_hash': '402bf8dde049d865bc48a2af2d9d5d9ab1e996b6da0dad5bb56118adccd5c1a2', 'expected_start_offset': 1, 'expected_end_offset': 7, 'expected_entry_count': 7, 'expected_last_global_seq': 23}: aprovat
    • {‘kind’: ‘runpack_integrity’}: aprovat

Descarregues de Runpack

Instantània de l’escenari

{
  "scenario_id": "robotics_cell",
  "version": "0.1.0",
  "namespace_id": 1,
  "containers": {
    "conveyor": "container-31001",
    "grid": "container-31002",
    "gripper": "container-31003",
    "robot_pose": "container-31004"
  },
  "classes": {
    "item": "class-41001",
    "robot_pose": "class-41002"
  },
  "units": {
    "fixed_point_scale": 1000,
    "length_unit": "mm",
    "time_unit": "ms"
  }
}

Failure branch

POSITION_OCCUPIED -> graella lliure -> torna a provar amb la mateixa clau d’idempotència

Audit trail (opcional)

La transcripció captura les parelles de sol·licitud i resposta exactes emeses durant l’execució. Aquí hi ha un extracte compacte que podeu utilitzar per validar el determinisme i la propagació de metadades:

{
  "kind": "commit",
  "name": "conveyor-reconcile",
  "request": {
    "path": "/v1/write/namespaces/1/commit",
    "idempotency_key": "robotics-cell-reconcile",
    "actor_id": "robotics-cell",
    "metadata": {
      "job_id": "job-robotics-001",
      "sensor_ts_ms": 1725000001250,
      "step": "conveyor-reconcile",
      "trace_id": "trace-robotics-001",
      "vision_confidence": 0.78
    },
    "operations": [
      "MoveInstance"
    ]
  },
  "response": {
    "commit_id": "00000000000000000000000000000002",
    "world_seq_start": 15,
    "world_seq_end": 16,
    "event_count": 2
  }
}

Nota de prevol

  • Per defecte, les accions criden a enviar compromisos.
  • Estableix ActionOptions(preflight=True) o crida assetcore_commit_preflight per a la validació.

SDK configuració

from assetcore_sdk import AssetCoreClient
from assetcore_sdk.actions import ActionOptions
from assetcore_sdk.operations import (
    AddInstance,
    CreateContainer,
    MoveInstance,
    RegisterClass,
    RegisterClassContinuousShape1d,
    RegisterClassContinuousShape2d,
    RegisterClassShape,
)

# Snippets assume an async context (e.g., inside async def main()).
write_client = AssetCoreClient(
    base_url="http://localhost:8080",
    api_key="WRITE_API_KEY",
)
read_client = AssetCoreClient(
    base_url="http://localhost:8081",
    api_key="READ_API_KEY",
)

Guia

Pas 1: Configuració

Registra classes/formes i crea contenidors.

Per què és important aquest pas: Els fluxos de treball de robòtica necessiten que la geometria dels contenidors i les formes de classe estiguin definides abans que qualsevol col·locació o moviment pugui ser validat.

Condicions prèvies:

  • Cap. Aquest és el commit de bootstrap.

El que crea aquest commit:

  • Transportador (continu 1D), contenidors (reixeta), pinça (ranures), posició del robot (continu 2D).
  • Classes d’ítems i robots amb formes de graella i contínues.

Canvi d’estat esperat:

  • Els contenidors i les formes estan registrats perquè les futures operacions de MoveInstance puguin ser validades.

Operacions

  • CreateContainer (x4) - Crea un contenidor (regió de memòria estructurada) amb el tipus sol·licitat.
  • RegisterClass (x2) - Registra una definició de classe perquè les operacions futures la puguin referenciar.
  • RegisterClassShape - Registra una empremta de forma de graella per a una classe o variant de classe.
  • RegisterClassContinuousShape1d - Registra un interval continu 1D per a una classe o variant de classe.
  • RegisterClassContinuousShape2d - Registra un rectangle continu 2D per a una classe o variant de classe.
await write_client.commit_operations(
    [
        CreateContainer(
            kind={
                "bucket_cell_size": 1000,
                "max_x": 39999,
                "min_x": 0,
                "quantization_inv": 1000,
                "type": "continuous_line_1d",
            },
            policies=None,
            external_id="container-31001",
            owner_external_id="owner-77",
        ),
        CreateContainer(
            kind={"capacity": 16, "grid_width": 4, "type": "grid"},
            policies=None,
            external_id="container-31002",
            owner_external_id="owner-77",
        ),
        CreateContainer(
            kind={"count": 2, "type": "slots"},
            policies=None,
            external_id="container-31003",
            owner_external_id="owner-77",
        ),
        CreateContainer(
            kind={
                "bucket_cell_size": 1000,
                "max_x": 9999,
                "max_y": 9999,
                "min_x": 0,
                "min_y": 0,
                "quantization_inv": 1000,
                "type": "continuous_grid_2d",
            },
            policies=None,
            external_id="container-31004",
            owner_external_id="owner-77",
        ),
        RegisterClass(
            request={
                "behavior": {"balance_scale": 1},
                "class_id": "class-41001",
                "flags": 0,
                "name": "robotics-item-41001",
            },
        ),
        RegisterClass(
            request={
                "behavior": {"balance_scale": 1},
                "class_id": "class-41002",
                "flags": 0,
                "name": "robotics-robot-41002",
            },
        ),
        RegisterClassShape(
            request={"class_id": "class-41001", "shape": {"height": 1, "width": 1}},
        ),
        RegisterClassContinuousShape1d(
            request={"class_id": "class-41001", "span": {"length": 2000}},
        ),
        RegisterClassContinuousShape2d(
            request={
                "class_id": "class-41002",
                "rect": {"height": 1000, "width": 1000},
            },
        ),
    ],
    namespace_id=1,
    idempotency_key="robotics-cell-setup",
    actor_id="robotics-cell",
    metadata={
        "job_id": "job-robotics-001",
        "step": "setup",
        "trace_id": "trace-robotics-001",
    },
)

Pas 2: Sembrar

Crea la posició del robot, l’element entrant i el contenidor bloquejat.

Per què és important aquest pas: La semilla proporciona al flux de treball instàncies concretes per moure: una posició del robot, un article entrant i un contenidor deliberadament bloquejat.

Condicions prèvies:

  • La configuració del commit ha creat contenidors i ha registrat classes/formes.

Què cal notar en el codi:

  • La posició del robot es col·loca en 2D continu.
  • L’element entrant es col·loca a la línia de transport.
  • L’element de contenidor bloquejat ocupa la cel·la de la graella objectiu.

Canvi d’estat esperat:

  • Les instàncies de robot, d’element entrant i de bloqueig existeixen a les seves ubicacions d’inici.

Operacions

  • AddInstance (x3) - Crea una nova instància i la col·loca en una ubicació objectiu.
await write_client.commit_operations(
    [
        AddInstance(
            class_id="class-41002",
            client_tag="robot-arm-1",
            key=None,
            location={
                "container_id": "container-31004",
                "coord": {"x": 2000, "y": 3000},
                "kind": "continuous_2d",
                "rotation_millideg": 0,
            },
        ),
        AddInstance(
            class_id="class-41001",
            client_tag="inbound-item",
            key=None,
            location={
                "container_id": "container-31001",
                "coord": {"x": 4000},
                "kind": "continuous_1d",
            },
        ),
        AddInstance(
            class_id="class-41001",
            client_tag="blocked-bin",
            key=None,
            location={
                "container_id": "container-31002",
                "kind": "grid_cell",
                "position": 6,
                "rotation": None,
            },
        ),
    ],
    namespace_id=1,
    idempotency_key="robotics-cell-seed",
    actor_id="robotics-cell",
    metadata={
        "job_id": "job-robotics-001",
        "sensor_ts_ms": 1725000000000,
        "step": "seed",
        "trace_id": "trace-robotics-001",
        "vision_confidence": 0.82,
    },
)

Pas 3: Avanç del transportador

Mou l’element en funció de la velocitat del transportador i els tics de l’encoder.

Per què és important aquest pas: La cinta transportadora mou articles en funció dels tics de l’encoder. En un sistema no determinista, confiaries en el recompte de tics de l’encoder i esperaries que coincideixi amb la realitat. AssetCore registra la posició exacta com un compromís - amb una marca de temps, amb metadades de l’encoder - així que si una recollida falla més tard, pots reproduir des d’aquest punt i veure si la posició de l’encoder era correcta o si va ocórrer un desplaçament del sensor.

Condicions prèvies:

  • L’element entrant existeix a la cinta transportadora des del compromís inicial.

Què proporciona AssetCore:

  • Les actualitzacions de posició són compromisos atòmics (sense moviments parcials)
  • La metadada captura els ticks de l’encoder i la velocitat per a l’anàlisi forense
  • La clau d’idempotència assegura que la reproducció d’aquest compromís produeix el mateix estat

Què cal notar en el codi:

  • encoder_ticks: 1825 i speed_mm_s: 450 en metadades - capturat per a auditoria
  • Coordenada contínua 1D x: 10000 (10mm amb fixed_point_scale=1000)
  • La clau d’idempotència robotics-cell-advance evita moviments duplicats en reintents

Canvi d’estat esperat:

  • L’element entrant es mou a la nova coordenada del transportador.

Operacions

  • MoveInstance - Mou una instància existent a una nova ubicació.
await write_client.actions.move_instance(
    instance="inst-2",
    to={
        "container_id": "container-31001",
        "coord": {"x": 10000},
        "kind": "continuous_1d",
    },
    options=ActionOptions(
        namespace_id=1,
        idempotency_key="robotics-cell-advance",
        actor_id="robotics-cell",
        metadata={
            "encoder_ticks": 1825,
            "job_id": "job-robotics-001",
            "speed_mm_s": 450,
            "step": "conveyor-advance",
            "trace_id": "trace-robotics-001",
        },
    ),
)

Pas 4: Reconciliació del transportador

Aplica la correcció del sensor a la posició de l’element.

Per què és important aquest pas: El sistema de visió detecta que la posició real difereix de l’estimació de l’encoder (10000mm encoder vs 11250mm visió). AssetCore aplica la correcció com un compromís separat amb la metadada vision_confidence: 0.78. Si es reprodueix des d’aquest punt, es veu la correcció exacta del sensor que s’ha aplicat.

Condicions prèvies:

  • L’element entrant roman a la cinta transportadora després del pas d’avanç.

Què proporciona AssetCore:

  • Les correccions del sensor són compromisos de primera classe amb metadades
  • Les correccions de baixa confiança es registren per a una anàlisi posterior
  • La reproducció mostra el delta exacte entre les estimacions de l’encoder i la visió

Què cal notar en el codi:

  • Delta de 1250mm (12.5% de desviació de l’estimació de l’encoder)
  • Confiança de visió 0.78 capturada en metadades
  • El compromís separat permet consultar “quines correccions s’han aplicat”

Canvi d’estat esperat:

  • L’element entrant es mou a la coordenada corregida.

Operacions

  • MoveInstance - Mou una instància existent a una nova ubicació.
await write_client.actions.move_instance(
    instance="inst-2",
    to={
        "container_id": "container-31001",
        "coord": {"x": 11250},
        "kind": "continuous_1d",
    },
    options=ActionOptions(
        namespace_id=1,
        idempotency_key="robotics-cell-reconcile",
        actor_id="robotics-cell",
        metadata={
            "job_id": "job-robotics-001",
            "sensor_ts_ms": 1725000001250,
            "step": "conveyor-reconcile",
            "trace_id": "trace-robotics-001",
            "vision_confidence": 0.78,
        },
    ),
)

Pas 5: Moviment del Robot

Actualitza la posició del robot en 2D continu.

Per què és important aquest pas: Les actualitzacions de la posició del robot són canvis d’estat autoritzats, no suggeriments del planificador. Registrar-les com a commits fa que l’auditoria de moviment estigui preparada.

Condicions prèvies:

  • La instància del robot existeix al contenidor de posicions a partir del compromís inicial.

Què cal notar en el codi:

  • MoveInstance té com a objectiu un contenidor 2D continu amb coordenades de punt fix.

Canvi d’estat esperat:

  • La posició del robot s’actualitza a les noves coordenades X/Y.

Operacions

  • MoveInstance - Mou una instància existent a una nova ubicació.
await write_client.actions.move_instance(
    instance="inst-1",
    to={
        "container_id": "container-31004",
        "coord": {"x": 3500, "y": 4000},
        "kind": "continuous_2d",
        "rotation_millideg": 0,
    },
    options=ActionOptions(
        namespace_id=1,
        idempotency_key="robotics-cell-robot-move",
        actor_id="robotics-cell",
        metadata={
            "job_id": "job-robotics-001",
            "step": "robot-move",
            "trace_id": "trace-robotics-001",
        },
    ),
)

Pas 6: Escollir

Mou l’element del transportador a la pinça.

Per què és important aquest pas: La recollida és un moviment determinista del transportador al gripper. No hi ha cap estat ocult - l’element surt d’un contenidor i entra en un altre.

Condicions prèvies:

  • L’element entrant està sobre la cinta transportadora.
  • La ranura del gripper objectiu està buida.

Què cal notar en el codi:

  • MoveInstance té com a objectiu un contenidor de slot (gripper).

Canvi d’estat esperat:

  • L’element surt del contenidor del transportador i ocupa l’espai del gripper.

Operacions

  • MoveInstance - Mou una instància existent a una nova ubicació.
await write_client.actions.move_instance(
    instance="inst-2",
    to={"container_id": "container-31003", "kind": "slot", "slot_index": 1},
    options=ActionOptions(
        namespace_id=1,
        idempotency_key="robotics-cell-pick",
        actor_id="robotics-cell",
        metadata={
            "job_id": "job-robotics-001",
            "step": "pick",
            "trace_id": "trace-robotics-001",
        },
    ),
)

Pas 7: Col·locar Bloquejat (Error esperat)

El contenidor bloquejat retorna POSITION_OCCUPIED.

Per què és important aquest pas: La posició del contenidor 6 està ocupada. AssetCore retorna l’error POSITION_OCCUPIED abans de qualsevol canvi d’estat. No hi ha compromís parcial, ni neteja requerida. La detecció de conflictes es produeix en el moment de la validació (L2), així que el teu estat es manté net.

Condicions prèvies:

  • L’element està a la ranura del gripper.
  • La cel·la de la graella objectiu està ocupada pel bloquejador.

Què proporciona AssetCore:

  • Conflictes detectats abans de la mutació d’estat (validació barata)
  • La resposta d’error inclou detalls exactes del conflicte (quina posició, quin element)
  • Clau d’idempotència preservada per a reintents amb la posició corregida

Què cal notar en el codi:

  • L’error és determinista (no és una condició de competència)
  • retryable: false significa que el client ha de canviar la sol·licitud (consultar per una posició lliure)
  • La mateixa clau d’idempotència es torna a utilitzar després de la replanificació

Canvi d’estat esperat:

  • No s’apliquen canvis d’estat; aquesta és una fallada de validació determinista.

Operacions

  • MoveInstance - Mou una instància existent a una nova ubicació.

Error esperat

{
  "code": "POSITION_OCCUPIED",
  "detail": "Position 6 in container 2 is occupied by item at anchor 6",
  "hint": "Select an unoccupied position or move the existing item first.",
  "retryable": false,
  "status": 409,
  "title": "ConflictError",
  "type": "urn:assetcore:error:POSITION_OCCUPIED"
}
await write_client.actions.move_instance(
    instance="inst-2",
    to={
        "container_id": "container-31002",
        "kind": "grid_cell",
        "position": 6,
        "rotation": None,
    },
    options=ActionOptions(
        namespace_id=1,
        idempotency_key="robotics-cell-place",
        actor_id="robotics-cell",
        metadata={
            "job_id": "job-robotics-001",
            "step": "place-attempt",
            "trace_id": "trace-robotics-001",
        },
    ),
)

Pas 8: Reixeta Lliure

Troba l’ancoratge de graella disponible més proper.

Per què és important aquest pas: Després de detectar el conflicte, el planificador consulta les posicions de la graella lliures. Aquesta operació de lectura veu la projecció actual - sense bloquejos, sense bloqueig. L’escalabilitat de lectura d’AssetCore significa que els planificadors poden consultar contínuament les posicions disponibles sense afectar el rendiment d’escriptura.

Condicions prèvies:

  • Un intent de col·locació ha fallat a causa d’una cel·la de la graella ocupada.

Què proporciona AssetCore:

  • Les consultes de lectura mai bloquegen les escriptures (arquitectura CQRS)
  • La consulta sense graella retorna la primera posició disponible de manera determinista
  • El retard de frescor és limitat i mesurable (vegeu les metadades de resposta)

Què cal notar en el codi:

  • Paràmetres de consulta: height=1, width=1 (empremta de l’element)
  • La resposta retorna la posició 1 (primer ancoratge lliure en ordre de fila)
  • No es requereix cap transacció (consulta només de lectura)

Canvi d’estat esperat:

  • Cap. Aquesta és una consulta de planificació només de lectura.
await read_client.get_container_grid_free(
    container_id="container-31002",
    namespace_id=1,
    height=1,
    width=1,
)

Pas 9: Col·locació

Col·locar l’element en l’ancora de gra lliure.

Per què és important aquest pas: La replanificació de la col·locació compromet l’ancora corregida en un moviment atòmic del gripper a la graella.

Condicions prèvies:

  • L’element roman al gripper.
  • L’ancora gratuïta retornada per grid_free continua disponible.

Què cal notar en el codi:

  • MoveInstance apunta a la cel·la de la graella lliure retornada pel pas de lectura.

Canvi d’estat esperat:

  • L’element deixa el gripper i ocupa la cel·la de la graella lliure.

Operacions

  • MoveInstance - Mou una instància existent a una nova ubicació.
await write_client.actions.move_instance(
    instance="inst-2",
    to={
        "container_id": "container-31002",
        "kind": "grid_cell",
        "position": 1,
        "rotation": None,
    },
    options=ActionOptions(
        namespace_id=1,
        idempotency_key="robotics-cell-place",
        actor_id="robotics-cell",
        metadata={
            "job_id": "job-robotics-001",
            "replan_reason": "grid_free",
            "step": "place",
            "trace_id": "trace-robotics-001",
        },
    ),
)

Pas 10: Col·locació de Repetició

Reproduïu la col·locació per confirmar la idempotència.

Per què és important aquest pas: Reproduir el mateix commit (mateix idempotency key) retorna èxit sense efectes duplicats. Així és com AssetCore garanteix la idempotència: reproduir el registre sempre produeix el mateix estat. En un sistema distribuït, això significa que les reintents de xarxa són segures.

Condicions prèvies:

  • El compromís de col·locació ja ha tingut èxit.

Què proporciona AssetCore:

  • Idempotència a nivell de commit (no només HTTP)
  • Replay produeix el mateix commit_id i world_seq que l’original
  • Segur de tornar a provar qualsevol operació sense corrupció d’estat

Què cal notar en el codi:

  • Càrrega idèntica a la col·locació exitosa (mateix clau, mateixes operacions)
  • La resposta confirma que no s’han generat nous esdeveniments (idempotent)
  • Així és com funciona la recuperació de desastres: reproduir tot el registre

Canvi d’estat esperat:

  • Cap. La reproducció retorna el compromís emmagatzemat.

Operacions

  • MoveInstance - Mou una instància existent a una nova ubicació.
await write_client.actions.move_instance(
    instance="inst-2",
    to={
        "container_id": "container-31002",
        "kind": "grid_cell",
        "position": 1,
        "rotation": None,
    },
    options=ActionOptions(
        namespace_id=1,
        idempotency_key="robotics-cell-place",
        actor_id="robotics-cell",
        metadata={
            "job_id": "job-robotics-001",
            "replan_reason": "grid_free",
            "step": "place",
            "trace_id": "trace-robotics-001",
        },
    ),
)

Validació

Aquests lectures i fluxos confirmen l’estat final després dels passos sense mutar res.

Llegir 1: Llegir Transportador

Verifiqueu que les col·locacions dels cinturons estiguin buides.

await read_client.get_container_continuous_placements_1d(
    container_id="container-31001",
    namespace_id=1,
)

Llegir 2: Llegir Slots

Verifiqueu que les ranures del gripper estiguin buides.

await read_client.get_container_slots(
    container_id="container-31003",
    namespace_id=1,
)

Llegir 3: Llegir la Xarxa

Verifiqueu que les ubicacions de la graella continguin bloquejador i element.

await read_client.get_container_grid(
    container_id="container-31002",
    namespace_id=1,
)

Llegir 4: Llegir Robot

Verifiqueu la col·locació de la posició del robot.

await read_client.get_container_continuous_placements_2d(
    container_id="container-31004",
    namespace_id=1,
)

Flux 5: Compromís de Flux

Llegeix el compromís de col·locació de SSE.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "assetcore_read_stream",
  "params": {
    "from_world_seq": 22,
    "limit": 1,
    "namespace_id": 1
  }
}

Què Prova Això: Robòtica de Grau de Producció amb Garanties Deterministes

Aquest escenari demostra la complexitat dels fluxos de treball de recollida i col·locació en producció: seguiment de posició continu, reconciliació de sensors, detecció de conflictes i replanificació automàtica.

Punt de prova 1: Cada canvi d’estat és auditable

Cada commit porta metadades: job_id, trace_id, sensor_ts_ms, vision_confidence. Quan un pick falla, no endevines - consultes el registre de commits i veus:

  • Posició exacta de l’encoder en l’avanç del transportador
  • Correcció de visió aplicada (delta: 1250mm, confiança: 0.78)
  • Quina posició de la graella estava bloquejada
  • Nova posició de la graella seleccionada després de la replanificació

Punt de prova 2: Detecció de conflictes sense bloqueig

El pas 7 mostra la detecció de POSITION_OCCUPIED en el moment de la validació. Sense bloquejos distribuïts, sense sobrecàrrega de coordinació. L’arquitectura de escriptor únic d’AssetCore fa que els conflictes siguin deterministes: es detecten abans de qualsevol canvi d’estat, i la resposta d’error et diu exactament què has de corregir.

Punt de prova 3: Repetició idempotent per a la depuració

Pas 10 prova la idempotència: reproduir el mateix commit (mateix clau d’idempotència, mateixes operacions) té èxit sense efectes secundaris. Així és com es depuren les fallades en producció:

  1. Exporta el registre de commits de la finestra de fallada
  2. Reproduir localment per reproduir l’estat exacte
  3. Inspeccionar l’estat intermedi en qualsevol commit
  4. Soluciona el problema i verifica amb la reproducció

Valor Empresarial: De “Ha Fallat” a “Aquí Tenim el Motiu”

Els sistemes de robòtica tradicionals et proporcionen tres registres contradictoris (visió, planificador, execució) i et fan reconstruir el que ha passat. AssetCore et proporciona un registre autoritari on cada canvi d’estat està marcat amb un segell de temps, atribuït (actor_id) i es pot reproduir.

Per a la comissió: Reproduir les execucions de producció per validar el comportament de la cel·la

Per a la depuració: Viatge en el temps fins al commit exacte on va ocórrer la fallada

Per compliment: Exportar un registre d’auditoria immutable amb metadades del sensor

Per a l’optimització: Analitzar les metadades de commit per identificar punts de congestió

Això és el que permeten les eines de classe mundial: una gestió d’estat determinista que et permet centrar-te en la lògica del domini de la robòtica en comptes de lluitar contra errors de reconciliació d’estat.

Properes passes

  • Prova-ho localment: Clona el repositori i executa l’escenari per dur a terme aquest flux de treball
  • Estén-ho: Afegiu coordinació multi-robot mitjançant la fragmentació entre espais de noms
  • Integra-ho: Vegeu SDK Reference per a patrons d’integració en producció
  • Pregunteu-nos: Reserveu una sessió tècnica per discutir el vostre cas d’ús de robòtica