Сортировочная ячейка Isaac Sim: CV-пайплайн и меши товаров

Замкнутый контур "поток -> 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>
This commit is contained in:
dasha_f
2026-08-01 13:07:24 +00:00
parent 6ce460378a
commit 0d32f32db0
342 changed files with 18000 additions and 0 deletions
+79
View File
@@ -0,0 +1,79 @@
"""Почему лента не тянет: сырой прогон одной дорожки с печатью каждого шага.
Предыдущий вывод "стоит/упал" был ложным - я снимал положения ПОСЛЕ stop(), который
возвращает сцену в исходное состояние, поэтому все тела оказались в точках рождения
независимо от того, ехали они или нет. Здесь положение печатается ВО ВРЕМЯ прогона.
Первый подозреваемый - surfaceVelocityEnabled: PhysxSurfaceVelocityAPI можно применить
и задать вектор, но без включённого флага он не действует, и внешне это неотличимо от
нехватки трения.
"""
import sys
REPO = "/home/dasha/robozon-sorter"
if REPO not in sys.path:
sys.path.insert(0, REPO)
import omni.usd, omni.timeline
import isaacsim.core.experimental.utils.app as app_utils
from pxr import Gf, UsdPhysics, PhysxSchema, UsdShade
from isaacsim.core.experimental.prims import RigidPrim
stage = omni.usd.get_context().get_stage()
tl = omni.timeline.get_timeline_interface()
if tl.is_playing():
tl.stop(); await app_utils.update_app_async(steps=10)
BELT = "/World/ConveyorTrack/Belt"
PROBE = "/World/_BeltProbe/main_00"
pr = stage.GetPrimAtPath(BELT)
print("=== состояние привода ленты ===")
for a in pr.GetAttributes():
n = a.GetName()
if "urfaceVelocity" in n or "kinematic" in n.lower():
print(f" {n} = {a.Get()}")
print(" применённые схемы:", [s for s in pr.GetAppliedSchemas()])
# включить флаг явно
api = PhysxSchema.PhysxSurfaceVelocityAPI.Apply(pr)
en = pr.GetAttribute("physxSurfaceVelocity:surfaceVelocityEnabled")
if not en or not en.IsValid():
en = api.CreateSurfaceVelocityEnabledAttr()
en.Set(True)
print(" surfaceVelocityEnabled выставлен в True")
# трение: без материала на ленте тянуть нечем
MAT = "/World/_TestGrip"
m = stage.GetPrimAtPath(MAT)
if not m.IsValid():
m = stage.DefinePrim(MAT, "Material")
pm = UsdPhysics.MaterialAPI.Apply(m)
pm.CreateStaticFrictionAttr().Set(1.1)
pm.CreateDynamicFrictionAttr().Set(0.95)
pm.CreateRestitutionAttr().Set(0.0)
for target in (BELT, PROBE):
t = stage.GetPrimAtPath(target)
if t.IsValid():
UsdShade.MaterialBindingAPI.Apply(t).Bind(
UsdShade.Material(m), bindingStrength=UsdShade.Tokens.strongerThanDescendants,
materialPurpose="physics")
print(f" трение 1.1/0.95 привязано к ленте и к пробе")
probe = stage.GetPrimAtPath(PROBE)
print(f" проба существует: {probe.IsValid()}")
tl.play()
await app_utils.update_app_async(steps=20)
rp = RigidPrim(paths=[PROBE])
print("\n=== ВО ВРЕМЯ прогона ===")
print(" шаг x y z dx за шаг")
prev = None
for i in range(12):
pos, _ = rp.get_world_poses()
p = pos.numpy()[0]
d = "-" if prev is None else f"{(p[0]-prev)*1000:+7.1f} мм"
print(f" {i*10:4d} {p[0]:+7.3f} {p[1]:+7.3f} {p[2]:+7.3f} {d}")
prev = p[0]
await app_utils.update_app_async(steps=10)
tl.stop()
await app_utils.update_app_async(steps=5)