diff --git a/src/unitdev03/0328/test_transform.py b/src/unitdev03/0328/test_transform.py new file mode 100644 index 0000000..af72a2d --- /dev/null +++ b/src/unitdev03/0328/test_transform.py @@ -0,0 +1,331 @@ +import rclpy +from pymavlink import mavutil +from time import sleep +import time + +import socket +import struct + +# used at fdm_switch_example_two +import threading +import queue + +import json + +def mavlink_analyzer_simple(count = 500): + # rclpy.init() + # node = rclpy.create_node('mavlink_analyzer_simple') + + print('Inintializing connection') + + connection_string="udp:127.0.0.1:14550" + connection = mavutil.mavlink_connection(connection_string) + + print('Catch messages') + msg_count = {} + + start_time = time.time() + + for _ in range(count): + msg = connection.recv_msg() + # msg = connection.recv_match(blocking=True) + if msg: + msg_type = msg.get_type() + if msg_type in msg_count: + msg_count[msg_type] += 1 + else: + msg_count[msg_type] = 1 + + if msg.get_type() == 'SERVO_OUTPUT_RAW': + print(msg) + pass + + else: + print('No message yet, 1 second for data to fill') + sleep(1) + + print('Messages Type received:') + print(msg_count) + + end_time = time.time() + print('Time elapsed: ', end_time - start_time) + + print('Closing connection') + connection.close() + + +def fdm_parser_example(data=None): + if data is None: + data = bytes.fromhex('1a48e903b1340500e803e803e803e803000000000000000000000000000000000000000000000000') + # 1a48e903b1340500e803e803e803e803000000000000000000000000000000000000000000000000 + + + parse_format = 'HHI16H' + + if len(data) != struct.calcsize(parse_format): + print("got packet of len %u, expected %u" % (len(data), struct.calcsize(parse_format))) + exit(1) + + decoded = struct.unpack(parse_format,data) + + magic = decoded[0] + frame_rate_hz = decoded[1] + frame_count = decoded[2] + pwm = decoded[3:] + + + print("magic: %u, frame_rate_hz: %u, frame_count: %u, pwm: %s" % (magic, frame_rate_hz, frame_count, pwm)) + +def fdm_switch_example_one(): + + ''' + 這個範例在 SITL 與 Gazebo 之間 做一個簡單的UDP轉發器 + 沒有轉換數據格式 + ''' + # make a link get fdm from SITL, as a server + sock_s2g = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock_s2g.bind(('', 9002)) + sock_s2g.settimeout(0.1) + + # set a target link pass JSON to Gazebo, as a client + sock_g2s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + server_address = ('127.0.0.1', 19002) + + packet_count = 0 + start_time = time.time() + + while True: + try: + # 接到SITL的數據 並轉發給Gazebo + data_s2g, addr_s2g = sock_s2g.recvfrom(1024) + sock_g2s.sendto(data_s2g, server_address) + # 得到Gazebo的回應 並轉發給SITL + data_g2s, addr_g2s = sock_g2s.recvfrom(1024) + sock_s2g.sendto(data_g2s, addr_s2g) + + # 解析並保存接收到的數據到 JSON 檔案 (SITL -> Gazebo) + try: + # 解析從 SITL 到 Gazebo 的數據 + decoded = struct.unpack('HHI16H', data_s2g) + s2g_json = { + "magic": decoded[0], + "frame_rate_hz": decoded[1], + "frame_count": decoded[2], + "pwm": list(decoded[3:]) + } + + # 解析從 Gazebo 到 SITL 的數據 + # 注意:假設從 Gazebo 返回的數據是字串形式的 JSON + try: + g2s_data_str = data_g2s.decode('utf-8') + # 保存原始數據,適合後續分析 + with open('gazebo_response_raw.txt', 'a') as f: + f.write(g2s_data_str + '\n') + except: + # 如果不是 UTF-8 格式,可能是二進制數據 + g2s_data_str = str(data_g2s) + + # 合併數據到一個 JSON 對象 + combined_data = { + "sitl_to_gazebo": s2g_json, + "gazebo_to_sitl": g2s_data_str, + "timestamp": time.time() + } + + # 寫入 JSON 檔案 + with open('fdm_one_data.json', 'w') as f: + json.dump(combined_data, f, indent=2) + + except Exception as e: + print(f"JSON 處理錯誤: {e}") + + packet_count += 1 + except socket.timeout: + print(f'no value') + #print(f'address:{addr_s2g}') + #pass + + current_time = time.time() + elapsed_time = current_time - start_time + + if elapsed_time >= 1.0: + #print(f"Packets received in the last second: {packet_count}") + print(f'JSON Pack:{data_g2s}') + packet_count = 0 + start_time = current_time + fdm_parser_example(data_s2g) + + +def fdm_switch_example_two(): + ''' + 這個範例在 SITL 與 Gazebo 之間 做一個簡單的UDP轉發器 + 有轉換數據格式 + + time_usec + servo1_raw + servo16_raw + ''' + # read info from SITL via MAVLink + connection_string="udp:127.0.0.1:14550" # uart mavlink # MATLAB + connection = mavutil.mavlink_connection(connection_string) + + # set a target link pass JSON to Gazebo, as a client + sock_g2s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + server_address = ('127.0.0.1', 19002) + + data_queue = queue.Queue() + servo_out = [0] * 16 + data_queue.put(servo_out) + + def send_data_from_queue(sock, server_address, q, frame_rate_fdm=600, frame_count_fdm=1): + interval = 1.0 / frame_rate_fdm + while True: + start_time = time.time() + try: + data = q.get(timeout=0.1) + if data is None: + break + last_data = data + except queue.Empty: + data = last_data + data = struct.pack('HHI16H', 0x481a, frame_rate_fdm, frame_count_fdm, *servo_out) + sock.sendto(data, server_address) + + # 新增:寫入 JSON 檔案 + data_json = { + "magic": 0x481a, + "frame_rate_hz": frame_rate_fdm, + "frame_count": frame_count_fdm, + "pwm": list(servo_out) + } + with open('fdm_data.json', 'w') as f: + json.dump(data_json, f) + + frame_count_fdm += 1 + fdm_parser_example(data) # debug + + elapsed_time = time.time() - start_time + sleep_time = interval - elapsed_time + if sleep_time > 0: + sleep(sleep_time) + + Running = True + thread = threading.Thread(target=send_data_from_queue, args=(sock_g2s, server_address, data_queue)) + thread.start() + + while Running: + msgb1 = None + msg = connection.recv_msg() + while msg : + if msg.get_type() == 'SERVO_OUTPUT_RAW': + msgb1 = msg + # break # 這裡不需要break,因為我要最後一個 servo_output_raw 的值 + msg = connection.recv_msg() + + if msgb1: + for i in range(16): + servo_out[i] = getattr(msgb1, f'servo{i+1}_raw') + data_queue.put(servo_out) + msgb1 = None + # Running = False # debug + else: + # print('No message yet, 10 ms for data to fill') + sleep(0.01) + + # Example of putting data into the queue + # data_queue.put(data) + # To stop the thread, you can put None into the queue + # data_queue.put(None) + + +def fdm_switch_example_one_with_remote_forwarding(): + ''' + 這個範例在 SITL 與 Gazebo 之間 做一個簡單的UDP轉發器 + 並且將JSON數據轉發到指定的遠端IP + ''' + # make a link get fdm from SITL, as a server + sock_s2g = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + sock_s2g.bind(('', 9002)) + sock_s2g.settimeout(0.1) + + # set a target link pass JSON to Gazebo, as a client + sock_g2s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + server_address = ('127.0.0.1', 19002) + + # 建立與遠端IP的socket連接 + remote_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) + remote_address = ('140.120.31.130', 9003) # 遠端IP與埠號,您可以根據需要更改埠號 + print(f'Setting up forwarding to remote address: {remote_address}') + + packet_count = 0 + start_time = time.time() + + while True: + try: + # 接到SITL的數據 並轉發給Gazebo + data_s2g, addr_s2g = sock_s2g.recvfrom(1024) + sock_g2s.sendto(data_s2g, server_address) + + # 得到Gazebo的回應 並轉發給SITL + data_g2s, addr_g2s = sock_g2s.recvfrom(1024) + sock_s2g.sendto(data_g2s, addr_s2g) + + # 解析並保存接收到的數據到 JSON 檔案 (SITL -> Gazebo) + try: + # 解析從 SITL 到 Gazebo 的數據 + decoded = struct.unpack('HHI16H', data_s2g) + s2g_json = { + "magic": decoded[0], + "frame_rate_hz": decoded[1], + "frame_count": decoded[2], + "pwm": list(decoded[3:]) + } + + # 解析從 Gazebo 到 SITL 的數據 + try: + g2s_data_str = data_g2s.decode('utf-8') + # 保存原始數據,適合後續分析 + with open('gazebo_response_raw.txt', 'a') as f: + f.write(g2s_data_str + '\n') + except: + # 如果不是 UTF-8 格式,可能是二進制數據 + g2s_data_str = str(data_g2s) + + # 合併數據到一個 JSON 對象 + combined_data = { + "sitl_to_gazebo": s2g_json, + "gazebo_to_sitl": g2s_data_str, + "timestamp": time.time() + } + + # 寫入 JSON 檔案 + with open('fdm_one_data.json', 'w') as f: + json.dump(combined_data, f, indent=2) + + # 將JSON數據轉發到遠端IP + remote_socket.sendto(json.dumps(combined_data).encode(), remote_address) + + except Exception as e: + print(f"JSON 處理錯誤: {e}") + + packet_count += 1 + except socket.timeout: + print(f'no value') + #pass + + current_time = time.time() + elapsed_time = current_time - start_time + + if elapsed_time >= 1.0: + print(f'JSON Pack:{data_g2s}') + print(f'Forwarded data to remote IP: 140.120.31.130') + packet_count = 0 + start_time = current_time + fdm_parser_example(data_s2g) + +print('Start') +#fdm_switch_example_two() +#mavlink_analyzer_simple() +#fdm_switch_example_one() +fdm_switch_example_one_with_remote_forwarding() +#fdm_parser_example() \ No newline at end of file