Files
AirTrapMine/src/unitdev03/0519/test_transform.py
T

663 lines
25 KiB
Python

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(('', 9012))
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', 19012)
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', 19012)
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(('', 9012))
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', 19012)
# 建立與遠端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)
def fdm_switch_multiple(num_systems=3):
'''
Create multiple UDP forwarders between SITL and Gazebo using threading
Each forwarder uses its own set of ports following the pattern:
- SITL ports: 9002, 9012, 9022, ...
- Gazebo ports: 19002, 19012, 19022, ...
Parameters:
num_systems (int): Number of forwarding pairs to create
'''
# Flag to control thread execution
running = True
def forwarder_thread(system_id):
sitl_port = 9002 + (system_id * 10)
gazebo_port = 19002 + (system_id * 10)
# Create SITL socket (server)
sitl_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sitl_socket.bind(('', sitl_port))
sitl_socket.settimeout(0.1)
# Create Gazebo socket (client)
gazebo_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
gazebo_socket.settimeout(0.1)
gazebo_address = ('127.0.0.1', gazebo_port)
print(f"System {system_id}: Forwarding {sitl_port} → {gazebo_port}")
packet_count = 0
start_time = time.time()
last_data_s2g = None
try:
while running:
try:
# Receive from SITL and forward to Gazebo
data_s2g, addr_s2g = sitl_socket.recvfrom(1024)
last_data_s2g = data_s2g
gazebo_socket.sendto(data_s2g, gazebo_address)
try:
# Get response from Gazebo and send back to SITL
data_g2s, addr_g2s = gazebo_socket.recvfrom(1024)
sitl_socket.sendto(data_g2s, addr_s2g)
# Process and store data
try:
# Parse SITL to Gazebo data
decoded = struct.unpack('HHI16H', data_s2g)
s2g_json = {
"magic": decoded[0],
"frame_rate_hz": decoded[1],
"frame_count": decoded[2],
"pwm": list(decoded[3:])
}
# Try to parse Gazebo to SITL data
try:
g2s_data_str = data_g2s.decode('utf-8')
if packet_count % 50 == 0:
with open(f'gazebo_response_raw_{system_id}.txt', 'a') as f:
f.write(g2s_data_str + '\n')
except:
g2s_data_str = str(data_g2s)
# Combine data
combined_data = {
"sitl_to_gazebo": s2g_json,
"gazebo_to_sitl": g2s_data_str,
"timestamp": time.time(),
"system_id": system_id,
"sitl_port": sitl_port,
"gazebo_port": gazebo_port
}
# Save to JSON file (once per second)
current_time = time.time()
elapsed_time = current_time - start_time
if elapsed_time >= 1.0:
with open(f'fdm_data_system_{system_id}.json', 'w') as f:
json.dump(combined_data, f, indent=2)
except Exception as e:
print(f"System {system_id} - JSON processing error: {e}")
packet_count += 1
except socket.timeout:
# No response from Gazebo, continue
pass
except socket.timeout:
# No data from SITL, continue
pass
# Print stats periodically
current_time = time.time()
elapsed_time = current_time - start_time
if elapsed_time >= 1.0:
# print(f"System {system_id} - Packets: {packet_count} in the last second")
if packet_count > 0 and last_data_s2g:
print(f'System {system_id} - JSON Pack: {data_g2s}')
fdm_parser_example(last_data_s2g)
packet_count = 0
start_time = current_time
except Exception as e:
print(f"System {system_id} - Error in forwarder thread: {e}")
finally:
# Clean up resources
sitl_socket.close()
gazebo_socket.close()
print(f"System {system_id} - Forwarder thread terminated")
# Create and start threads for each system
threads = []
for i in range(num_systems):
thread = threading.Thread(target=forwarder_thread, args=(i,))
thread.daemon = True
threads.append(thread)
thread.start()
# Keep the main thread running
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("\nShutting down all forwarders...")
running = False
time.sleep(1)
print("Done.")
return
def fdm_switch_multiple_with_remote(num_systems=3, remote_ip='140.120.31.130'):
'''
Create multiple UDP forwarders between SITL and Gazebo using threading
Also forwards the combined data to a remote IP address
Each forwarder uses its own set of ports following the pattern:
- SITL ports: 9002, 9012, 9022, ...
- Gazebo ports: 19002, 19012, 19022, ...
- Remote ports: 9003, 9013, 9023, ... (for the remote forwarding)
Parameters:
num_systems (int): Number of forwarding pairs to create
remote_ip (str): IP address for remote forwarding
'''
# Flag to control thread execution
running = True
# Add shared counters for total packets
total_packets_sent = 0
total_packets_lock = threading.Lock() # For thread safety
def forwarder_thread(system_id):
nonlocal total_packets_sent
sitl_port = 9002 + (system_id * 10)
gazebo_port = 19002 + (system_id * 10)
remote_port = 9003 + (system_id * 10)
# Create SITL socket (server)
sitl_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sitl_socket.bind(('', sitl_port))
sitl_socket.settimeout(0.1)
# Create Gazebo socket (client)
gazebo_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
gazebo_socket.settimeout(0.1)
gazebo_address = ('127.0.0.1', gazebo_port)
# Create remote forwarding socket
remote_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
remote_address = (remote_ip, remote_port)
print(f"System {system_id}: SITL:{sitl_port} → Gazebo:{gazebo_port}, Remote:{remote_ip}:{remote_port}")
packet_count = 0
start_time = time.time()
last_data_s2g = None
forward_counter = 0 # 添加轉發計數器
system_packets_sent = 0 # Local counter for this system
try:
while running:
try:
# Receive from SITL and forward to Gazebo
data_s2g, addr_s2g = sitl_socket.recvfrom(1024)
last_data_s2g = data_s2g
gazebo_socket.sendto(data_s2g, gazebo_address)
try:
# Get response from Gazebo and send back to SITL
data_g2s, addr_g2s = gazebo_socket.recvfrom(1024)
sitl_socket.sendto(data_g2s, addr_s2g)
# Process and store data
try:
# Parse SITL to Gazebo data
decoded = struct.unpack('HHI16H', data_s2g)
s2g_json = {
"magic": decoded[0],
"frame_rate_hz": decoded[1],
"frame_count": decoded[2],
"pwm": list(decoded[3:])
}
# Try to parse Gazebo to SITL data
try:
g2s_data_str = data_g2s.decode('utf-8')
if packet_count % 50 == 0:
with open(f'gazebo_response_raw_{system_id}.txt', 'a') as f:
f.write(g2s_data_str + '\n')
except:
g2s_data_str = str(data_g2s)
# Combine data
combined_data = {
"sitl_to_gazebo": s2g_json,
"gazebo_to_sitl": g2s_data_str,
"timestamp": time.time(),
"system_id": system_id,
"sitl_port": sitl_port,
"gazebo_port": gazebo_port
}
'''
# 每n筆才轉發一次
forward_counter += 1
if forward_counter >= 18:
# Forward data to remote server
remote_socket.sendto(json.dumps(combined_data).encode(), remote_address)
#print(f"System {system_id} - Send data to remote (第{packet_count}個包)")
forward_counter = 0 # 重置計數器
'''
# 使用模運算代替計數器重置
forward_counter += 1
if packet_count % 1 == 0:
# Forward data to remote server
remote_socket.sendto(json.dumps(combined_data).encode(), remote_address)
system_packets_sent += 1
with total_packets_lock:
total_packets_sent += 1
# Debug用,看每秒傳了多少筆出去
#print(f"System {system_id} - Send data to remote (第{packet_count}個包)")
# Save to JSON file (once per second)
current_time = time.time()
elapsed_time = current_time - start_time
if elapsed_time >= 1.0:
with open(f'fdm_data_system_{system_id}.json', 'w') as f:
json.dump(combined_data, f, indent=2)
except Exception as e:
print(f"System {system_id} - JSON processing error: {e}")
packet_count += 1
except socket.timeout:
# No response from Gazebo, continue
pass
except socket.timeout:
# No data from SITL, continue
pass
# Print stats periodically
current_time = time.time()
elapsed_time = current_time - start_time
if elapsed_time >= 1.0:
print(f"System {system_id} - Packets: {packet_count} in the last second")
if packet_count > 0 and last_data_s2g:
fdm_parser_example(last_data_s2g)
packet_count = 0
start_time = current_time
except Exception as e:
print(f"System {system_id} - Error in forwarder thread: {e}")
finally:
# Clean up resources
sitl_socket.close()
gazebo_socket.close()
remote_socket.close()
print(f"System {system_id} - Forwarder thread terminated")
# Create statistics display thread
def stats_display_thread():
start_time = time.time()
while running:
time.sleep(5) # Display stats every 5 seconds
elapsed = time.time() - start_time
with total_packets_lock:
rate = total_packets_sent / elapsed if elapsed > 0 else 0
print(f"\n===== STATISTICS =====")
print(f"Total packets sent: {total_packets_sent}")
print(f"Average rate: {rate:.2f} packets/sec")
print(f"Running time: {elapsed:.1f} seconds")
print(f"======================\n")
# Create and start threads for each system
threads = []
for i in range(num_systems):
thread = threading.Thread(target=forwarder_thread, args=(i,))
thread.daemon = True
threads.append(thread)
thread.start()
# Start stats display thread
stats_thread = threading.Thread(target=stats_display_thread)
stats_thread.daemon = True
stats_thread.start()
# Keep the main thread running
try:
while True:
time.sleep(1)
except KeyboardInterrupt:
print("\nShutting down all forwarders...")
running = False
time.sleep(1)
print(f"Final total packets sent: {total_packets_sent}")
print("Done.")
return
print('Start')
#fdm_switch_example_two()
#mavlink_analyzer_simple()
#fdm_switch_example_one()
#fdm_switch_example_one_with_remote_forwarding()
#fdm_switch_multiple(1) # Create 3 forwarding pairs
fdm_switch_multiple_with_remote(3) # Create 1 forwarding pair with remote forwarding
#fdm_parser_example()