sonar_socket2.py 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. import math
  2. import socket
  3. import struct
  4. import select
  5. import time
  6. from io import BytesIO
  7. import matplotlib.pyplot as plt
  8. import matplotlib.image as image
  9. import construct as c
  10. import numpy as np
  11. from PIL import Image
  12. from db_connecter import UseDatabase
  13. from memory_storage import MemoryStorage
  14. from hard_disk_storage import HardDiskStorage
  15. from PIL import Image
  16. import ctypes
  17. import os
  18. import logging
  19. from logging.handlers import TimedRotatingFileHandler
  20. SONAR_MODE = 'lvs34'
  21. redis_db = MemoryStorage()
  22. hard_disk_db = HardDiskStorage()
  23. data_heard = c.Struct(magic_number=c.Int32ul, length_mm=c.Int32ul, type=c.Int32ul)
  24. sonar_data = c.Struct(
  25. magic_number=c.Int32ul, # 固定不便,可能用于区分不同设备
  26. length_mm=c.Int32ul, # 数据包长度
  27. type=c.Int32ul, # 固定不变,可能用于识别声呐不同状态的数据
  28. sequence_count=c.Int32ul, # 每个包加一
  29. num_results=c.Int32ul, # 每包数据量
  30. pack_count=c.Int32ul, # 累加数据量,可能用于判断当前是第几个包
  31. length_data_mm=c.Int32ul, # 当前包数据量
  32. # pack_data=c.Array(c.this.length_data_mm, c.Byte) # 数据,怀疑是声呐数据
  33. pack_data=c.Bytes(c.this.length_data_mm)
  34. )
  35. attitude_data = c.Struct(
  36. unknown_1_1=c.Float16l,
  37. unknown_1_21=c.Int8ul,
  38. unknown_1_22=c.Int8ul,
  39. unknown_2=c.Float32l, # 俯仰角:-90°(俯)~ 90°(仰)
  40. unknown_3=c.Float32l, # 横滚角: -180(左倾)~ 180°(右倾)
  41. unknown_4=c.Int32ul,
  42. unknown_5=c.Float32l, # 浮点数
  43. unknown_6=c.Int32ul,
  44. unknown_7=c.Int32ul,
  45. unknown_8=c.Int32ul,
  46. unknown_9=c.Float32l, # 浮点数
  47. unknown_10=c.Float32l, # 浮点数
  48. unknown_11=c.Int32ul,
  49. unknown_12=c.Float32l, # 浮点数
  50. unknown_13=c.Int32ul,
  51. unknown_14=c.Int32ul,
  52. unknown_15=c.Int32ul,
  53. unknown_16=c.Int32ul,
  54. unknown_17=c.Int32ul,
  55. )
  56. log_handler = TimedRotatingFileHandler(filename='/home/sencott/sonar/log/socket2.log', when='midnight', interval=30, backupCount=5,
  57. encoding="utf8")
  58. # 配置日志记录器
  59. logging.basicConfig(level=logging.WARNING, format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
  60. handlers=[log_handler])
  61. # 获取日志记录器
  62. logger = logging.getLogger()
  63. def is_allowed_save():
  64. # 从redis获取是否存储标志,允许存储返回时间戳
  65. res = redis_db.get_value(['flag', 'timestamp', 'num', 'depth', 'temp', 'yaw', 'roll', 'pitch', 'servo_angle', 'img_type', 'water_leak1', 'water_leak2'])
  66. # {'flag': '0', 'timestamp': None, 'num': None, 'depth': '-2.350517511367798', 'temp': '7.96875', 'yaw': '310.625', 'roll': '-0.5', 'pitch': '178.75', 'servo_angle': '5', 'img_type': None}
  67. if 'flag' in res:
  68. if res['flag'] == '1':
  69. return res
  70. else:
  71. return False
  72. else:
  73. return False
  74. def get_uuid():
  75. sql = f"SELECT uuid FROM measurement_data ORDER BY id DESC LIMIT 1;"
  76. result = hard_disk_db.execute_sql(sql, None)
  77. if result:
  78. return result[0]['uuid']
  79. else:
  80. return None
  81. # 接收方
  82. def Receiver():
  83. group_ip = '239.254.2.16' # 组地址
  84. group_port = 50223 # 端口号
  85. # 创建IPv4/UDP套接字
  86. sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
  87. sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
  88. # 获取本地ip 先获取主机名,在通过主机名获取ip
  89. # local_ip = socket.gethostbyname(socket.gethostname()) #windows
  90. local_ip = '0.0.0.0' # ubuntu
  91. # local_ip = '192.168.1.188' # ubuntu
  92. # 绑定端口
  93. sock.bind((local_ip, group_port))
  94. mreq = struct.pack("=4sl", socket.inet_aton(group_ip), socket.INADDR_ANY)
  95. while True:
  96. try:
  97. # 加入组播组
  98. # 使用默认的IPV4组播接口
  99. sock.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mreq)
  100. break
  101. except Exception as e:
  102. print(e)
  103. time.sleep(1)
  104. sequence_count = None # 期望的序列号,用于检测是否丢失或乱序
  105. sonar_data_list = None
  106. count = 0
  107. save_img = 0
  108. path = '/data/bin_data/'
  109. sonar_temp = -10
  110. dll = ctypes.CDLL("/home/sencott/sonar/sonar/build/libImageDraw.so")
  111. while True:
  112. data, addr = sock.recvfrom(65536) # 接受数值大一点,防止被撑爆
  113. # print('images', len(data))
  114. if count < 100:
  115. count = count + 1
  116. if len(data) == 96:
  117. save_img = save_img + 1
  118. else:
  119. if save_img > 1:
  120. redis_db.set_value({'sonar_status': 'open'})
  121. else:
  122. cur_sonar_status = redis_db.get_value(['sonar_status'])['sonar_status']
  123. if cur_sonar_status == 'open':
  124. logger.warning('data error , sonar close')
  125. redis_db.set_value({'sonar_status': 'close'})
  126. save_img = 0
  127. count = 0
  128. res = data_heard.parse(data)
  129. if res.magic_number == 2308 and res.type == 393284:
  130. res = sonar_data.parse(data)
  131. if res.pack_count == 0:
  132. sonar_data_list = res.pack_data
  133. sequence_count = res.sequence_count
  134. elif sequence_count == res.sequence_count:
  135. sonar_data_list = sonar_data_list + res.pack_data
  136. if sonar_data_list != None:
  137. debug = False
  138. if debug == True:
  139. # 显示及存储,调试使用
  140. if len(sonar_data_list) == res.num_results:
  141. if SONAR_MODE == 'lvs34':
  142. img = sonar_data_list[3645:] # lvs34
  143. elif SONAR_MODE == 'lvs62':
  144. img = sonar_data_list[1853:] # lvs62
  145. plt.clf() # 清除上一幅图像
  146. byte_stream = BytesIO(img)
  147. img = image.imread(byte_stream, format='jpeg')
  148. # # 图片保存
  149. # roiImg = Image.open(byte_stream)
  150. # roiImg.save('save.jpeg')
  151. plt.imshow(img)
  152. plt.pause(0.05) # 暂停0.05秒 这一句是实现动态更新的
  153. plt.ioff() # 关闭画图的窗口
  154. # redis_db.set_value({'flag': '0'})
  155. # if not save_info:
  156. # continue
  157. if len(sonar_data_list) == res.num_results:
  158. # print("数据包大小(字节):", len(sonar_data_list))
  159. if SONAR_MODE == 'lvs34':
  160. angle_data = sonar_data_list[68:2112] # lvs34
  161. img = sonar_data_list[3645:] # lvs34
  162. elif SONAR_MODE == 'lvs62':
  163. angle_data = sonar_data_list[68:1088] # lvs62
  164. img = sonar_data_list[1853:] # lvs62
  165. # 解析俯仰和横滚数据
  166. res1 = attitude_data.parse(sonar_data_list[:68])
  167. pitch = res1.unknown_2 * 180 / math.pi
  168. roll = res1.unknown_3 * 180 / math.pi
  169. redis_db.set_value({"sonar_pitch":pitch, "sonar_roll":roll})
  170. # print(res1.unknown_5, res1.unknown_9, res1.unknown_10, res1.unknown_12)
  171. # print('save_image',img)
  172. image = angle_data + img
  173. # 预览图像
  174. dll.draw_image(ctypes.c_char_p('/data/tmp/'.encode()), ctypes.c_char_p('tmp'.encode()), image, len(image), 43)
  175. save_image_time = int(time.time())
  176. redis_db.set_value_permanent({'save_image_time': save_image_time})
  177. save_info = is_allowed_save()
  178. uuid = get_uuid()
  179. print('[success] 接收图片')
  180. if save_info: # 允许存储
  181. # 数据库存储
  182. sql = f"insert into sonar_data (uuid,image_name, depth, temp, yaw, roll, pitch, servo_angle, sonar_temp, sonar_pitch, sonar_roll, water_leak1,water_leak2) " \
  183. f"values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)"
  184. res_data = redis_db.get_value(["sonar_temp"])
  185. if res_data['sonar_temp']:
  186. sonar_temp = res_data['sonar_temp']
  187. else:
  188. sonar_temp = -10
  189. if not uuid:
  190. continue
  191. val = (uuid,
  192. save_info['timestamp'][0:10] + '_' + save_info['img_type'] + '_' + save_info['num'],
  193. save_info['depth'],
  194. save_info['temp'], save_info['yaw'], save_info['roll'], save_info['pitch'],
  195. save_info['servo_angle'], sonar_temp, pitch, roll,
  196. save_info['water_leak1'], save_info['water_leak2'])
  197. hard_disk_db.execute_sql(sql, val)
  198. # 二进制文件存储
  199. img_name = save_info['timestamp'][0:10] + '_' + save_info['img_type'] + '_' + save_info['num']
  200. f1 = open(path + str(img_name) + '.bin', 'wb')
  201. f1.write(sonar_data_list)
  202. f1.close()
  203. # 图像解析存储
  204. save_path_in = '/data/img_data/'
  205. save_path_p = ctypes.c_char_p(save_path_in.encode())
  206. filename_p = ctypes.c_char_p(img_name.encode())
  207. if save_info['img_type'] == "s":
  208. mat_ptr = dll.draw_image(save_path_p, filename_p, angle_data + img, len(angle_data + img), 43)
  209. else:
  210. mat_ptr = dll.draw_image(save_path_p, filename_p, angle_data + img, len(angle_data + img), 34)
  211. redis_db.set_value({'flag': '0'}) # 存储完一帧,置零,否则会出现
  212. # packet_seq_num, total_packets, packet_data = data.split(b":") # 从数据包中解析序号、总包数和数据
  213. # print(packet_seq_num, total_packets, packet_data)
  214. # img = BytesIO(data)
  215. if __name__ == '__main__':
  216. Receiver()
  217. # while True:
  218. # save_info = is_allowed_save()
  219. # if not save_info:
  220. # continue
  221. # print(save_info)
  222. # conn = UseDatabase()
  223. # sql = f"insert into sonar_data (image_name, angle, images, depth, temp, yaw, roll, pitch, servo_angle) " \
  224. # f"values (%s,%s,%s,%s,%s,%s,%s,%s,%s)"
  225. # val = (save_info['timestamp'] + '_' + save_info['num'], b'123', b'123', save_info['depth'],
  226. # save_info['temp'], save_info['yaw'], save_info['roll'], save_info['pitch'], save_info['servo_angle'])
  227. # conn.update(sql, val)
  228. # redis_db.set_value({'flag': '0'}) # 存储完一帧,置零