Fix captures 2/3 perdues + miroir + stabilite camera post-prise

- post_capture_grace=10 : ignore les erreurs -52 transitoires juste
  apres une prise (Canon EOS a besoin ~1s pour stabiliser le capteur)
- Threshold abandon capture : 3 -> 8 erreurs consecutives
- Threshold reconnexion : 5 -> 10 erreurs consecutives
- Avant chaque prise : eosviewfinder=1 pour garantir miroir leve
- Apres prise : viewfinder relance + sleep 1s + drain 8 evenements
- Sim auto-detect : pas de USB reset (evite boucle -52), verification
  fonctionnelle avec un capture_preview() avant de valider la camera
- Sim poll : 15s au lieu de 10s

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-15 15:02:51 +02:00
parent 529cb41581
commit eb0634fab4

View File

@@ -753,22 +753,30 @@ class PB:
# ── Thread caméra ────────────────────────────────────────────────────────
def _cam_loop(self):
errs = 0
post_capture_grace = 0 # frames de grâce après une prise (ignore erreurs transitoires)
while True:
# En simulation : tentative de connexion automatique toutes les 10s
# En simulation : tentative de connexion automatique toutes les 15s
# Pas de USB reset ici — reset seulement en cas de reconnexion
if self.sim:
time.sleep(10)
_usb_reset_done()
time.sleep(15)
for _ in range(2):
try:
c = gp.Camera(); c.init()
# Vérification fonctionnelle : un preview doit réussir
_f = c.capture_preview(); _bytes = bytes(_f.get_data_and_size())
if self.cam:
try: self.cam.exit()
except: pass
self.cam = c; self.sim = False; self.prev_actif = True
surf = pygame.image.load(io.BytesIO(_bytes))
surf = pygame.transform.scale(surf, (W, H))
with self.flock: self.frame = surf
print("DSLR détecté automatiquement")
break
except Exception as e:
print(f"Auto-detect caméra: {e}")
try: c.exit()
except: pass
time.sleep(1)
continue
if self.prev_actif:
@@ -776,8 +784,15 @@ class PB:
if self.cam is None:
raise RuntimeError("camera None")
if self.cap_demande:
# Déclenchement sans mouvement miroir :
# eosremoterelease garde le LV actif sur Canon EOS
# Avant la prise : activer le viewfinder EOS (miroir levé, liveview ON)
try:
cfg_c = self.cam.get_config()
vf = cfg_c.get_child_by_name('eosviewfinder')
vf.set_value(1)
self.cam.set_config(cfg_c)
time.sleep(0.2)
except: pass
# Déclenchement obturateur seul via eosremoterelease
triggered = False
try:
cfg_c = self.cam.get_config()
@@ -805,45 +820,65 @@ class PB:
rl.set_value('None')
self.cam.set_config(cfg_c)
except: pass
# Relance le viewfinder et laisse le capteur se stabiliser
try:
cfg_c = self.cam.get_config()
vf = cfg_c.get_child_by_name('eosviewfinder')
vf.set_value(1)
self.cam.set_config(cfg_c)
except: pass
time.sleep(1.0) # stabilisation capteur Canon entre deux prises
# Drainer les événements résiduels
for _ in range(8):
try:
self.cam.wait_for_event(50)
except: break
self.cap_result=ch; self.cap_demande=False; self.cap_done.set()
errs = 0
errs = 0; post_capture_grace = 10
else:
f=self.cam.capture_preview(); data=bytes(f.get_data_and_size())
surf=pygame.image.load(io.BytesIO(data))
surf=pygame.transform.scale(surf,(W,H))
with self.flock: self.frame=surf
errs = 0
if post_capture_grace > 0:
post_capture_grace -= 1
except Exception as e:
errs += 1
print(f"cam erreur ({errs}): {e}")
if self.cap_demande and errs >= 3:
# abandon de la capture en cours
self.cap_result=None; self.cap_demande=False; self.cap_done.set()
if errs >= 5:
# reconnexion automatique
print("Caméra perdue — tentative de reconnexion...")
self.prev_actif = False
with self.flock: self.frame = None
try:
if self.cam: self.cam.exit()
except: pass
self.cam = None; errs = 0
for _nb_retry in range(10):
time.sleep(3)
_usb_reset_done()
try:
c = gp.Camera(); c.init()
self.cam = c; self.prev_actif = True
print("Caméra reconnectée automatiquement")
break
except Exception as re:
print(f"Reconnexion échouée ({_nb_retry+1}): {re}")
else:
# 10 tentatives échouées → bascule en simulation
self.sim = True
print("Caméra introuvable → mode simulation")
if post_capture_grace > 0:
# Erreurs transitoires post-capture normales sur EOS — on ignore
post_capture_grace -= 1
print(f"cam post-capture ({post_capture_grace} restants): {e}")
time.sleep(0.2)
else:
time.sleep(0.1)
errs += 1
print(f"cam erreur ({errs}): {e}")
if self.cap_demande and errs >= 8:
# abandon de la capture seulement après 8 erreurs consécutives
self.cap_result=None; self.cap_demande=False; self.cap_done.set()
if errs >= 10:
# reconnexion automatique
print("Caméra perdue — tentative de reconnexion...")
self.prev_actif = False
with self.flock: self.frame = None
try:
if self.cam: self.cam.exit()
except: pass
self.cam = None; errs = 0
for _nb_retry in range(10):
time.sleep(3)
_usb_reset_done()
try:
c = gp.Camera(); c.init()
self.cam = c; self.prev_actif = True
print("Caméra reconnectée automatiquement")
break
except Exception as re:
print(f"Reconnexion échouée ({_nb_retry+1}): {re}")
else:
self.sim = True
print("Caméra introuvable → mode simulation")
else:
time.sleep(0.2)
else:
time.sleep(0.05)