Skip to content
This repository was archived by the owner on Sep 4, 2025. It is now read-only.

Commit 21cc415

Browse files
Implement remote vision system with tracking and training capabilities
- Added Tracking class for tracking the largest detected object and sending servo commands. - Introduced TrainModel class for training a face recognition model using images from a dataset. - Created VideoStream class to handle various camera sources including remote streams, GStreamer, and libcamera. - Developed RemoteVision class to manage video input, face detection, and motion detection modes. - Integrated pubsub messaging for logging and state management across modules. - Enhanced error handling and logging throughout the system for better debugging and user feedback.
1 parent 45acccb commit 21cc415

20 files changed

+37892
-0
lines changed

modules/SerialShareManager.py

Lines changed: 339 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,339 @@
1+
import threading
2+
import time
3+
from pubsub import pub
4+
import traceback
5+
import serial # Serial bağlantı için
6+
7+
# --- MQTT aktifse bu modül devre dışı bırakılır ---
8+
DISABLE_SERIAL_SHARE_MANAGER = False
9+
10+
class SerialShareManager:
11+
"""
12+
Class to manage ESP32 serial connection sharing between modules
13+
"""
14+
_instance = None
15+
_lock = threading.RLock()
16+
17+
def __new__(cls):
18+
"""Singleton pattern to ensure only one instance exists"""
19+
with cls._lock:
20+
if cls._instance is None:
21+
cls._instance = super(SerialShareManager, cls).__new__(cls)
22+
cls._instance._serial = None
23+
cls._instance._initialized = False
24+
cls._instance._active_modules = {}
25+
cls._instance._verbose_logging = False # Default olarak detaylı log kapalı
26+
cls._instance._setup_pubsub()
27+
# Log creation only in verbose mode
28+
try:
29+
if cls._instance._verbose_logging:
30+
pub.sendMessage('log', msg=f'[SerialManager] Instance created')
31+
except:
32+
pass # Suppress if pub not ready
33+
return cls._instance
34+
35+
def _setup_pubsub(self):
36+
"""Set up pubsub handlers"""
37+
try:
38+
pub.subscribe(self._handle_serial_ready, 'esp32:serial_ready')
39+
pub.subscribe(self._handle_module_connect, 'esp32:module_connect')
40+
pub.subscribe(self._handle_module_disconnect, 'esp32:module_disconnect')
41+
# Önemli olaylar için yeni abonelikler
42+
pub.subscribe(self._handle_priority_animation, 'priority:person_detected')
43+
except:
44+
# May happen if pubsub not initialized yet
45+
pass
46+
47+
def _handle_serial_ready(self):
48+
"""Handle serial ready event from provider module"""
49+
if self._verbose_logging:
50+
pub.sendMessage('log', msg=f'[SerialManager] Received serial ready notification')
51+
# Broadcast our own ready event
52+
try:
53+
threading.Timer(0.2, lambda: pub.sendMessage('esp32:serial_global_ready')).start()
54+
except:
55+
pass
56+
57+
def _handle_module_connect(self, module_name):
58+
"""Track module connection to serial"""
59+
with self._lock:
60+
self._active_modules[module_name] = time.time()
61+
if self._verbose_logging:
62+
pub.sendMessage('log', msg=f'[SerialManager] Module {module_name} connected to serial')
63+
64+
def _handle_module_disconnect(self, module_name):
65+
"""Track module disconnection from serial"""
66+
with self._lock:
67+
if module_name in self._active_modules:
68+
del self._active_modules[module_name]
69+
if self._verbose_logging:
70+
pub.sendMessage('log', msg=f'[SerialManager] Module {module_name} disconnected from serial')
71+
72+
def _handle_priority_animation(self, person_name, animation_name="RAINBOW_CYCLE"):
73+
"""Öncelikli kişi için animasyon tetikleyici"""
74+
if self._serial and self._initialized:
75+
try:
76+
pub.sendMessage('log:info', msg=f'[SerialManager] Priority person detected: {person_name}, ensuring animation runs')
77+
# LED animasyonunu doğrudan tetikle
78+
animation_cmd = f"ANIMATE {animation_name.upper()} GREEN 3\n"
79+
self._serial.write(animation_cmd.encode())
80+
81+
# Yedekleme olarak standart LED animasyon kanalını da tetikle
82+
threading.Timer(0.5, lambda: pub.sendMessage('led:animate', animation=animation_name, color='GREEN', repeat=3)).start()
83+
except Exception as e:
84+
pub.sendMessage('log:error', msg=f'[SerialManager] Error sending priority animation: {e}')
85+
86+
def register_serial_provider(self, serial, provider_name='neopixel'):
87+
"""Register the serial connection from a provider module"""
88+
if DISABLE_SERIAL_SHARE_MANAGER:
89+
return False
90+
with self._lock:
91+
old_serial = self._serial
92+
self._serial = serial
93+
self._initialized = True
94+
self._active_modules[provider_name] = time.time()
95+
96+
# Eski bağlantıyı kapat (varsa)
97+
if old_serial and old_serial != serial:
98+
try:
99+
old_serial.close()
100+
except:
101+
pass
102+
103+
try:
104+
if self._verbose_logging:
105+
pub.sendMessage('log', msg=f'[SerialManager] Serial registered by {provider_name}')
106+
107+
# Bağlantıyı test et
108+
self._verify_connection()
109+
110+
# Notify others that serial is ready
111+
threading.Timer(0.5, lambda: pub.sendMessage('esp32:serial_global_ready')).start()
112+
except Exception as e:
113+
pub.sendMessage('log:error', msg=f'[SerialManager] Error in register_serial_provider: {e}')
114+
traceback.print_exc()
115+
116+
def _verify_connection(self):
117+
"""Seri port bağlantısını doğrula"""
118+
if not self._serial:
119+
return False
120+
121+
try:
122+
# Veri akışını temizle
123+
self._serial.reset_input_buffer()
124+
self._serial.reset_output_buffer()
125+
126+
# PING komutu gönder
127+
self._serial.write(b"PING\n")
128+
129+
# Yanıtı bekle (2 saniye timeout)
130+
start_time = time.time()
131+
response = ""
132+
133+
while time.time() - start_time < 2.0:
134+
if self._serial.in_waiting > 0:
135+
line = self._serial.readline().decode().strip()
136+
if "PONG" in line:
137+
if self._verbose_logging:
138+
pub.sendMessage('log:info', msg=f'[SerialManager] Connection verified (PONG received)')
139+
return True
140+
141+
# PONG alınamadı, tekrar dene
142+
self._serial.write(b"PING\n")
143+
start_time = time.time()
144+
145+
while time.time() - start_time < 2.0:
146+
if self._serial.in_waiting > 0:
147+
line = self._serial.readline().decode().strip()
148+
if "PONG" in line:
149+
if self._verbose_logging:
150+
pub.sendMessage('log:info', msg=f'[SerialManager] Connection verified on second attempt')
151+
return True
152+
153+
pub.sendMessage('log:warn', msg=f'[SerialManager] Connection verification failed (no PONG response)')
154+
return False
155+
156+
except Exception as e:
157+
pub.sendMessage('log:error', msg=f'[SerialManager] Error verifying connection: {e}')
158+
return False
159+
160+
def get_serial(self, module_name):
161+
"""Get the shared serial connection for a module"""
162+
if DISABLE_SERIAL_SHARE_MANAGER:
163+
return None
164+
with self._lock:
165+
if self._serial is not None and self._initialized:
166+
self._active_modules[module_name] = time.time()
167+
if self._verbose_logging:
168+
try:
169+
pub.sendMessage('log', msg=f'[SerialManager] Providing serial to {module_name}')
170+
except:
171+
# Suppress errors if pub not ready
172+
pass
173+
return self._serial
174+
else:
175+
if self._verbose_logging:
176+
try:
177+
pub.sendMessage('log', msg=f'[SerialManager] Serial not available for {module_name}')
178+
except:
179+
# Suppress errors if pub not ready
180+
pass
181+
return None
182+
183+
def send_command(self, command, module_name="unknown"):
184+
"""Direkt komut gönderme methodu"""
185+
if DISABLE_SERIAL_SHARE_MANAGER:
186+
return False
187+
with self._lock:
188+
if self._serial and self._initialized:
189+
try:
190+
# Komut bir satır sonu ile bitmiyorsa ekle
191+
if not command.endswith('\n'):
192+
command += '\n'
193+
194+
# Komutu gönder
195+
self._serial.write(command.encode())
196+
197+
# İşleme için kısa süre bekle
198+
time.sleep(0.05)
199+
200+
if self._verbose_logging:
201+
pub.sendMessage('log:debug', msg=f'[SerialManager] Command sent from {module_name}: {command.strip()}')
202+
203+
return True
204+
except Exception as e:
205+
pub.sendMessage('log:error', msg=f'[SerialManager] Error sending command from {module_name}: {e}')
206+
else:
207+
if self._verbose_logging:
208+
pub.sendMessage('log:warn', msg=f'[SerialManager] Cannot send command: serial not initialized')
209+
210+
return False
211+
212+
def connect(self, serial_port, baudrate=115200, provider_name="auto_connect"):
213+
"""Seri port bağlantısını kur ve paylaş"""
214+
if DISABLE_SERIAL_SHARE_MANAGER:
215+
return False
216+
with self._lock:
217+
# Eğer halihazırda bir seri port bağlantısı varsa, kapat
218+
if self._serial and self._serial.is_open:
219+
try:
220+
self._serial.close()
221+
time.sleep(0.5) # Kapanma için bekle
222+
except:
223+
pass
224+
225+
try:
226+
# Bağlantı için 3 deneme yap
227+
for attempt in range(3):
228+
try:
229+
serial_connection = serial.Serial(
230+
serial_port,
231+
baudrate,
232+
timeout=1,
233+
write_timeout=1
234+
)
235+
236+
# Veri akışını temizle
237+
serial_connection.reset_input_buffer()
238+
serial_connection.reset_output_buffer()
239+
240+
# ESP32'nin hazır olması için bekle
241+
time.sleep(1.5)
242+
243+
# Bağlantıyı test et
244+
serial_connection.write(b"PING\n")
245+
time.sleep(0.5)
246+
247+
response = ""
248+
start_time = time.time()
249+
while time.time() - start_time < 2.0:
250+
if serial_connection.in_waiting > 0:
251+
line = serial_connection.readline().decode().strip()
252+
if "PONG" in line:
253+
# Bağlantı başarılı
254+
self._serial = serial_connection
255+
self._initialized = True
256+
self._active_modules[provider_name] = time.time()
257+
258+
pub.sendMessage('log:info', msg=f'[SerialManager] Connected to {serial_port} at {baudrate} baud')
259+
260+
# Haber ver
261+
threading.Timer(0.5, lambda: pub.sendMessage('esp32:serial_global_ready')).start()
262+
263+
return True
264+
265+
# PONG alınamadı, birkaç saniye bekleyip tekrar dene
266+
time.sleep(2)
267+
268+
except Exception as e:
269+
pub.sendMessage('log:warn', msg=f'[SerialManager] Connection attempt {attempt+1} failed: {e}')
270+
time.sleep(1)
271+
272+
pub.sendMessage('log:error', msg=f'[SerialManager] Failed to connect after 3 attempts')
273+
return False
274+
275+
except Exception as e:
276+
pub.sendMessage('log:error', msg=f'[SerialManager] Connection error: {e}')
277+
return False
278+
279+
def get_active_modules(self):
280+
"""Get a list of active modules using the serial connection"""
281+
if DISABLE_SERIAL_SHARE_MANAGER:
282+
return []
283+
with self._lock:
284+
return list(self._active_modules.keys())
285+
286+
def set_verbose_logging(self, verbose):
287+
"""Enable or disable verbose logging"""
288+
if DISABLE_SERIAL_SHARE_MANAGER:
289+
return
290+
self._verbose_logging = verbose
291+
292+
# Create a global instance
293+
serialManager = SerialShareManager()
294+
295+
def register_serial(serial_connection, provider_name='neopixel'):
296+
"""Register a serial connection to be shared"""
297+
if DISABLE_SERIAL_SHARE_MANAGER:
298+
return False
299+
try:
300+
global serialManager
301+
serialManager.register_serial_provider(serial_connection, provider_name)
302+
return True
303+
except Exception as e:
304+
print(f"Error in register_serial: {e}")
305+
traceback.print_exc()
306+
return False
307+
308+
def get_serial(module_name):
309+
"""Get the shared serial connection for a module"""
310+
if DISABLE_SERIAL_SHARE_MANAGER:
311+
return None
312+
try:
313+
global serialManager
314+
return serialManager.get_serial(module_name)
315+
except Exception as e:
316+
print(f"Error in get_serial: {e}")
317+
traceback.print_exc()
318+
return None
319+
320+
def send_command(command, module_name="unknown"):
321+
"""Komut gönderme fonksiyonu"""
322+
if DISABLE_SERIAL_SHARE_MANAGER:
323+
return False
324+
global serialManager
325+
return serialManager.send_command(command, module_name)
326+
327+
def connect_serial(serial_port, baudrate=115200):
328+
"""Seri port bağlantısı kur"""
329+
if DISABLE_SERIAL_SHARE_MANAGER:
330+
return False
331+
global serialManager
332+
return serialManager.connect(serial_port, baudrate)
333+
334+
def set_verbose_logging(verbose):
335+
"""Set verbose logging for SerialShareManager"""
336+
if DISABLE_SERIAL_SHARE_MANAGER:
337+
return
338+
global serialManager
339+
serialManager.set_verbose_logging(verbose)

0 commit comments

Comments
 (0)