============================================================================= set_qpos — manager-required runtime write to a single articulation's qpos. Two write modes: - Free-base 7-vec shortcut: len=7 and the first joint is mjJNT_FREE, writes only the 7 free-joint slots (xyz + quat). Skips dof joints. - Full per-articulation qpos: len matches the articulation's total qpos dim (sum of per-joint
| 2604 | // path so derived quantities (xpos, sensors) reflect the new state. |
| 2605 | // ============================================================================= |
| 2606 | TSharedPtr<FJsonObject> FURLabRpcDispatcher::HandleSetQpos(const TSharedPtr<FJsonObject>& Req) |
| 2607 | { |
| 2608 | AAMjManager* Mgr = OwnerMgr.Get(); |
| 2609 | if (!Mgr || !Mgr->PhysicsEngine || !Mgr->PhysicsEngine->IsInitialized()) |
| 2610 | return MakeError(TEXT("not_ready"), TEXT("Manager not initialised")); |
| 2611 | |
| 2612 | mjModel* m = Mgr->PhysicsEngine->GetModel(); |
| 2613 | mjData* d = Mgr->PhysicsEngine->GetData(); |
| 2614 | if (!m || !d) |
| 2615 | return MakeError(TEXT("not_ready"), TEXT("MjModel/MjData missing")); |
| 2616 | |
| 2617 | // target/target_by wire shape. target_by="actor_name" looks up via |
| 2618 | // the manager's GetArticulation (UE name match); default |
| 2619 | // "actor_id" walks ActorId. |
| 2620 | FString Target, By; |
| 2621 | Req->TryGetStringField(TEXT("target"), Target); |
| 2622 | Req->TryGetStringField(TEXT("target_by"), By); |
| 2623 | if (Target.IsEmpty()) |
| 2624 | { |
| 2625 | return MakeError(TEXT("missing_field"), |
| 2626 | TEXT("set_qpos: missing 'target' field")); |
| 2627 | } |
| 2628 | const bool bByName = By.Equals(TEXT("actor_name"), ESearchCase::IgnoreCase); |
| 2629 | |
| 2630 | AMjArticulation* Art = nullptr; |
| 2631 | if (bByName) |
| 2632 | { |
| 2633 | Art = Mgr->GetArticulation(Target); |
| 2634 | } |
| 2635 | else |
| 2636 | { |
| 2637 | for (AMjArticulation* A : Mgr->GetAllArticulations()) |
| 2638 | { |
| 2639 | if (A && A->ActorId.Equals(Target)) |
| 2640 | { |
| 2641 | Art = A; |
| 2642 | break; |
| 2643 | } |
| 2644 | } |
| 2645 | } |
| 2646 | if (!Art) |
| 2647 | { |
| 2648 | return MakeError(TEXT("unknown_articulation"), Target); |
| 2649 | } |
| 2650 | |
| 2651 | const TArray<TSharedPtr<FJsonValue>>* QPosArr = nullptr; |
| 2652 | if (!Req->TryGetArrayField(TEXT("qpos"), QPosArr) || !QPosArr) |
| 2653 | return MakeError(TEXT("missing_field"), TEXT("set_qpos requires 'qpos' array")); |
| 2654 | |
| 2655 | struct FJointSlot |
| 2656 | { |
| 2657 | int32 Adr; |
| 2658 | int32 Size; |
| 2659 | int32 Type; |
| 2660 | }; |
| 2661 | TArray<FJointSlot> Slots; |
| 2662 | int32 ArtQDim = 0; |
| 2663 | for (UMjJoint* J : Art->GetJoints()) |
nothing calls this directly
no test coverage detected