|
| 1 | +import logging |
| 2 | +logging.basicConfig(level=logging.DEBUG) |
| 3 | + |
| 4 | +# import serial |
| 5 | +import matplotlib.pyplot as plt |
| 6 | + |
| 7 | +# from matplotlib.animation import FuncAnimation, FFMpegWriter |
| 8 | +import ffmpegio as ff |
| 9 | + |
| 10 | +from datetime import datetime, timedelta |
| 11 | +import numpy as np |
| 12 | +import schedule |
| 13 | +import time |
| 14 | + |
| 15 | +# Constants |
| 16 | +GRAVITY = 9.81 # Standard gravity in m/s² |
| 17 | + |
| 18 | +# Initialize serial connections to HC-06 devices |
| 19 | +# ser_x_accel = serial.Serial('COM4', 9600, timeout=1) # X-axis acceleration data |
| 20 | +# ser_y_angle = serial.Serial('COM11', 9600, timeout=1) # Y-axis angle data |
| 21 | + |
| 22 | +# Initialize empty lists to store data |
| 23 | +x_accel_data = [] |
| 24 | +y_angle_data = [] |
| 25 | +timestamps = [] |
| 26 | + |
| 27 | +# Initialize Excel workbook |
| 28 | +# wb = openpyxl.Workbook() |
| 29 | +# ws = wb.active |
| 30 | +# ws.title = "Sensor Data" |
| 31 | +# ws.append(["Timestamp", "X Acceleration (m/s²)", "Y Angle (degrees)"]) |
| 32 | + |
| 33 | + |
| 34 | +# Function to update the plot and log data |
| 35 | +def update(f): |
| 36 | + # Read data from serial connections |
| 37 | + line_x_accel = np.random.randn(1) # ser_x_accel.readline().decode('utf-8').strip() |
| 38 | + line_y_angle = np.random.randn(1) # ser_y_angle.readline().decode('utf-8').strip() |
| 39 | + |
| 40 | + try: |
| 41 | + # Parse and process X-axis acceleration data |
| 42 | + x_accel_g = float(line_x_accel) # Acceleration in g read from serial |
| 43 | + x_accel_ms2 = x_accel_g * GRAVITY # Convert from g to m/s² |
| 44 | + x_accel_data.append(x_accel_ms2) |
| 45 | + |
| 46 | + # Parse and process Y-axis angle data |
| 47 | + y_angle = float(line_y_angle) |
| 48 | + y_angle_data.append(y_angle) |
| 49 | + |
| 50 | + # Append timestamp |
| 51 | + timestamps.append(datetime.now()) |
| 52 | + |
| 53 | + # Limit data points to show only the latest 100 |
| 54 | + if len(x_accel_data) > 100: |
| 55 | + x_accel_data.pop(0) |
| 56 | + y_angle_data.pop(0) |
| 57 | + timestamps.pop(0) |
| 58 | + |
| 59 | + # Log data to Excel with timestamp |
| 60 | + # timestamp_str = timestamps[-1].strftime("%H:%M:%S") |
| 61 | + # ws.append([timestamp_str, x_accel_data[-1], y_angle_data[-1]]) |
| 62 | + |
| 63 | + # Clear and update plots |
| 64 | + ax1.clear() |
| 65 | + ax1.plot(timestamps, x_accel_data, label="X Acceleration", color="b") |
| 66 | + ax1.legend(loc="upper left") |
| 67 | + ax1.set_ylim([-20, 20]) # Adjust based on expected acceleration range in m/s² |
| 68 | + ax1.set_title("Real-time X Acceleration Data") |
| 69 | + ax1.set_xlabel("Time") |
| 70 | + ax1.set_ylabel("Acceleration (m/s²)") |
| 71 | + ax1.grid(True) |
| 72 | + |
| 73 | + ax2.clear() |
| 74 | + ax2.plot(timestamps, y_angle_data, label="Y Angle", color="g") |
| 75 | + ax2.legend(loc="upper left") |
| 76 | + ax2.set_ylim([-180, 180]) |
| 77 | + ax2.set_title("Real-time Y Angle Data") |
| 78 | + ax2.set_xlabel("Time") |
| 79 | + ax2.set_ylabel("Angle (degrees)") |
| 80 | + ax2.grid(True) |
| 81 | + |
| 82 | + # Update text boxes with latest values |
| 83 | + text_box.set_text(f"X Acceleration: {x_accel_data[-1]:.2f} m/s²") |
| 84 | + text_box2.set_text(f"Y Angle: {y_angle_data[-1]:.2f}°") |
| 85 | + |
| 86 | + # Save the workbook periodically (every 100 updates) |
| 87 | + # if frame % 100 == 0: |
| 88 | + # wb.save("sensor_data.xlsx") |
| 89 | + |
| 90 | + # plt.draw() |
| 91 | + |
| 92 | + # print("update", datetime.now()) |
| 93 | + f.write(fig) |
| 94 | + |
| 95 | + except ValueError: |
| 96 | + pass # Ignore lines that are not properly formatted |
| 97 | + |
| 98 | + |
| 99 | +# Setup the plots |
| 100 | +# with plt.ion(): |
| 101 | +fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 8)) |
| 102 | +text_box = ax1.text( |
| 103 | + 0.05, |
| 104 | + 0.95, |
| 105 | + "", |
| 106 | + transform=ax1.transAxes, |
| 107 | + fontsize=12, |
| 108 | + verticalalignment="top", |
| 109 | + bbox=dict(boxstyle="round", facecolor="wheat", alpha=0.5), |
| 110 | +) |
| 111 | +text_box2 = ax2.text( |
| 112 | + 0.05, |
| 113 | + 0.95, |
| 114 | + "", |
| 115 | + transform=ax2.transAxes, |
| 116 | + fontsize=12, |
| 117 | + verticalalignment="top", |
| 118 | + bbox=dict(boxstyle="round", facecolor="wheat", alpha=0.5), |
| 119 | +) |
| 120 | + |
| 121 | +with ff.open( |
| 122 | + "sandbox/test.mp4|[f=mpegts]udp://127.0.0.1:1234?pkt_size=1316", |
| 123 | + "wv", |
| 124 | + rate_in=10, |
| 125 | + y=ff.FLAG, |
| 126 | + show_log=True, |
| 127 | + preset="ultrafast", |
| 128 | + tune="zerolatency", |
| 129 | + vcodec="libx264", |
| 130 | + map= '0:v', |
| 131 | + f="tee", |
| 132 | +) as f: |
| 133 | + s = schedule.every(0.1) |
| 134 | + s.seconds.until(datetime.now() + timedelta(seconds=10)).do( |
| 135 | + update, f |
| 136 | + ) # minutes=1) |
| 137 | + |
| 138 | + while True: |
| 139 | + n = schedule.idle_seconds() |
| 140 | + if n is None: |
| 141 | + # no more jobs |
| 142 | + break |
| 143 | + elif n > 0: |
| 144 | + # sleep exactly the right amount of time |
| 145 | + time.sleep(n) |
| 146 | + schedule.run_pending() |
| 147 | + time.sleep(0.1) |
| 148 | + |
| 149 | + print("schedule complete") |
| 150 | + |
| 151 | +# # Animate the plots |
| 152 | +# ani = FuncAnimation(fig, update, interval=100) # Update interval of 100ms |
| 153 | + |
| 154 | +# # Save the animation as a video file |
| 155 | +# writer = FFMpegWriter(fps=10, metadata=dict(artist='Me'), bitrate=1800) |
| 156 | +# ani.save("sensor_data.mp4", writer=writer) |
| 157 | + |
| 158 | +# plt.tight_layout() |
| 159 | +# plt.show() |
0 commit comments