Conversation
Greptile SummaryThis PR introduces a self-contained Key changes:
Issues found:
Confidence Score: 2/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Agent
participant SecurityModule
participant PatrolRouter
participant Planner as ReplanningAStarPlanner
participant NavStack as Navigation (goal_request / cmd_vel)
participant YOLO as Yolo2DDetector
participant TTS as SpeakSkill
Agent->>SecurityModule: start_security_patrol()
SecurityModule->>Planner: set_replanning_enabled(False)
SecurityModule->>SecurityModule: spawn _main_loop thread
SecurityModule-->>Agent: "Security patrol started"
loop PATROLLING state
SecurityModule->>PatrolRouter: next_goal()
PatrolRouter-->>SecurityModule: PoseStamped goal
SecurityModule->>NavStack: goal_request.publish(goal)
SecurityModule->>YOLO: process_image(latest_image)
alt person detected
SecurityModule->>NavStack: goal_request.publish(current_pose) [cancel]
SecurityModule->>TTS: speak("Intruder detected")
SecurityModule->>SecurityModule: transition → FOLLOWING
else no detection
SecurityModule->>SecurityModule: wait for goal_reached event
end
end
loop FOLLOWING state
SecurityModule->>YOLO: process_image(latest_image)
alt person visible
SecurityModule->>NavStack: cmd_vel.publish(twist)
else person lost
SecurityModule->>NavStack: cmd_vel.publish(Twist.zero())
SecurityModule->>TTS: speak("Lost sight of intruder, resuming patrol")
SecurityModule->>PatrolRouter: reset()
SecurityModule->>SecurityModule: transition → PATROLLING
end
end
Agent->>SecurityModule: stop_security_patrol()
SecurityModule->>SecurityModule: _stop_event.set()
SecurityModule->>Planner: set_replanning_enabled(True)
SecurityModule->>NavStack: goal_request.publish(current_pose) [cancel]
SecurityModule->>SecurityModule: join _main_loop thread (timeout=5s)
SecurityModule->>SecurityModule: transition → IDLE
SecurityModule-->>Agent: "Security patrol stopped"
Last reviewed commit: "feat(security): add ..." |
| def _follow_step(self) -> None: | ||
| """One iteration of the follow loop (YOLO detect + servo + publish).""" | ||
| with self._lock: | ||
| latest_image = self._latest_image | ||
|
|
||
| if latest_image is None: | ||
| return | ||
|
|
||
| best = self._find_best_person(latest_image) | ||
|
|
||
| if best is None: | ||
| self.cmd_vel.publish(Twist.zero()) | ||
| self._speak_skill.speak("Lost sight of intruder, resuming patrol") | ||
| self._router.reset() | ||
| self._has_active_goal = False | ||
| self._transition_to("PATROLLING") | ||
| return |
There was a problem hiding this comment.
CPU busy-wait when
latest_image is None during FOLLOWING
When latest_image is None, _follow_step returns immediately with no sleep or yield. The _main_loop will immediately call it again, spinning at 100% CPU until an image arrives. Compare this with _patrol_step, which correctly uses self._stop_event.wait(timeout=0.01) in the analogous branch. A similar small wait should be added here:
if latest_image is None:
self._stop_event.wait(timeout=0.01)
return85be8b4 to
d9faea6
Compare
| return getattr(python_module, attr_name)() # type: ignore[no-any-return] | ||
| module_path, class_name = all_modules[name].rsplit(".", 1) | ||
| python_module = __import__(module_path, fromlist=[class_name]) | ||
| return getattr(python_module, class_name).blueprint() # type: ignore[no-any-return] |
There was a problem hiding this comment.
thanks for breaking this out into that other PR. It does make it easier to understand.
|
|
||
| if self.processing_thread and self.processing_thread.is_alive(): | ||
| self.processing_thread.join(timeout=5.0) | ||
| self.processing_thread.join(timeout=30.0) |
There was a problem hiding this comment.
why so big? this makes me worry about other timeouts
| def _play_audio_event(self, audio_event) -> None: # type: ignore[no-untyped-def] | ||
| """Play audio from an AudioEvent.""" | ||
| if not self._running or not self._stream: | ||
| if not self._running: |
There was a problem hiding this comment.
why does self._stream need a lock but self._running doesn't?
aa28910 to
a3a2469
Compare
Problem
Closes DIM-XXX
Solution
Breaking Changes
None
How to Test
VERY IMPORTANT: YOU MUST EXPLORE FIRST
uv run dimos --dtop --robot-ip <IP> run --disable spatial-memory unitree-go2-securityhumancliand tell itstart the security patrol. Just call start_security_patrol. Do not ask me anything.Contributor License Agreement