importcontextlibimportqueueimporttimefromthreadingimportEvent,ThreadfromtypingimportTypeVarfromtqdmimporttqdmfrompupil_labs.neon_usbimportIMU,IMUDataT=TypeVar("T")defget_all_items(q:queue.Queue[T])->list[T]:"""Retrieve all items from a queue and always at least one."""items=[]# Need to get at least one item# Otherwise the queue might be spammed with requestsitems.append(q.get())whileTrue:try:items.append(q.get_nowait())exceptqueue.Empty:breakreturnitemsdefimu_receiver(output_q:queue.Queue[IMUData],start_event:Event,stop_event:Event,wait_event:Event|None=None,)->None:imu=IMU()start_event.set()ifwait_eventisnotNone:wait_event.wait()whileTrue:ifstop_event.is_set():breakimu_data=imu.get_imu_data()withcontextlib.suppress(queue.Full):output_q.put_nowait(imu_data)imu_start_signal=Event()imu_stop_signal=Event()imu_q=queue.Queue[IMUData](maxsize=400)imu_thread=Thread(target=imu_receiver,args=(imu_q,imu_start_signal,imu_stop_signal),)imu_thread.start()imu_start_signal.wait()total_frames=500frame_counter=0withtqdm(total=total_frames)aspbar:start=time.time()whileTrue:ifframe_counter>=total_frames:breakimu_frames=get_all_items(imu_q)num_imu_frames=len(imu_frames)frame_counter+=num_imu_framespbar.update(num_imu_frames)end=time.time()imu_stop_signal.set()print(f"IMU FPS: {frame_counter/(end-start):.1f}\t Duration: {end-start:.1f}")