0d32f32db0
Замкнутый контур "поток -> CV -> механика": товары идут по конвейеру с шагом 700 мм, класс определяется стереопайплайном во время движения, пушер и плуг реагируют физически. Состав: * control_test/ - ячейка и CV. run_sorting_cv.py + cv_worker.py (два процесса, потому что torch внутри Isaac роняет сцену), cell.py (физика лент, плуга, пушера), measure_plane.py (замер габаритов), README.md и .memory.md с замерами, проблемами и ловушками * robozon_sorter/ - модули симуляции, scripts/ - утилиты, scene/ - сцены * assets/ - меши товаров, плуг, объекты Objaverse Бейзлайн CV: DEFOM-Stereo vitl, вход 480, iters 24, кроп зоны осмотра, без сегментации. На потоке 700 мм - классы 8/9, габариты MAE 32.8 мм, 469 мс на товар при такте 700 мс. Веса моделей (4.5 ГБ) и пропсы конвейера NVIDIA (274 МБ) не включены - источники и команды скачивания в MODELS.md. Выход прогонов (captures/, runtime/) не включён: воспроизводится. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
73 lines
3.0 KiB
Python
73 lines
3.0 KiB
Python
"""Why goods stop at x=-6.0: place one item either side of the belt junction and watch.
|
|
|
|
Run A parks an item at x=-5.5, upstream of the transfer, and lets it drive at it.
|
|
Run B starts one already at x=-6.3, past the transfer, on the wide belt through the plow.
|
|
|
|
If A stalls and B runs, the transfer is blocked by structure, not by a dead belt. The
|
|
suspect is the downstream end frame of ConveyorTrack_03: `open_junction()` clears the shell
|
|
collider on the plow track and both lanes, but not on the track goods arrive *on*, so its
|
|
end plate stands across the path at exactly x=-6.0.
|
|
"""
|
|
import sys, time
|
|
REPO = "/home/dasha/robozon-sorter"
|
|
if REPO not in sys.path:
|
|
sys.path.insert(0, REPO)
|
|
|
|
# The live Isaac process keeps every module it has ever imported, so an edited
|
|
# robozon_sorter/ on disk is invisible to a second run in the same session. Drop the
|
|
# package from sys.modules first or you spend the evening re-testing the old code.
|
|
for _m in [k for k in list(sys.modules) if k.startswith("robozon_sorter")]:
|
|
del sys.modules[_m]
|
|
import importlib
|
|
importlib.invalidate_caches() # a *new* module file is invisible until the finder is reset
|
|
|
|
import omni.timeline, isaacsim.core.experimental.utils.app as app_utils
|
|
from pxr import UsdPhysics
|
|
from robozon_sorter import config as C
|
|
from robozon_sorter.sim import plow_sort, plow_vision
|
|
from robozon_sorter.sim.mechanics import Cell
|
|
|
|
OPEN_03 = bool(globals().get("open_03", False)) # also clear ConveyorTrack_03's shell
|
|
START_X = float(globals().get("start_x", -5.5))
|
|
ITEM = globals().get("item", "barrel")
|
|
SECONDS = float(globals().get("seconds", 6.0))
|
|
|
|
stage, info = plow_vision.load(belt_speed=1.0, script_control=True)
|
|
plow_sort.keep_lanes_active(stage)
|
|
plow_sort.configure_lanes(stage, 1.0)
|
|
opened = plow_sort.open_junction(stage)
|
|
extra = None
|
|
if OPEN_03:
|
|
p = stage.GetPrimAtPath("/World/ConveyorTrack_03/SM_ConveyorBelt_A24_02")
|
|
a = p.GetAttribute("physics:collisionEnabled") or \
|
|
UsdPhysics.CollisionAPI.Apply(p).CreateCollisionEnabledAttr()
|
|
a.Set(False)
|
|
extra = str(p.GetPath())
|
|
print(f"opened {len(opened)} shells, extra={extra}")
|
|
|
|
items = {k: v["zone"] for k, v in info["items"].items()}
|
|
await app_utils.update_app_async(steps=30)
|
|
cell = Cell(stage, items.keys())
|
|
cell.park_all()
|
|
await app_utils.update_app_async(steps=10)
|
|
|
|
cell.place(ITEM, (START_X, 0.0, C.BELT_Z + 0.10))
|
|
app_utils.play(commit=True)
|
|
await app_utils.update_app_async(steps=20)
|
|
|
|
print(f"\n{ITEM} from x={START_X} (plow at x={C.PLOW_POS[0]})")
|
|
t0, last = time.time(), None
|
|
while time.time() - t0 < SECONDS:
|
|
await app_utils.update_app_async(steps=12)
|
|
p = cell.pose(ITEM)
|
|
x, y, z = (float(v) for v in p[:3])
|
|
moved = "" if last is None else f" dx={x - last:+.3f}"
|
|
print(f" t={time.time() - t0:4.1f} x={x:+.3f} y={y:+.3f} z={z:+.3f}{moved}")
|
|
last = x
|
|
if z < C.BELT_Z - 0.5:
|
|
print(" -> fell off"); break
|
|
|
|
app_utils.stop()
|
|
await app_utils.update_app_async(steps=10)
|
|
print(f"verdict: {'REACHED PLOW' if last is not None and last < -6.6 else 'STALLED at x=%.2f' % (last or 0)}")
|