mirror of
https://github.com/EyeTrackVR/EyeTrackVR.git
synced 2025-11-04 14:39:42 +08:00
feat: add v2 serial comms with packet headers
* feat: serial read no longer drops frames on buffer reset * fix: fps now calculated properly * fix: remove unnecessary logs
This commit is contained in:
parent
295f10476d
commit
c2aad0e859
@ -11,6 +11,15 @@ import numpy as np
|
|||||||
|
|
||||||
WAIT_TIME = 0.1
|
WAIT_TIME = 0.1
|
||||||
|
|
||||||
|
# Serial communication protocol:
|
||||||
|
# header-begin (2 bytes)
|
||||||
|
# header-type (2 bytes)
|
||||||
|
# packet-size (2 bytes)
|
||||||
|
# packet (packet-size bytes)
|
||||||
|
ETVR_HEADER = b'\xff\xa0'
|
||||||
|
ETVR_HEADER_FRAME = b'\xff\xa1'
|
||||||
|
ETVR_HEADER_LEN = 6
|
||||||
|
|
||||||
|
|
||||||
class CameraState(Enum):
|
class CameraState(Enum):
|
||||||
CONNECTING = 0
|
CONNECTING = 0
|
||||||
@ -18,11 +27,6 @@ class CameraState(Enum):
|
|||||||
DISCONNECTED = 2
|
DISCONNECTED = 2
|
||||||
|
|
||||||
|
|
||||||
# Find JPEG frames based on start and end bytes.
|
|
||||||
FRAME_JPEG_BEGIN = b'\xff\xd8'
|
|
||||||
FRAME_JPEG_END = b'\xff\xd9'
|
|
||||||
|
|
||||||
|
|
||||||
class Camera:
|
class Camera:
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@ -45,6 +49,7 @@ class Camera:
|
|||||||
self.wired_camera: "cv2.VideoCapture" = None
|
self.wired_camera: "cv2.VideoCapture" = None
|
||||||
|
|
||||||
self.serial_connection = None
|
self.serial_connection = None
|
||||||
|
self.last_frame_time = time.time()
|
||||||
self.frame_number = 0
|
self.frame_number = 0
|
||||||
self.fps = 0
|
self.fps = 0
|
||||||
self.start = True
|
self.start = True
|
||||||
@ -125,38 +130,27 @@ class Camera:
|
|||||||
self.camera_status = CameraState.DISCONNECTED
|
self.camera_status = CameraState.DISCONNECTED
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_next_frame_bounds(self):
|
def get_next_packet_bounds(self):
|
||||||
beg = -1
|
beg = -1
|
||||||
end = -1
|
while beg == -1:
|
||||||
# Initial read.
|
self.buffer += self.serial_connection.read(2048)
|
||||||
self.buffer += self.serial_connection.read(4096)
|
beg = self.buffer.find(ETVR_HEADER + ETVR_HEADER_FRAME)
|
||||||
while beg == -1 or end == -1:
|
# Discard any data before the frame header.
|
||||||
# Find the jpeg begin bytes.
|
|
||||||
if beg == -1:
|
|
||||||
beg = self.buffer.find(FRAME_JPEG_BEGIN)
|
|
||||||
continue
|
|
||||||
# Discard any data before the jpeg frame.
|
|
||||||
if beg > 0:
|
if beg > 0:
|
||||||
self.buffer = self.buffer[beg:]
|
self.buffer = self.buffer[beg:]
|
||||||
beg = 0
|
beg = 0
|
||||||
continue
|
# We know exactly how long the jpeg packet is
|
||||||
# Find the jpeg end bytes.
|
end = int.from_bytes(self.buffer[4:6], signed=False, byteorder="little")
|
||||||
end = self.buffer.find(FRAME_JPEG_END)
|
self.buffer += self.serial_connection.read(end - len(self.buffer))
|
||||||
# Read more data when no jpeg end bytes found.
|
|
||||||
if end == -1:
|
|
||||||
self.buffer += self.serial_connection.read(2048)
|
|
||||||
return beg, end
|
return beg, end
|
||||||
|
|
||||||
def get_next_jpeg_frame(self):
|
def get_next_jpeg_frame(self):
|
||||||
beg, end = self.get_next_frame_bounds()
|
beg, end = self.get_next_packet_bounds()
|
||||||
# Extract jpeg from the buffer.
|
jpeg = self.buffer[beg+ETVR_HEADER_LEN:end+ETVR_HEADER_LEN]
|
||||||
jpeg = self.buffer[beg:end+2]
|
self.buffer = self.buffer[end+ETVR_HEADER_LEN:]
|
||||||
# Remove jpeg from the buffer.
|
|
||||||
self.buffer = self.buffer[end+2:]
|
|
||||||
return jpeg
|
return jpeg
|
||||||
|
|
||||||
def get_serial_camera_picture(self, should_push):
|
def get_serial_camera_picture(self, should_push):
|
||||||
start = time.time()
|
|
||||||
try:
|
try:
|
||||||
if self.serial_connection.in_waiting:
|
if self.serial_connection.in_waiting:
|
||||||
jpeg = self.get_next_jpeg_frame()
|
jpeg = self.get_next_jpeg_frame()
|
||||||
@ -171,7 +165,9 @@ class Camera:
|
|||||||
self.serial_connection.reset_input_buffer()
|
self.serial_connection.reset_input_buffer()
|
||||||
self.buffer = b''
|
self.buffer = b''
|
||||||
# Calculate the fps.
|
# Calculate the fps.
|
||||||
delta_time = time.time() - start
|
current_frame_time = time.time()
|
||||||
|
delta_time = current_frame_time - self.last_frame_time
|
||||||
|
self.last_frame_time = current_frame_time
|
||||||
if delta_time > 0:
|
if delta_time > 0:
|
||||||
self.fps = 1 / delta_time
|
self.fps = 1 / delta_time
|
||||||
self.frame_number = self.frame_number + 1
|
self.frame_number = self.frame_number + 1
|
||||||
@ -182,7 +178,6 @@ class Camera:
|
|||||||
print(ex)
|
print(ex)
|
||||||
except Exception:
|
except Exception:
|
||||||
print("\033[93m[WARN]Serial capture source problem, assuming camera disconnected, waiting for reconnect.\033[0m")
|
print("\033[93m[WARN]Serial capture source problem, assuming camera disconnected, waiting for reconnect.\033[0m")
|
||||||
|
|
||||||
self.serial_connection.close()
|
self.serial_connection.close()
|
||||||
self.camera_status = CameraState.DISCONNECTED
|
self.camera_status = CameraState.DISCONNECTED
|
||||||
pass
|
pass
|
||||||
@ -217,7 +212,6 @@ class Camera:
|
|||||||
def push_image_to_queue(self, image, frame_number, fps):
|
def push_image_to_queue(self, image, frame_number, fps):
|
||||||
# If there's backpressure, just yell. We really shouldn't have this unless we start getting
|
# If there's backpressure, just yell. We really shouldn't have this unless we start getting
|
||||||
# some sort of capture event conflict though.
|
# some sort of capture event conflict though.
|
||||||
print(f"N {frame_number} FPS {fps}")
|
|
||||||
qsize = self.camera_output_outgoing.qsize()
|
qsize = self.camera_output_outgoing.qsize()
|
||||||
if qsize > 1:
|
if qsize > 1:
|
||||||
print(
|
print(
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user