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>
90 lines
4.2 KiB
Python
90 lines
4.2 KiB
Python
"""Что держит товар на x = -3.15: список коллайдеров в этой полосе + трасса остановки.
|
|
|
|
Пушер проверить не вышло - товар не доехал до точки срабатывания (PUSH_X = -3.9) и встал
|
|
раньше. Прежде чем править пушер, надо понять, упирается товар в препятствие или теряет
|
|
привод: это разные неисправности, и внешне они неотличимы.
|
|
"""
|
|
import sys, math
|
|
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, Usd, UsdGeom, UsdPhysics, PhysxSchema, UsdShade
|
|
from isaacsim.core.experimental.prims import RigidPrim
|
|
from robozon_sorter import config as C
|
|
from robozon_sorter.sim import plow_cell
|
|
|
|
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)
|
|
|
|
bb = UsdGeom.BBoxCache(Usd.TimeCode.Default(), [UsdGeom.Tokens.default_, UsdGeom.Tokens.render])
|
|
print("КОЛЛАЙДЕРЫ, накрывающие полосу x -3.4..-3.0 на высоте ленты (z 1.75..2.10):")
|
|
for p in stage.Traverse():
|
|
if not p.HasAPI(UsdPhysics.CollisionAPI):
|
|
continue
|
|
en = p.GetAttribute("physics:collisionEnabled")
|
|
if en and en.Get() is False:
|
|
continue
|
|
r = bb.ComputeWorldBound(p).ComputeAlignedRange()
|
|
mn, mx = r.GetMin(), r.GetMax()
|
|
if mx[0] < -3.4 or mn[0] > -3.0:
|
|
continue
|
|
if mx[2] < 1.75 or mn[2] > 2.10:
|
|
continue
|
|
if abs(mn[1]) > 0.6 and abs(mx[1]) > 0.6 and mn[1] * mx[1] > 0:
|
|
continue
|
|
print(f" x {mn[0]:+7.3f}..{mx[0]:+7.3f} y {mn[1]:+6.2f}..{mx[1]:+6.2f} "
|
|
f"z {mn[2]:+6.3f}..{mx[2]:+6.3f} {p.GetPath()}")
|
|
|
|
# какая лента под этой точкой и что у неё со скоростью
|
|
print("\nЛЕНТЫ ПОД x=-3.15:")
|
|
for path in list(plow_cell.BELTS) + [plow_cell.BRANCH]:
|
|
pr = stage.GetPrimAtPath(path)
|
|
if not pr.IsValid():
|
|
continue
|
|
r = bb.ComputeWorldBound(pr).ComputeAlignedRange()
|
|
mn, mx = r.GetMin(), r.GetMax()
|
|
if mn[0] <= -3.15 <= mx[0]:
|
|
v = pr.GetAttribute("physxSurfaceVelocity:surfaceVelocity").Get()
|
|
e = pr.GetAttribute("physxSurfaceVelocity:surfaceVelocityEnabled")
|
|
print(f" {path}: v={v} включено={e.Get() if e else None} "
|
|
f"y {mn[1]:+.2f}..{mx[1]:+.2f}")
|
|
|
|
# трасса: пустить товар и печатать x, пока не встанет
|
|
TOP = bb.ComputeWorldBound(stage.GetPrimAtPath("/World/ConveyorTrack_03/Belt")
|
|
).ComputeAlignedRange().GetMax()[2]
|
|
if stage.GetPrimAtPath("/World/_Stall").IsValid():
|
|
stage.RemovePrim("/World/_Stall")
|
|
stage.DefinePrim("/World/_Stall", "Xform")
|
|
c = UsdGeom.Cube.Define(stage, "/World/_Stall/item"); c.CreateSizeAttr().Set(2.0)
|
|
xf = UsdGeom.Xformable(c.GetPrim())
|
|
xf.AddTranslateOp().Set(Gf.Vec3d(-2.40, 0.0, TOP + 0.055))
|
|
xf.AddScaleOp().Set(Gf.Vec3f(0.05, 0.05, 0.05))
|
|
p = c.GetPrim()
|
|
UsdPhysics.RigidBodyAPI.Apply(p); UsdPhysics.CollisionAPI.Apply(p)
|
|
UsdPhysics.MassAPI.Apply(p).CreateMassAttr().Set(0.5)
|
|
PhysxSchema.PhysxRigidBodyAPI.Apply(p).CreateSolverPositionIterationCountAttr().Set(32)
|
|
g = stage.GetPrimAtPath(plow_cell.GRIP_MATERIAL)
|
|
if g.IsValid():
|
|
UsdShade.MaterialBindingAPI.Apply(p).Bind(
|
|
UsdShade.Material(g), bindingStrength=UsdShade.Tokens.strongerThanDescendants,
|
|
materialPurpose="physics")
|
|
|
|
tl.play(); await app_utils.update_app_async(steps=25)
|
|
rp = RigidPrim(paths=["/World/_Stall/item"])
|
|
print("\nТРАССА (старт x=-2.40):")
|
|
prev, t0 = None, float(tl.get_current_time())
|
|
for i in range(28):
|
|
q = rp.get_world_poses()[0].numpy()[0]
|
|
t = float(tl.get_current_time())
|
|
d = "-" if prev is None else f"{(float(q[0])-prev)*1000:+7.1f} мм"
|
|
print(f" t={t-t0:5.2f}s x={float(q[0]):+7.3f} y={float(q[1]):+6.3f} "
|
|
f"z={float(q[2]):+6.3f} {d}")
|
|
prev = float(q[0])
|
|
await app_utils.update_app_async(steps=6)
|
|
tl.stop(); await app_utils.update_app_async(steps=5)
|