From fdfe1b1d8582b14e45f9460e0dc64248cb442c6e Mon Sep 17 00:00:00 2001 From: RangeOfGlitching Date: Mon, 17 Apr 2023 15:17:05 +0800 Subject: [PATCH] organize files --- .../RTL_test/MQTT_measure_rtl/allinone.bash | 0 .../MQTT_measure_rtl/delayClientA_PUB.py | 0 .../MQTT_measure_rtl/delayClientA_SUB.py | 8 +- .../RTL_test/MQTT_measure_rtl/delayClientB.py | 10 +- .../delayData/measureDelay.py | 0 .../RTL_test/MQTT_measure_rtl/ex | 0 .../MQTT_measure_rtl/proto/duration_pb2.py | 0 .../proto/flight_information.proto | 0 .../proto/flight_information_pb2.py | 0 .../proto/flyformatioln.proto | 0 .../proto/flyformatioln_pb2.py | 0 .../MQTT_measure_rtl/utils/__init__.py | 0 .../MQTT_measure_rtl/utils/basicMqtt.py | 0 .../utils/mqttConfig_delayA_PUB.yml | 0 .../utils/mqttConfig_delayA_SUB.yml | 0 .../utils/mqttConfig_delayB_SUB.yml | 0 .../utils/protoJson_delayClientA_PUB.py | 0 .../utils/protoJson_delayClientA_SUB.py | 0 .../utils/protoJson_delayClientB_SUB.py | 0 .../MQTT_measure_rtl/utils/readConfig.py | 0 .../uavlink_measrue_rtl/delayClientA_PUB.py | 2 +- .../uavlink_measrue_rtl/delayClientA_SUB.py | 0 .../uavlink_measrue_rtl/delayClientB.py | 0 .../delayData/measureDelay.py | 0 .../uavlink_measrue_rtl/proto/duration_pb2.py | 0 .../proto/flight_information.proto | 0 .../proto/flight_information_pb2.py | 0 .../proto/flyformatioln.proto | 0 .../proto/flyformatioln_pb2.py | 0 .../uavlink_measrue_rtl/utils/__init__.py | 0 .../uavlink_measrue_rtl/utils/basicMqtt.py | 0 .../utils/proto_delayClientA_PUB.py | 0 .../utils/proto_delayClientA_SUB.py | 0 .../utils/proto_delayClientB_SUB.py | 2 +- .../uavlink_measrue_rtl/utils/readConfig.py | 0 .../utils/uavlinkConfig_PUB.yml | 2 +- .../utils/uavlinkConfig_SUB.yml | 11 ++ .../datalose_test/MQTT_measure_datalose/ex | 3 + .../loseData/test1/results.csv | 11 ++ .../loseData/test5/results.csv | 11 ++ .../MQTT_measure_datalose/lose_ClientA_PUB.py | 107 ++++++++++++ .../MQTT_measure_datalose/lose_ClientB_SUB.py | 114 +++++++++++++ .../MQTT_measure_datalose/measureLose.py | 85 ++++++++++ .../proto/duration_pb2.py | 78 +++++++++ .../proto/flight_information.proto | 14 ++ .../proto/flight_information_pb2.py | 27 ++++ .../proto/flyformatioln.proto | 17 ++ .../proto/flyformatioln_pb2.py | 27 ++++ .../MQTT_measure_datalose/utils/__init__.py | 6 + .../MQTT_measure_datalose/utils/basicMqtt.py | 17 ++ .../utils/mqttConfig_delayA_PUB.yml | 15 ++ .../utils/mqttConfig_delayA_SUB.yml | 12 ++ .../utils/mqttConfig_delayB_SUB.yml | 13 ++ .../utils/protoJson_delayClientA_PUB.py | 77 +++++++++ .../utils/protoJson_delayClientA_SUB.py | 36 +++++ .../utils/protoJson_delayClientB_SUB.py | 53 ++++++ .../MQTT_measure_datalose/utils/readConfig.py | 109 +++++++++++++ .../loseData/test1/results.csv | 4 + .../loseData/test5/results.csv | 11 ++ .../lose_ClientA_PUB.py | 82 ++++++++++ .../uavlink_measrue_datalose/lose_ClientB.py | 69 ++++++++ .../uavlink_measrue_datalose/measureLose.py | 85 ++++++++++ .../proto/duration_pb2.py | 78 +++++++++ .../proto/flight_information.proto | 0 .../proto/flight_information_pb2.py | 0 .../proto/flyformatioln.proto | 17 ++ .../proto/flyformatioln_pb2.py | 27 ++++ .../utils/__init__.py | 0 .../utils/basicMqtt.py | 17 ++ .../utils/proto_delayClientA_PUB.py | 28 ++++ .../utils/proto_delayClientA_SUB.py | 25 +++ .../utils/proto_delayClientB_SUB.py | 47 ++++++ .../utils/readConfig.py | 152 ++++++++++++++++++ .../utils/uavlinkConfig_PUB.yml | 12 ++ .../utils/uavlinkConfig_SUB.yml | 2 +- .../protomsg/Data/sizeData | 0 Stream/experiment/protomsg/Data/timeData | 1 + .../JsonProtosize/duration_info_message | 0 .../JsonProtosize/duration_info_message.bin | 0 .../JsonProtosize/flight_info_message | 0 .../JsonProtosize/flight_info_message.bin | 0 .../protomsg/JsonProtosize/fly_format_message | 0 .../JsonProtosize/fly_format_message.bin | Bin .../JsonProtosize/flymode_info_message | 0 .../JsonProtosize/flymode_info_message.bin | 0 .../protomsg/JsonProtosize/imu_info_message | 0 .../JsonProtosize/imu_info_message.bin | Bin .../protomsg/JsonProtosize/odom_info_message | 0 .../JsonProtosize/odom_info_message.bin | Bin .../JsonProtosize/timestamp_info_message | 0 .../JsonProtosize/timestamp_info_message.bin | 0 .../protomsg/proto/duration.proto | 0 .../protomsg/proto/duration_pb2.py | 0 .../protomsg/proto/flight_information.proto | 14 ++ .../protomsg/proto/flight_information_pb2.py | 130 +++++++++++++++ .../protomsg/proto/flyformatioln.proto | 0 .../protomsg/proto/flyformatioln_pb2.py | 0 .../protomsg/proto/flymode.proto | 0 .../protomsg/proto/flymode_pb2.py | 0 .../protomsg/proto/imu.proto | 0 .../protomsg/proto/imu_pb2.py | 0 .../protomsg/proto/odom.proto | 0 .../protomsg/proto/odom_pb2.py | 0 .../protomsg/proto/timestamp.proto | 0 .../protomsg/proto/timestamp_pb2.py | 0 .../protomsg/protoMsg.py | 0 .../protomsg/size_test.py | 0 .../protomsg/timeit_test.py | 0 .../internet/internet_mqtt_pub_ros.py | 0 .../internet/internet_mqtt_sub_ros.py | 0 .../local_mqtt_pub_data_to_ros.py | 0 .../local_mqtt_sub_data_from_ros.py | 0 Stream/uav_proto_msg/flight_information.bin | 2 - Stream/uav_proto_msg/flight_information.json | 6 - Stream/uav_proto_msg/fly_formation.bin | Bin 7 -> 0 bytes Stream/uav_proto_msg/fly_formation.json | 2 - Stream/uav_proto_msg/protomsg/Data/timeData | 1 - .../protomsg/performancePlot/size.png | Bin 246320 -> 0 bytes .../protomsg/performancePlot/time.png | Bin 18089 -> 0 bytes 119 files changed, 1655 insertions(+), 24 deletions(-) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/allinone.bash (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/delayClientA_PUB.py (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/delayClientA_SUB.py (98%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/delayClientB.py (98%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/delayData/measureDelay.py (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/ex (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/proto/duration_pb2.py (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/proto/flight_information.proto (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/proto/flight_information_pb2.py (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/proto/flyformatioln.proto (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/proto/flyformatioln_pb2.py (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/utils/__init__.py (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/utils/basicMqtt.py (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayA_PUB.yml (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayA_SUB.yml (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayB_SUB.yml (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientA_PUB.py (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientA_SUB.py (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientB_SUB.py (100%) rename Stream/{ => experiment}/RTL_test/MQTT_measure_rtl/utils/readConfig.py (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/delayClientA_PUB.py (97%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/delayClientA_SUB.py (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/delayClientB.py (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/delayData/measureDelay.py (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/proto/duration_pb2.py (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/proto/flight_information.proto (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/proto/flight_information_pb2.py (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/proto/flyformatioln.proto (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/proto/flyformatioln_pb2.py (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/utils/__init__.py (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/utils/basicMqtt.py (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientA_PUB.py (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientA_SUB.py (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientB_SUB.py (92%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/utils/readConfig.py (100%) rename Stream/{ => experiment}/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_PUB.yml (90%) create mode 100644 Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_SUB.yml create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/ex create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/loseData/test1/results.csv create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/loseData/test5/results.csv create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/lose_ClientA_PUB.py create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/lose_ClientB_SUB.py create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/measureLose.py create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/proto/duration_pb2.py create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flight_information.proto create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flight_information_pb2.py create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flyformatioln.proto create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flyformatioln_pb2.py create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/utils/__init__.py create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/utils/basicMqtt.py create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/utils/mqttConfig_delayA_PUB.yml create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/utils/mqttConfig_delayA_SUB.yml create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/utils/mqttConfig_delayB_SUB.yml create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/utils/protoJson_delayClientA_PUB.py create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/utils/protoJson_delayClientA_SUB.py create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/utils/protoJson_delayClientB_SUB.py create mode 100644 Stream/experiment/datalose_test/MQTT_measure_datalose/utils/readConfig.py create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/loseData/test1/results.csv create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/loseData/test5/results.csv create mode 100755 Stream/experiment/datalose_test/uavlink_measrue_datalose/lose_ClientA_PUB.py create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/lose_ClientB.py create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/measureLose.py create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/duration_pb2.py rename Stream/{uav_proto_msg/protomsg => experiment/datalose_test/uavlink_measrue_datalose}/proto/flight_information.proto (100%) rename Stream/{uav_proto_msg/protomsg => experiment/datalose_test/uavlink_measrue_datalose}/proto/flight_information_pb2.py (100%) create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/flyformatioln.proto create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/flyformatioln_pb2.py create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/__init__.py create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/basicMqtt.py create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/proto_delayClientA_PUB.py create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/proto_delayClientA_SUB.py create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/proto_delayClientB_SUB.py create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/readConfig.py create mode 100644 Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/uavlinkConfig_PUB.yml rename Stream/{RTL_test/uavlink_measrue_rtl => experiment/datalose_test/uavlink_measrue_datalose}/utils/uavlinkConfig_SUB.yml (87%) rename Stream/{uav_proto_msg => experiment}/protomsg/Data/sizeData (100%) create mode 100644 Stream/experiment/protomsg/Data/timeData rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/duration_info_message (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/duration_info_message.bin (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/flight_info_message (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/flight_info_message.bin (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/fly_format_message (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/fly_format_message.bin (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/flymode_info_message (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/flymode_info_message.bin (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/imu_info_message (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/imu_info_message.bin (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/odom_info_message (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/odom_info_message.bin (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/timestamp_info_message (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/JsonProtosize/timestamp_info_message.bin (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/proto/duration.proto (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/proto/duration_pb2.py (100%) create mode 100644 Stream/experiment/protomsg/proto/flight_information.proto create mode 100644 Stream/experiment/protomsg/proto/flight_information_pb2.py rename Stream/{uav_proto_msg => experiment}/protomsg/proto/flyformatioln.proto (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/proto/flyformatioln_pb2.py (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/proto/flymode.proto (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/proto/flymode_pb2.py (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/proto/imu.proto (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/proto/imu_pb2.py (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/proto/odom.proto (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/proto/odom_pb2.py (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/proto/timestamp.proto (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/proto/timestamp_pb2.py (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/protoMsg.py (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/size_test.py (100%) rename Stream/{uav_proto_msg => experiment}/protomsg/timeit_test.py (100%) rename Stream/{ => old_version_mqtt}/internet/internet_mqtt_pub_ros.py (100%) rename Stream/{ => old_version_mqtt}/internet/internet_mqtt_sub_ros.py (100%) rename Stream/{ => old_version_mqtt}/localRosData/local_mqtt_pub_data_to_ros.py (100%) rename Stream/{ => old_version_mqtt}/localRosData/local_mqtt_sub_data_from_ros.py (100%) delete mode 100644 Stream/uav_proto_msg/flight_information.bin delete mode 100644 Stream/uav_proto_msg/flight_information.json delete mode 100644 Stream/uav_proto_msg/fly_formation.bin delete mode 100644 Stream/uav_proto_msg/fly_formation.json delete mode 100644 Stream/uav_proto_msg/protomsg/Data/timeData delete mode 100644 Stream/uav_proto_msg/protomsg/performancePlot/size.png delete mode 100644 Stream/uav_proto_msg/protomsg/performancePlot/time.png diff --git a/Stream/RTL_test/MQTT_measure_rtl/allinone.bash b/Stream/experiment/RTL_test/MQTT_measure_rtl/allinone.bash similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/allinone.bash rename to Stream/experiment/RTL_test/MQTT_measure_rtl/allinone.bash diff --git a/Stream/RTL_test/MQTT_measure_rtl/delayClientA_PUB.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/delayClientA_PUB.py similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/delayClientA_PUB.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/delayClientA_PUB.py diff --git a/Stream/RTL_test/MQTT_measure_rtl/delayClientA_SUB.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/delayClientA_SUB.py similarity index 98% rename from Stream/RTL_test/MQTT_measure_rtl/delayClientA_SUB.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/delayClientA_SUB.py index 80240ec..688d973 100644 --- a/Stream/RTL_test/MQTT_measure_rtl/delayClientA_SUB.py +++ b/Stream/experiment/RTL_test/MQTT_measure_rtl/delayClientA_SUB.py @@ -52,7 +52,7 @@ if __name__ == '__main__': if args.format != None: cfg.msg_format = args.format - init_dataFormat(cfg) + # set log log_format = "%(asctime)s - %(levelname)s - %(message)s" file_foramt = "%(message)s" @@ -70,12 +70,14 @@ if __name__ == '__main__': file_handler.setLevel(logging.INFO) logger = logging.getLogger("__delayA_SUB__") - logger.setLevel(logging.INFO) + logger.setLevel(logging.DEBUG) logger.addHandler(file_handler) logger.addHandler(stream_handler) logger.debug(cfg) - + + init_dataFormat(cfg) + # Mqtt client.on_connect = on_connect client.on_publish = on_publish diff --git a/Stream/RTL_test/MQTT_measure_rtl/delayClientB.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/delayClientB.py similarity index 98% rename from Stream/RTL_test/MQTT_measure_rtl/delayClientB.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/delayClientB.py index 38a7e39..9a7f396 100644 --- a/Stream/RTL_test/MQTT_measure_rtl/delayClientB.py +++ b/Stream/experiment/RTL_test/MQTT_measure_rtl/delayClientB.py @@ -70,10 +70,7 @@ if __name__ == '__main__': client.on_publish = on_publish client.on_disconnect = on_disconnect client.connect(host=cfg.host, port=cfg.port, keepalive=cfg.keepalive) - - # initialize - init_dataFormat(cfg) # set log log_format = "%(asctime)s - %(levelname)s - %(message)s" file_foramt = "%(message)s" @@ -91,12 +88,13 @@ if __name__ == '__main__': file_handler.setLevel(logging.INFO) logger = logging.getLogger("__SUB__") - logger.setLevel(logging.INFO) + logger.setLevel(logging.DEBUG) logger.addHandler(file_handler) logger.addHandler(stream_handler) - logger.debug(cfg) - + + # initialize + init_dataFormat(cfg) try: client.loop_forever() # rospy.spin() diff --git a/Stream/RTL_test/MQTT_measure_rtl/delayData/measureDelay.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/delayData/measureDelay.py similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/delayData/measureDelay.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/delayData/measureDelay.py diff --git a/Stream/RTL_test/MQTT_measure_rtl/ex b/Stream/experiment/RTL_test/MQTT_measure_rtl/ex similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/ex rename to Stream/experiment/RTL_test/MQTT_measure_rtl/ex diff --git a/Stream/RTL_test/MQTT_measure_rtl/proto/duration_pb2.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/proto/duration_pb2.py similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/proto/duration_pb2.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/proto/duration_pb2.py diff --git a/Stream/RTL_test/MQTT_measure_rtl/proto/flight_information.proto b/Stream/experiment/RTL_test/MQTT_measure_rtl/proto/flight_information.proto similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/proto/flight_information.proto rename to Stream/experiment/RTL_test/MQTT_measure_rtl/proto/flight_information.proto diff --git a/Stream/RTL_test/MQTT_measure_rtl/proto/flight_information_pb2.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/proto/flight_information_pb2.py similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/proto/flight_information_pb2.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/proto/flight_information_pb2.py diff --git a/Stream/RTL_test/MQTT_measure_rtl/proto/flyformatioln.proto b/Stream/experiment/RTL_test/MQTT_measure_rtl/proto/flyformatioln.proto similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/proto/flyformatioln.proto rename to Stream/experiment/RTL_test/MQTT_measure_rtl/proto/flyformatioln.proto diff --git a/Stream/RTL_test/MQTT_measure_rtl/proto/flyformatioln_pb2.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/proto/flyformatioln_pb2.py similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/proto/flyformatioln_pb2.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/proto/flyformatioln_pb2.py diff --git a/Stream/RTL_test/MQTT_measure_rtl/utils/__init__.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/utils/__init__.py similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/utils/__init__.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/utils/__init__.py diff --git a/Stream/RTL_test/MQTT_measure_rtl/utils/basicMqtt.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/utils/basicMqtt.py similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/utils/basicMqtt.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/utils/basicMqtt.py diff --git a/Stream/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayA_PUB.yml b/Stream/experiment/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayA_PUB.yml similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayA_PUB.yml rename to Stream/experiment/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayA_PUB.yml diff --git a/Stream/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayA_SUB.yml b/Stream/experiment/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayA_SUB.yml similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayA_SUB.yml rename to Stream/experiment/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayA_SUB.yml diff --git a/Stream/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayB_SUB.yml b/Stream/experiment/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayB_SUB.yml similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayB_SUB.yml rename to Stream/experiment/RTL_test/MQTT_measure_rtl/utils/mqttConfig_delayB_SUB.yml diff --git a/Stream/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientA_PUB.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientA_PUB.py similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientA_PUB.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientA_PUB.py diff --git a/Stream/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientA_SUB.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientA_SUB.py similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientA_SUB.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientA_SUB.py diff --git a/Stream/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientB_SUB.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientB_SUB.py similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientB_SUB.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/utils/protoJson_delayClientB_SUB.py diff --git a/Stream/RTL_test/MQTT_measure_rtl/utils/readConfig.py b/Stream/experiment/RTL_test/MQTT_measure_rtl/utils/readConfig.py similarity index 100% rename from Stream/RTL_test/MQTT_measure_rtl/utils/readConfig.py rename to Stream/experiment/RTL_test/MQTT_measure_rtl/utils/readConfig.py diff --git a/Stream/RTL_test/uavlink_measrue_rtl/delayClientA_PUB.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/delayClientA_PUB.py similarity index 97% rename from Stream/RTL_test/uavlink_measrue_rtl/delayClientA_PUB.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/delayClientA_PUB.py index 2838604..04dfca1 100755 --- a/Stream/RTL_test/uavlink_measrue_rtl/delayClientA_PUB.py +++ b/Stream/experiment/RTL_test/uavlink_measrue_rtl/delayClientA_PUB.py @@ -67,7 +67,7 @@ if __name__ == '__main__': # test json Proto_msg_from_ros.callBack_gps(gps) Proto_msg_from_ros.callBack_compass_hdg(hdg) - time.sleep(0.5) + time.sleep(1) hdg.data += 1 except KeyboardInterrupt as e: sel.write(b'\xf2' + b'......................' + b'\x0d\x2a') diff --git a/Stream/RTL_test/uavlink_measrue_rtl/delayClientA_SUB.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/delayClientA_SUB.py similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/delayClientA_SUB.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/delayClientA_SUB.py diff --git a/Stream/RTL_test/uavlink_measrue_rtl/delayClientB.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/delayClientB.py similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/delayClientB.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/delayClientB.py diff --git a/Stream/RTL_test/uavlink_measrue_rtl/delayData/measureDelay.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/delayData/measureDelay.py similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/delayData/measureDelay.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/delayData/measureDelay.py diff --git a/Stream/RTL_test/uavlink_measrue_rtl/proto/duration_pb2.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/proto/duration_pb2.py similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/proto/duration_pb2.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/proto/duration_pb2.py diff --git a/Stream/RTL_test/uavlink_measrue_rtl/proto/flight_information.proto b/Stream/experiment/RTL_test/uavlink_measrue_rtl/proto/flight_information.proto similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/proto/flight_information.proto rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/proto/flight_information.proto diff --git a/Stream/RTL_test/uavlink_measrue_rtl/proto/flight_information_pb2.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/proto/flight_information_pb2.py similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/proto/flight_information_pb2.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/proto/flight_information_pb2.py diff --git a/Stream/RTL_test/uavlink_measrue_rtl/proto/flyformatioln.proto b/Stream/experiment/RTL_test/uavlink_measrue_rtl/proto/flyformatioln.proto similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/proto/flyformatioln.proto rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/proto/flyformatioln.proto diff --git a/Stream/RTL_test/uavlink_measrue_rtl/proto/flyformatioln_pb2.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/proto/flyformatioln_pb2.py similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/proto/flyformatioln_pb2.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/proto/flyformatioln_pb2.py diff --git a/Stream/RTL_test/uavlink_measrue_rtl/utils/__init__.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/__init__.py similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/utils/__init__.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/__init__.py diff --git a/Stream/RTL_test/uavlink_measrue_rtl/utils/basicMqtt.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/basicMqtt.py similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/utils/basicMqtt.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/basicMqtt.py diff --git a/Stream/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientA_PUB.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientA_PUB.py similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientA_PUB.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientA_PUB.py diff --git a/Stream/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientA_SUB.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientA_SUB.py similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientA_SUB.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientA_SUB.py diff --git a/Stream/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientB_SUB.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientB_SUB.py similarity index 92% rename from Stream/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientB_SUB.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientB_SUB.py index 932a684..bc01695 100644 --- a/Stream/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientB_SUB.py +++ b/Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/proto_delayClientB_SUB.py @@ -22,7 +22,7 @@ class Proto_msg_to_ros: def on_message_Flight_Information(cls, msg, timeSub): proto = msg[1:-2] proto_msg = cls.flight_information_msg.FromString(proto) - # cls.sel.write(b'\xf2' + proto + b'\x0d\x0a') + cls.sel.write(b'\xf2' + proto + b'\x0d\x0a') timePub = time.perf_counter_ns() # readTenByte = cls.sel.read_until(size=5) timeDiff = timePub - timeSub diff --git a/Stream/RTL_test/uavlink_measrue_rtl/utils/readConfig.py b/Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/readConfig.py similarity index 100% rename from Stream/RTL_test/uavlink_measrue_rtl/utils/readConfig.py rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/readConfig.py diff --git a/Stream/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_PUB.yml b/Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_PUB.yml similarity index 90% rename from Stream/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_PUB.yml rename to Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_PUB.yml index e98b1dc..f7d5723 100644 --- a/Stream/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_PUB.yml +++ b/Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_PUB.yml @@ -2,7 +2,7 @@ UAVLINK: uavlink_msg_format: Proto uav_id: \x01\x01 baudrate: 250000 - ttyport: /dev/ttyUSB3 + ttyport: /dev/ttyUSB0 MQTT: "None" #ROS ROS: diff --git a/Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_SUB.yml b/Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_SUB.yml new file mode 100644 index 0000000..029e877 --- /dev/null +++ b/Stream/experiment/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_SUB.yml @@ -0,0 +1,11 @@ +UAVLINK: + uavlink_msg_format: Proto + uav_id: \x01\x01 + baudrate: 250000 + ttyport: /dev/ttyUSB0 +MQTT: "None" +ROS: + ROSClientNameSub: Drone550UAVLINKSub + Dron550_ROStopicName_Flight_Information: Flight_Information_reciver +LOG: + logFileName: ProtodelayA_SUB.log \ No newline at end of file diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/ex b/Stream/experiment/datalose_test/MQTT_measure_datalose/ex new file mode 100644 index 0000000..bcfdac3 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/ex @@ -0,0 +1,3 @@ +python delayClientA_PUB.py -q 0 -p 1884 -f Json + + diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/loseData/test1/results.csv b/Stream/experiment/datalose_test/MQTT_measure_datalose/loseData/test1/results.csv new file mode 100644 index 0000000..23254e8 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/loseData/test1/results.csv @@ -0,0 +1,11 @@ +frequency,packet_loss,percentage_loss +1hz,0,0.0 +2hz,0,0.0 +3hz,0,0.0 +4hz,0,0.0 +5hz,0,0.0 +6hz,0,0.0 +7hz,0,0.0 +8hz,0,0.0 +9hz,0,0.0 +10hz,0,0.0 diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/loseData/test5/results.csv b/Stream/experiment/datalose_test/MQTT_measure_datalose/loseData/test5/results.csv new file mode 100644 index 0000000..128e619 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/loseData/test5/results.csv @@ -0,0 +1,11 @@ +frequency,packet_loss,percentage_loss +1hz,0,0.0 +2hz,1,1.0 +3hz,6,6.0 +4hz,8,8.0 +5hz,17,17.0 +6hz,32,32.0 +7hz,48,48.0 +8hz,52,52.0 +9hz,52,52.0 +10hz,55,55.00000000000001 diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/lose_ClientA_PUB.py b/Stream/experiment/datalose_test/MQTT_measure_datalose/lose_ClientA_PUB.py new file mode 100644 index 0000000..d4eb633 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/lose_ClientA_PUB.py @@ -0,0 +1,107 @@ +#!/usr/bin/env python3 +#coding:utf-8 +import paho.mqtt.client as mqtt +import os +import sys +import time +import utils +import argparse +import proto.flyformatioln_pb2 as flyformatioln_pb2 +import logging +from utils.protoJson_delayClientA_PUB import Json_msg +from utils.protoJson_delayClientA_PUB import Proto_msg + + + +def init_dataFormat(cfg:utils.Read_delayA_PUB_Config): + global pubFun + if cfg.msg_format == "Proto": + Proto_msg.client = client + Proto_msg.qos = cfg.qos + Proto_msg.Delay_topicToMqtt_PUB = cfg.Delay_topicToMqtt_PUB + cfg.logFileName = "Proto" + cfg.logFileName + pubFun = Proto_msg.callBack_gps + elif cfg.msg_format == "Json": + Json_msg.client = client + Json_msg.qos = cfg.qos + Json_msg.Delay_topicToMqtt_PUB = cfg.Delay_topicToMqtt_PUB + cfg.logFileName = "Json" + cfg.logFileName + pubFun = Json_msg.callBack_gps + else: + logging.debug("msg_format not found") + + +def on_connect(self, userdata, flags, rc): + logger.debug("Connected with result code " + str(rc)) + +def on_publish(self, userdata, mid): + # logger.debug("pub success") + pass + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("-q", "--qos", type=int, help="qos") + parser.add_argument("-p", "--port", type=int, help="port") + parser.add_argument("-d", "--data_format", type=str, help="data_format") + parser.add_argument("-f", "--fre", type=str, help="format") + parser.add_argument("-t", "--delaytime", type=float, default="1.0", help="number of packet", required=True) + args = parser.parse_args() + # Read Config + FilePath = os.path.join(os.path.dirname(__file__),"utils","mqttConfig_delayA_PUB.yml") + cfg = utils.Read_delayA_PUB_Config(FilePath) + + if args.qos != None: + cfg.qos = args.qos + if args.port != None: + cfg.port = args.port + if args.data_format != None: + cfg.msg_format = args.data_format + # Mqtt + client = utils.MQTTClient(cfg.MQTTClientNamePub) + pubFun = None + + + init_dataFormat(cfg) + + # set log + log_format = "%(asctime)s - %(levelname)s - %(message)s" + file_format = "%(message)s" + file_formatter = logging.Formatter(file_format) + formatter = logging.Formatter(log_format) + + stream_handler = logging.StreamHandler() + stream_handler.setFormatter(formatter) + stream_handler.setLevel(logging.DEBUG) + + + file_handler = logging.FileHandler(cfg.logFileName, mode="w") + file_handler.setFormatter(file_formatter) + file_handler.setLevel(logging.INFO) + + logger = logging.getLogger("__PUB__") + logger.setLevel(logging.DEBUG) + logger.addHandler(file_handler) + logger.addHandler(stream_handler) + + logger.debug(cfg) + # Mqtt + client.on_connect = on_connect + client.on_publish = on_publish + + client.connect(host=cfg.host, port=cfg.port, keepalive=cfg.keepalive) + client.loop_start() + + for i in range(cfg.msgAmount): + try: + pubFun() + time.sleep(args.delaytime) + except KeyboardInterrupt as e: + client.disconnect() + logger.debug("Not elegeant of program") + sys.exit() + + client.disconnect() + logger.debug(cfg) + logger.debug("End of program") + sys.exit() \ No newline at end of file diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/lose_ClientB_SUB.py b/Stream/experiment/datalose_test/MQTT_measure_datalose/lose_ClientB_SUB.py new file mode 100644 index 0000000..6ac1cb8 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/lose_ClientB_SUB.py @@ -0,0 +1,114 @@ +#!/usr/bin/env python3 +#coding:utf-8 +import paho.mqtt.client as mqtt +import os +import sys +import argparse +import utils +import proto.flight_information_pb2 as flight_information_pb2 +import proto.flyformatioln_pb2 as flyformatioln_pb2 +import logging +from utils.protoJson_delayClientB_SUB import Json_msg +from utils.protoJson_delayClientB_SUB import Proto_msg + +def init_dataFormat(cfg:utils.Read_delayB_SUB_Config): + if cfg.msg_format == "Proto": + Proto_msg.qos = cfg.qos + Proto_msg.flight_information_msg = flight_information_pb2.flight_information_message() + Proto_msg.fly_formation_msg = flyformatioln_pb2.fly_formation_message() + Proto_msg.client = client + client.on_message = Proto_msg.on_message + cfg.logFileName = "Proto" + cfg.logFileName + + Proto_msg.Delay_topicToMqtt_PUB = cfg.Delay_topicToMqtt_PUB + elif cfg.msg_format == "Json": + client.on_message = Json_msg.on_message + Json_msg.qos = cfg.qos + Json_msg.client = client + Json_msg.Delay_topicToMqtt_PUB = cfg.Delay_topicToMqtt_PUB + cfg.logFileName = "Json" + cfg.logFileName + else: + logger.debug("msg_format not found") + + +def on_connect(self, userdata, flags, rc): + logger.debug("Connected with result code " + str(rc)) + client.subscribe(cfg.Delay_topicToMqtt_SUB, qos=cfg.qos) + +def on_disconnect(client, userdata, rc): + # logger.info("disconnecting reason " +str(rc)) + client.connected_flag=False + client.disconnect_flag=True + +def on_publish(self, userdata, mid): + pass + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("-q", "--qos", type=int, help="qos") + parser.add_argument("-p", "--port", type=int, help="port") + parser.add_argument("-d", "--data_format", type=str, help="format") + parser.add_argument("-f", "--frequency", type=str, default="1", help="transmission frequency", required=True) + + args = parser.parse_args() + + # Read Config + FilePath = os.path.join(os.path.dirname(__file__),"utils","mqttConfig_delayB_SUB.yml") + cfg = utils.Read_delayB_SUB_Config(FilePath) + + if args.qos != None: + cfg.qos = args.qos + if args.port != None: + cfg.port = args.port + if args.data_format != None: + cfg.msg_format = args.data_format + + + client = utils.MQTTClient(cfg.MQTTClientNameSub) + # Mqtt + client = utils.MQTTClient(cfg.MQTTClientNameSub) + client.on_connect = on_connect + client.on_publish = on_publish + client.on_disconnect = on_disconnect + client.connect(host=cfg.host, port=cfg.port, keepalive=cfg.keepalive) + + + # initialize + init_dataFormat(cfg) + # set log + log_format = "%(asctime)s - %(levelname)s - %(message)s" + file_foramt = "%(message)s" + + formatter = logging.Formatter(log_format) + file_formatter = logging.Formatter(file_foramt) + + stream_handler = logging.StreamHandler() + stream_handler.setFormatter(formatter) + stream_handler.setLevel(logging.DEBUG) + + + file_handler = logging.FileHandler(args.frequency +"hz.log", mode='w') + file_handler.setFormatter(file_formatter) + file_handler.setLevel(logging.INFO) + + logger = logging.getLogger("__SUB__") + logger.setLevel(logging.DEBUG) + logger.addHandler(file_handler) + logger.addHandler(stream_handler) + + logger.debug(cfg) + + try: + client.loop_forever() + # rospy.spin() + except KeyboardInterrupt as e: + client.loop_stop() + client.disconnect() + logger.debug("Not elegeant end of program") + sys.exit() + client.loop_stop() + client.disconnect() + logger.debug("End of program") + sys.exit() + diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/measureLose.py b/Stream/experiment/datalose_test/MQTT_measure_datalose/measureLose.py new file mode 100644 index 0000000..f665875 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/measureLose.py @@ -0,0 +1,85 @@ +import pandas as pd +import matplotlib.pyplot as plt +import argparse +import os +import fnmatch +import re + + +def check_number_of_lines(df, log_name): + if df.shape[0] != args.number: + print(f"Warning: Number of lines in the log file {log_name} is not correct") + return list(check_continuous_count(df, log_name)) + else: + return [] + + +def check_continuous_count(df, log_name): + duplicates = df[df["count"].duplicated()]["count"] + if not duplicates.empty: + print(f"Warning: Non-continuous count in the log file {log_name} at index {duplicates.index.tolist()}") + max_count = args.number + all_counts = set(range(1, max_count + 1)) + actual_counts = set(df["count"]) + missing = all_counts - actual_counts + if missing != set(): + print(f"Warning: missing msg in {log_name} at index {missing}") + return missing + else: + return 0 + + +def extract_number(filename): + return int(re.search(r'\d+', filename).group()) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-n", "--number", type=int, default="1000", help="number of packet", required=True) + parser.add_argument("-t", "--test", type=str, default="1", help="number of test", required=True) + args = parser.parse_args() + + log_files_path = os.listdir(f"loseData/test{args.test}") + log_files = [file_name for file_name in log_files_path if fnmatch.fnmatch(file_name, '*.log')] + log_files.sort(key=extract_number) + + frequence = [file_name.replace(".log", "") for file_name in log_files] + + dataframes = [] + missing_counts = [] + for log_file in log_files: + df = pd.read_csv(f"loseData/test{args.test}/{log_file}", delim_whitespace=True, header=None, names=["count", "time"]) + dataframes.append(df) + missing_counts.append(check_number_of_lines(df, log_file)) + + total_lengths = [len(sublist) for sublist in missing_counts] + print(total_lengths) + + plt.rcParams["figure.figsize"] = [13, 6] + plt.rcParams["figure.autolayout"] = True + + bar_plot = plt.bar(frequence, total_lengths, edgecolor='black') + + plt.title("Packet drop") + plt.xlabel("Frequency") + plt.ylabel("packet loss rate((%))") + + total_packets = args.number + for i, bar in enumerate(bar_plot): + loss_percentage = total_lengths[i] / total_packets * 100 + plt.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 0.1, + f"{loss_percentage:.2f}%", ha="center", va="bottom") + + + plt.savefig(f"loseData/test{args.test}/test{args.test}.png", dpi=300) + plt.show() + + # Create a DataFrame with frequency and packet loss data + results_df = pd.DataFrame({'frequency': frequence, 'packet_loss': total_lengths}) + + # Calculate percentage loss for each row + results_df['percentage_loss'] = results_df['packet_loss'] / total_packets * 100 + + # Save the results as a CSV file + results_df.to_csv(f"loseData/test{args.test}/results.csv", index=False) + \ No newline at end of file diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/duration_pb2.py b/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/duration_pb2.py new file mode 100644 index 0000000..1a30c51 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/duration_pb2.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: duration.proto + +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='duration.proto', + package='google.protobuf', + syntax='proto3', + serialized_options=b'\n\023com.google.protobufB\rDurationProtoP\001Z1google.golang.org/protobuf/types/known/durationpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes', + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n\x0e\x64uration.proto\x12\x0fgoogle.protobuf\"*\n\x08\x44uration\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x42\x83\x01\n\x13\x63om.google.protobufB\rDurationProtoP\x01Z1google.golang.org/protobuf/types/known/durationpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3' +) + + + + +_DURATION = _descriptor.Descriptor( + name='Duration', + full_name='google.protobuf.Duration', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='seconds', full_name='google.protobuf.Duration.seconds', index=0, + number=1, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='nanos', full_name='google.protobuf.Duration.nanos', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=35, + serialized_end=77, +) + +DESCRIPTOR.message_types_by_name['Duration'] = _DURATION +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +Duration = _reflection.GeneratedProtocolMessageType('Duration', (_message.Message,), { + 'DESCRIPTOR' : _DURATION, + '__module__' : 'duration_pb2' + # @@protoc_insertion_point(class_scope:google.protobuf.Duration) + }) +_sym_db.RegisterMessage(Duration) + + +DESCRIPTOR._options = None +# @@protoc_insertion_point(module_scope) diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flight_information.proto b/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flight_information.proto new file mode 100644 index 0000000..620a8c8 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flight_information.proto @@ -0,0 +1,14 @@ +syntax = 'proto3'; +package flight_information_proto; +// GPS + compass + +message GPS { + optional float LAT = 1; + optional float LON = 2; + optional float ALT = 3; +} + +message flight_information_message { + GPS gps = 1; + optional float heading = 2; +} \ No newline at end of file diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flight_information_pb2.py b/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flight_information_pb2.py new file mode 100644 index 0000000..d35aec8 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flight_information_pb2.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: flight_information.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x18\x66light_information.proto\x12\x18\x66light_information_proto\"S\n\x03GPS\x12\x10\n\x03LAT\x18\x01 \x01(\x02H\x00\x88\x01\x01\x12\x10\n\x03LON\x18\x02 \x01(\x02H\x01\x88\x01\x01\x12\x10\n\x03\x41LT\x18\x03 \x01(\x02H\x02\x88\x01\x01\x42\x06\n\x04_LATB\x06\n\x04_LONB\x06\n\x04_ALT\"j\n\x1a\x66light_information_message\x12*\n\x03gps\x18\x01 \x01(\x0b\x32\x1d.flight_information_proto.GPS\x12\x14\n\x07heading\x18\x02 \x01(\x02H\x00\x88\x01\x01\x42\n\n\x08_headingb\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flight_information_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _GPS._serialized_start=54 + _GPS._serialized_end=137 + _FLIGHT_INFORMATION_MESSAGE._serialized_start=139 + _FLIGHT_INFORMATION_MESSAGE._serialized_end=245 +# @@protoc_insertion_point(module_scope) diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flyformatioln.proto b/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flyformatioln.proto new file mode 100644 index 0000000..56a6d58 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flyformatioln.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package fly_formation_proto; +// leader only + +enum FLY_FORMATION{ + FLY_FORMATION_UNSPECIFIED = 0; + FLY_FORMATION_v = 1; + FLY_FORMATION_X = 2; + FLY_FORMATION_O = 3; + FLY_FORMATION_LINE = 4; + FLY_FORMATION_ROW = 5; + FLY_FORMATION_HEX = 6; + } + message fly_formation_message{ + optional float velocity = 1; + FLY_FORMATION fly_formation= 2; + } \ No newline at end of file diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flyformatioln_pb2.py b/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flyformatioln_pb2.py new file mode 100644 index 0000000..34014f4 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/proto/flyformatioln_pb2.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: flyformatioln.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13\x66lyformatioln.proto\x12\x13\x66ly_formation_proto\"v\n\x15\x66ly_formation_message\x12\x15\n\x08velocity\x18\x01 \x01(\x02H\x00\x88\x01\x01\x12\x39\n\rfly_formation\x18\x02 \x01(\x0e\x32\".fly_formation_proto.FLY_FORMATIONB\x0b\n\t_velocity*\xb3\x01\n\rFLY_FORMATION\x12\x1d\n\x19\x46LY_FORMATION_UNSPECIFIED\x10\x00\x12\x13\n\x0f\x46LY_FORMATION_v\x10\x01\x12\x13\n\x0f\x46LY_FORMATION_X\x10\x02\x12\x13\n\x0f\x46LY_FORMATION_O\x10\x03\x12\x16\n\x12\x46LY_FORMATION_LINE\x10\x04\x12\x15\n\x11\x46LY_FORMATION_ROW\x10\x05\x12\x15\n\x11\x46LY_FORMATION_HEX\x10\x06\x62\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flyformatioln_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _FLY_FORMATION._serialized_start=165 + _FLY_FORMATION._serialized_end=344 + _FLY_FORMATION_MESSAGE._serialized_start=44 + _FLY_FORMATION_MESSAGE._serialized_end=162 +# @@protoc_insertion_point(module_scope) diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/__init__.py b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/__init__.py new file mode 100644 index 0000000..259b419 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/__init__.py @@ -0,0 +1,6 @@ +from utils.readConfig import Read_delayA_PUB_Config +from utils.readConfig import Read_delayB_SUB_Config +from utils.readConfig import Read_delayA_SUB_Config +from utils.basicMqtt import MQTTClient + + diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/basicMqtt.py b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/basicMqtt.py new file mode 100644 index 0000000..572e84e --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/basicMqtt.py @@ -0,0 +1,17 @@ +import paho.mqtt.client as mqtt +import time +class MQTTClient(mqtt.Client): + + def __init__(self,cname,**kwargs): + super().__init__(cname,**kwargs) + self.last_pub_time=time.time() + self.topic_ack=[] + self.run_flag=True + self.subscribe_flag=False + self.bad_connection_flag=False + self.connected_flag=True + self.disconnect_flag=False + self.disconnect_time=0.0 + self.pub_msg_count=0 + self.devices=[] + diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/mqttConfig_delayA_PUB.yml b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/mqttConfig_delayA_PUB.yml new file mode 100644 index 0000000..38ff911 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/mqttConfig_delayA_PUB.yml @@ -0,0 +1,15 @@ +MQTT: + # msg_format: Proto + msg_format: Json + qos: 0 + MQTTClientNamePub: delayA_PUB + host: 192.168.50.117 + port: 1883 + keepalive: 60 + msgAmount: 100 + msgInterval: 0.01 + # Mqtt topic + Delay_topicToMqtt_PUB: delayA_PUB/delay + #ROS +LOG: + logFileName: delayA_PUB.log diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/mqttConfig_delayA_SUB.yml b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/mqttConfig_delayA_SUB.yml new file mode 100644 index 0000000..b6d1b20 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/mqttConfig_delayA_SUB.yml @@ -0,0 +1,12 @@ +MQTT: + # msg_format: Proto + msg_format: Json + qos: 0 + MQTTClientNameSub: delayA_SUB + host: 192.168.50.117 + port: 1883 + keepalive: 60 + # Mqtt topic + Respond_topicToMqtt_SUB: delayB/respond +LOG: + logFileName: delayA_SUB.log diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/mqttConfig_delayB_SUB.yml b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/mqttConfig_delayB_SUB.yml new file mode 100644 index 0000000..0336d3c --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/mqttConfig_delayB_SUB.yml @@ -0,0 +1,13 @@ +MQTT: + # msg_format: Proto + msg_format: Json + qos: 0 + MQTTClientNameSub: delayB_SUB + host: 192.168.50.117 + port: 1883 + keepalive: 60 + # Mqtt topic + Delay_topicToMqtt_SUB: delayA_PUB/delay + Delay_topicToMqtt_PUB: delayB/respond +LOG: + logFileName: delayB_SUB.log diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/protoJson_delayClientA_PUB.py b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/protoJson_delayClientA_PUB.py new file mode 100644 index 0000000..52a09f1 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/protoJson_delayClientA_PUB.py @@ -0,0 +1,77 @@ +import orjson +import time +import logging +import proto.flight_information_pb2 as flight_information_pb2 +logger = logging.getLogger("__PUB__") + +class Proto_msg: + #Protobuf + flight_information_msg = flight_information_pb2.flight_information_message() + flight_information_msg.gps.LAT = 100000000 + flight_information_msg.gps.LON = 200000000 + flight_information_msg.gps.ALT = 300000000 + timePub = 0 + #Mqtt + client = None + Delay_topicToMqtt_PUB = None + count = 1 + qos = None + + @classmethod + def callBack_gps(cls): + cls.flight_information_msg.heading = cls.count + flightInformationMsg = cls.flight_information_msg.SerializeToString() + cls.mqtt_Pub(message=flightInformationMsg, topics=cls.Delay_topicToMqtt_PUB) + + + + @classmethod + # publish a message + def mqtt_Pub(cls, message:bytes, topics:str, waitForAck:bool=False)->None: + cls.timePub = time.perf_counter_ns() + mid = cls.client.publish(topics, message, cls.qos)[1] + logger.info("{} {}".format(cls.count,cls.timePub)) + cls.count += 1 + # print(f"just published {message} to topic") + if waitForAck: + while mid not in cls.client.topic_ack: + # TODO: logging + print("wait for ack") + time.sleep(0.25)# You can download security extensions from the HiveMQ Marke + cls.client.topic_ack.remove(mid) + + + + +class Json_msg: + GPS_Data = {"lat": 100000000, "lon": 200000000, "alt": 300000000, "count":0} + count = 0 + #Mqtt + client = None + Delay_topicToMqtt_PUB = None + timePub = 0 + qos = None + + + + + + @classmethod + def callBack_gps(cls): + cls.GPS_Data["count"] = cls.count + dataJsonFormate = orjson.dumps(cls.GPS_Data) + cls.mqtt_Pub(message=dataJsonFormate, topics=cls.Delay_topicToMqtt_PUB) + # print ('lat:'+lat+'\n'+'lon:'+lon+'\n') + + + @classmethod + def mqtt_Pub(cls, message:str, topics:str, waitForAck:bool=False): + cls.timePub = time.perf_counter_ns() + mid = cls.client.publish(topics, message, cls.qos)[1] + logger.info("{} {}".format(cls.count,cls.timePub)) + cls.count += 1 + # if waitForAck: + # while mid not in cls.client.topic_ack: + # print("wait for ack") + # time.sleep(0.25) + # cls.client.topic_ack.remove(mid) \ No newline at end of file diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/protoJson_delayClientA_SUB.py b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/protoJson_delayClientA_SUB.py new file mode 100644 index 0000000..310c97c --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/protoJson_delayClientA_SUB.py @@ -0,0 +1,36 @@ +import orjson +import time + +import proto.flight_information_pb2 as flight_information_pb2 +import proto.flyformatioln_pb2 as flyformatioln_pb2 +import google.protobuf.json_format as json_format +import logging + + +logger = logging.getLogger("__delayA_SUB__") + +class Proto_msg: + #Protobuf + flight_information_msg = None + + timeRcv = 0 + msgCounter = None + + @classmethod + def on_message(cls, client, userdata, msg): + cls.timeRcv = time.perf_counter_ns() + cls.msgCounter = int(cls.flight_information_msg.FromString(msg.payload).heading) + logger.info("{} {}".format(cls.msgCounter, cls.timeRcv)) + + + +class Json_msg: + timeRcv = 0 + msgCounter = None + + @classmethod + def on_message(cls, client, userdata, msg): + cls.timeRcv = time.perf_counter_ns() + cls.msgCounter = orjson.loads(msg.payload)["count"] + logger.info("{} {}".format(cls.msgCounter, cls.timeRcv)) + diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/protoJson_delayClientB_SUB.py b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/protoJson_delayClientB_SUB.py new file mode 100644 index 0000000..a96a128 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/protoJson_delayClientB_SUB.py @@ -0,0 +1,53 @@ +import orjson +import time + +import proto.flight_information_pb2 as flight_information_pb2 +import proto.flyformatioln_pb2 as flyformatioln_pb2 +import google.protobuf.json_format as json_format +import logging + +# TODO: use native ros type instead of json or str +logger = logging.getLogger("__SUB__") + +class Proto_msg: + #Protobuf + flight_information_msg = None + fly_formation_msg = None # delcare in function + + #Mqtt topic: check data from which topic + Delay_topicToMqtt_PUB = None + qos = None + + client = None + timeRcv = 0 + timeRsp = 0 + + msgCounter = None + + + + @classmethod + def on_message(cls, client, userdata, msg): + cls.timeRcv = time.perf_counter_ns() + cls.msgCounter = int(cls.flight_information_msg.FromString(msg.payload).heading) + logger.info("{} {}".format(cls.msgCounter, cls.timeRcv)) + + +class Json_msg: + #Mqtt topic: check data from which topic + Delay_topicToMqtt_PUB = None + + qos = None + client = None + timeRcv = 0 + timeRsp = 0 + + msgCounter = None + + + + @classmethod + def on_message(cls, client, userdata, msg): + cls.timeRcv = time.perf_counter_ns() + cls.msgCounter = orjson.loads(msg.payload)["count"] + logger.info("{} {}".format(cls.msgCounter, cls.timeRcv)) \ No newline at end of file diff --git a/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/readConfig.py b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/readConfig.py new file mode 100644 index 0000000..87494d8 --- /dev/null +++ b/Stream/experiment/datalose_test/MQTT_measure_datalose/utils/readConfig.py @@ -0,0 +1,109 @@ +import yaml + +class Config: + def __init__(self, inFileName): + self.sectionNames = ["MQTT", "LOG"] + self.options = {} + self.inFileName = inFileName + + def setAttribute(self): + with open(self.inFileName,"r") as f: + self.ymlcfg=yaml.safe_load(f) + ecfgs = [self.ymlcfg.get(name) for name in self.sectionNames] + if None in ecfgs: + nameIndex = ecfgs.index(None) + raise Exception("Missing {} section in cfg file".format(self.sectionNames[nameIndex])) + #iterate over options + for opts, ecfg in zip(self.options, ecfgs): + for opt in self.options[opts]: + if opt in ecfg: + optval=ecfg[opt] + #verify parameter type + if type(optval) != self.options[opts][opt][0]: + raise Exception("Parameter {} has wrong type".format(opt)) + + #create attributes on the fly + setattr(self,opt,optval) + else: + if self.options[opts][opt][1]: + raise Exception("Missing mandatory parameter {}".format(opt)) + else: + setattr(self,opt,None) + + def __str__(self): + return str(yaml.dump(self.ymlcfg, default_flow_style=False)) + + +class Read_delayA_PUB_Config(Config): + def setAttribute(self): + super().setAttribute() + + def __init__(self, inFileName): + super().__init__(inFileName) + self.options = { + self.sectionNames[0]:{ + "msg_format": (str,True), + "MQTTClientNamePub": (str,True), + "host": (str,True), + "port": (int,True), + "keepalive": (int,True), + "Delay_topicToMqtt_PUB": (str,False), + "msgInterval": (float,True), + "msgAmount": (int,True), + "qos": (int,True)}, + self.sectionNames[1]:{ + "logFileName":(str,False)}} + self.setAttribute() + + def __str__(self): + return super().__str__() + +class Read_delayB_SUB_Config(Config): + def setAttribute(self): + super().setAttribute() + + def __init__(self, inFileName): + super().__init__(inFileName) + self.options = { + self.sectionNames[0]:{ + "msg_format": (str,True), + "MQTTClientNameSub": (str,True), + "host": (str,True), + "port": (int,True), + "keepalive": (int,True), + "Delay_topicToMqtt_SUB":(str,True), + "Delay_topicToMqtt_PUB":(str,True), + "qos": (int,True)}, + self.sectionNames[1]:{ + "logFileName":(str,False)}} + self.setAttribute() + +class Read_delayA_SUB_Config(Config): + def setAttribute(self): + super().setAttribute() + + def __init__(self, inFileName): + super().__init__(inFileName) + self.options = { + self.sectionNames[0]:{ + "msg_format": (str,True), + "MQTTClientNameSub": (str,True), + "host": (str,True), + "port": (int,True), + "keepalive": (int,True), + "Respond_topicToMqtt_SUB":(str,True), + "qos": (int,True)}, + self.sectionNames[1]:{ + "logFileName":(str,False)}} + self.setAttribute() + + def __str__(self): + return super().__str__() + + + +if __name__ == "__main__": + cfg=Read_delayA_SUB_Config("mqttConfig_CMD.yml") + print(cfg) + + diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/loseData/test1/results.csv b/Stream/experiment/datalose_test/uavlink_measrue_datalose/loseData/test1/results.csv new file mode 100644 index 0000000..f1b9870 --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/loseData/test1/results.csv @@ -0,0 +1,4 @@ +frequency,packet_loss,percentage_loss +1hz,0,0.0 +2hz,0,0.0 +5hz,15,15.0 diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/loseData/test5/results.csv b/Stream/experiment/datalose_test/uavlink_measrue_datalose/loseData/test5/results.csv new file mode 100644 index 0000000..128e619 --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/loseData/test5/results.csv @@ -0,0 +1,11 @@ +frequency,packet_loss,percentage_loss +1hz,0,0.0 +2hz,1,1.0 +3hz,6,6.0 +4hz,8,8.0 +5hz,17,17.0 +6hz,32,32.0 +7hz,48,48.0 +8hz,52,52.0 +9hz,52,52.0 +10hz,55,55.00000000000001 diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/lose_ClientA_PUB.py b/Stream/experiment/datalose_test/uavlink_measrue_datalose/lose_ClientA_PUB.py new file mode 100755 index 0000000..18a7ae4 --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/lose_ClientA_PUB.py @@ -0,0 +1,82 @@ +#!/usr/bin/env python3 +#coding:utf-8 +import serial +import time +import sys +import os +import proto.flight_information_pb2 as flight_information_pb2 +import logging +from utils.readConfig import Read_PUB_Config +from utils.proto_delayClientA_PUB import Proto_msg_from_ros +import random +import time +import argparse + +class fakeGps(): + def __init__(self): + self.latitude = 8.0 + self.longitude = 8.1 + self.altitude = 8.88 + +class fake_hdg(): + def __init__(self): + self.data = 1 + +def init_dataFormat(cfg:Read_PUB_Config): + + Proto_msg_from_ros.sel = sel + Proto_msg_from_ros.flight_information_msg = flight_information_pb2.flight_information_message() + + +if __name__ == '__main__': + FilePath = os.path.join(os.path.dirname(__file__),"utils","uavlinkConfig_PUB.yml") + cfg = Read_PUB_Config(FilePath) + gps = fakeGps() + hdg = fake_hdg() + + parser = argparse.ArgumentParser() + parser.add_argument("-t", "--delaytime", type=float, default="1.0", help="1/frequence", required=True) + args = parser.parse_args() + + # set log + stream_log_format = "%(asctime)s - %(levelname)s - %(message)s" + file_log_format = "%(message)s" + file_formatter = logging.Formatter(file_log_format) + stream_formatter = logging.Formatter(stream_log_format) + + stream_handler = logging.StreamHandler() + stream_handler.setFormatter(stream_formatter) + stream_handler.setLevel(logging.DEBUG) + + file_handler = logging.FileHandler(cfg.logFileName, mode='w') + file_handler.setFormatter(file_formatter) + file_handler.setLevel(logging.INFO) + + logger = logging.getLogger("__UAVLINKSUBPUB__") + logger.setLevel(logging.DEBUG) + logger.addHandler(file_handler) + logger.addHandler(stream_handler) + logger.debug(cfg) + + sel = serial.Serial(cfg.ttyport, cfg.baudrate, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE) + init_dataFormat(cfg) + + + while hdg.data <= 100: + gps.latitude = random.uniform(10, 100) + gps.longitude = random.uniform(10, 100) + gps.altitude = random.uniform(10, 100) + + + try: + # test json + Proto_msg_from_ros.callBack_gps(gps) + Proto_msg_from_ros.callBack_compass_hdg(hdg) + time.sleep(args.delaytime) + hdg.data += 1 + except KeyboardInterrupt as e: + sel.write(b'\xf2' + b'......................' + b'\x0d\x2a') + readTenByte = sel.read_until(size=5) + + print("End of program") + sys.exit() \ No newline at end of file diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/lose_ClientB.py b/Stream/experiment/datalose_test/uavlink_measrue_datalose/lose_ClientB.py new file mode 100644 index 0000000..bed14b7 --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/lose_ClientB.py @@ -0,0 +1,69 @@ +#!/usr/bin/env python3 +#coding:utf-8 +import serial +import time +import sys +import os +import proto.flight_information_pb2 as flight_information_pb2 +import logging +from utils.readConfig import Read_SUB_Config +from utils.proto_delayClientB_SUB import Proto_msg_to_ros +import google.protobuf.message +import argparse + +def init_dataFormat(cfg:Read_SUB_Config): + Proto_msg_to_ros.sel = sel + Proto_msg_to_ros.flight_information_msg = flight_information_pb2.flight_information_message() + + +if __name__ == '__main__': + parser = argparse.ArgumentParser() + parser.add_argument("-f", "--frequency", type=str, default="1", help="transmission frequency", required=True) + args = parser.parse_args() + FilePath = os.path.join(os.path.dirname(__file__),"utils","uavlinkConfig_SUB.yml") + cfg = Read_SUB_Config(FilePath) + + # set log + stream_log_format = "%(asctime)s - %(levelname)s - %(message)s" + file_log_format = "%(message)s" + file_formatter = logging.Formatter(file_log_format) + stream_formatter = logging.Formatter(stream_log_format) + + stream_handler = logging.StreamHandler() + stream_handler.setFormatter(stream_formatter) + stream_handler.setLevel(logging.DEBUG) + + file_handler = logging.FileHandler(args.frequency +"hz.log", mode='w') + file_handler.setFormatter(file_formatter) + file_handler.setLevel(logging.INFO) + + logger = logging.getLogger("__UAVLINKSUB__") + logger.setLevel(logging.DEBUG) + logger.addHandler(file_handler) + logger.addHandler(stream_handler) + logger.debug(cfg) + last_packet = None + count = 0 + sel = serial.Serial(cfg.ttyport, cfg.baudrate, serial.EIGHTBITS, serial.PARITY_NONE, serial.STOPBITS_ONE) + init_dataFormat(cfg) + + while True: + try: + # test json + if sel.in_waiting >= 25: + readTenByte = sel.read_until(expected= b'\x01\x17', size=25) + if readTenByte == last_packet: + count += 1 + continue + last_packet = readTenByte + timeSub = time.perf_counter_ns() + Proto_msg_to_ros.on_message_Flight_Information(readTenByte, timeSub) + except google.protobuf.message.DecodeError as e: + logger.debug(readTenByte) + logger.debug(len(readTenByte)) + logger.debug(e) + logger.debug(count) + except KeyboardInterrupt as e: + Proto_msg_to_ros.turnOffUavlink() + logger.debug("End of program") + sys.exit() \ No newline at end of file diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/measureLose.py b/Stream/experiment/datalose_test/uavlink_measrue_datalose/measureLose.py new file mode 100644 index 0000000..f665875 --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/measureLose.py @@ -0,0 +1,85 @@ +import pandas as pd +import matplotlib.pyplot as plt +import argparse +import os +import fnmatch +import re + + +def check_number_of_lines(df, log_name): + if df.shape[0] != args.number: + print(f"Warning: Number of lines in the log file {log_name} is not correct") + return list(check_continuous_count(df, log_name)) + else: + return [] + + +def check_continuous_count(df, log_name): + duplicates = df[df["count"].duplicated()]["count"] + if not duplicates.empty: + print(f"Warning: Non-continuous count in the log file {log_name} at index {duplicates.index.tolist()}") + max_count = args.number + all_counts = set(range(1, max_count + 1)) + actual_counts = set(df["count"]) + missing = all_counts - actual_counts + if missing != set(): + print(f"Warning: missing msg in {log_name} at index {missing}") + return missing + else: + return 0 + + +def extract_number(filename): + return int(re.search(r'\d+', filename).group()) + + +if __name__ == "__main__": + parser = argparse.ArgumentParser() + parser.add_argument("-n", "--number", type=int, default="1000", help="number of packet", required=True) + parser.add_argument("-t", "--test", type=str, default="1", help="number of test", required=True) + args = parser.parse_args() + + log_files_path = os.listdir(f"loseData/test{args.test}") + log_files = [file_name for file_name in log_files_path if fnmatch.fnmatch(file_name, '*.log')] + log_files.sort(key=extract_number) + + frequence = [file_name.replace(".log", "") for file_name in log_files] + + dataframes = [] + missing_counts = [] + for log_file in log_files: + df = pd.read_csv(f"loseData/test{args.test}/{log_file}", delim_whitespace=True, header=None, names=["count", "time"]) + dataframes.append(df) + missing_counts.append(check_number_of_lines(df, log_file)) + + total_lengths = [len(sublist) for sublist in missing_counts] + print(total_lengths) + + plt.rcParams["figure.figsize"] = [13, 6] + plt.rcParams["figure.autolayout"] = True + + bar_plot = plt.bar(frequence, total_lengths, edgecolor='black') + + plt.title("Packet drop") + plt.xlabel("Frequency") + plt.ylabel("packet loss rate((%))") + + total_packets = args.number + for i, bar in enumerate(bar_plot): + loss_percentage = total_lengths[i] / total_packets * 100 + plt.text(bar.get_x() + bar.get_width() / 2, bar.get_height() + 0.1, + f"{loss_percentage:.2f}%", ha="center", va="bottom") + + + plt.savefig(f"loseData/test{args.test}/test{args.test}.png", dpi=300) + plt.show() + + # Create a DataFrame with frequency and packet loss data + results_df = pd.DataFrame({'frequency': frequence, 'packet_loss': total_lengths}) + + # Calculate percentage loss for each row + results_df['percentage_loss'] = results_df['packet_loss'] / total_packets * 100 + + # Save the results as a CSV file + results_df.to_csv(f"loseData/test{args.test}/results.csv", index=False) + \ No newline at end of file diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/duration_pb2.py b/Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/duration_pb2.py new file mode 100644 index 0000000..1a30c51 --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/duration_pb2.py @@ -0,0 +1,78 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: duration.proto + +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='duration.proto', + package='google.protobuf', + syntax='proto3', + serialized_options=b'\n\023com.google.protobufB\rDurationProtoP\001Z1google.golang.org/protobuf/types/known/durationpb\370\001\001\242\002\003GPB\252\002\036Google.Protobuf.WellKnownTypes', + create_key=_descriptor._internal_create_key, + serialized_pb=b'\n\x0e\x64uration.proto\x12\x0fgoogle.protobuf\"*\n\x08\x44uration\x12\x0f\n\x07seconds\x18\x01 \x01(\x03\x12\r\n\x05nanos\x18\x02 \x01(\x05\x42\x83\x01\n\x13\x63om.google.protobufB\rDurationProtoP\x01Z1google.golang.org/protobuf/types/known/durationpb\xf8\x01\x01\xa2\x02\x03GPB\xaa\x02\x1eGoogle.Protobuf.WellKnownTypesb\x06proto3' +) + + + + +_DURATION = _descriptor.Descriptor( + name='Duration', + full_name='google.protobuf.Duration', + filename=None, + file=DESCRIPTOR, + containing_type=None, + create_key=_descriptor._internal_create_key, + fields=[ + _descriptor.FieldDescriptor( + name='seconds', full_name='google.protobuf.Duration.seconds', index=0, + number=1, type=3, cpp_type=2, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + _descriptor.FieldDescriptor( + name='nanos', full_name='google.protobuf.Duration.nanos', index=1, + number=2, type=5, cpp_type=1, label=1, + has_default_value=False, default_value=0, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR, create_key=_descriptor._internal_create_key), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=35, + serialized_end=77, +) + +DESCRIPTOR.message_types_by_name['Duration'] = _DURATION +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +Duration = _reflection.GeneratedProtocolMessageType('Duration', (_message.Message,), { + 'DESCRIPTOR' : _DURATION, + '__module__' : 'duration_pb2' + # @@protoc_insertion_point(class_scope:google.protobuf.Duration) + }) +_sym_db.RegisterMessage(Duration) + + +DESCRIPTOR._options = None +# @@protoc_insertion_point(module_scope) diff --git a/Stream/uav_proto_msg/protomsg/proto/flight_information.proto b/Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/flight_information.proto similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/flight_information.proto rename to Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/flight_information.proto diff --git a/Stream/uav_proto_msg/protomsg/proto/flight_information_pb2.py b/Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/flight_information_pb2.py similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/flight_information_pb2.py rename to Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/flight_information_pb2.py diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/flyformatioln.proto b/Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/flyformatioln.proto new file mode 100644 index 0000000..56a6d58 --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/flyformatioln.proto @@ -0,0 +1,17 @@ +syntax = "proto3"; +package fly_formation_proto; +// leader only + +enum FLY_FORMATION{ + FLY_FORMATION_UNSPECIFIED = 0; + FLY_FORMATION_v = 1; + FLY_FORMATION_X = 2; + FLY_FORMATION_O = 3; + FLY_FORMATION_LINE = 4; + FLY_FORMATION_ROW = 5; + FLY_FORMATION_HEX = 6; + } + message fly_formation_message{ + optional float velocity = 1; + FLY_FORMATION fly_formation= 2; + } \ No newline at end of file diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/flyformatioln_pb2.py b/Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/flyformatioln_pb2.py new file mode 100644 index 0000000..34014f4 --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/proto/flyformatioln_pb2.py @@ -0,0 +1,27 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: flyformatioln.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x13\x66lyformatioln.proto\x12\x13\x66ly_formation_proto\"v\n\x15\x66ly_formation_message\x12\x15\n\x08velocity\x18\x01 \x01(\x02H\x00\x88\x01\x01\x12\x39\n\rfly_formation\x18\x02 \x01(\x0e\x32\".fly_formation_proto.FLY_FORMATIONB\x0b\n\t_velocity*\xb3\x01\n\rFLY_FORMATION\x12\x1d\n\x19\x46LY_FORMATION_UNSPECIFIED\x10\x00\x12\x13\n\x0f\x46LY_FORMATION_v\x10\x01\x12\x13\n\x0f\x46LY_FORMATION_X\x10\x02\x12\x13\n\x0f\x46LY_FORMATION_O\x10\x03\x12\x16\n\x12\x46LY_FORMATION_LINE\x10\x04\x12\x15\n\x11\x46LY_FORMATION_ROW\x10\x05\x12\x15\n\x11\x46LY_FORMATION_HEX\x10\x06\x62\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'flyformatioln_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _FLY_FORMATION._serialized_start=165 + _FLY_FORMATION._serialized_end=344 + _FLY_FORMATION_MESSAGE._serialized_start=44 + _FLY_FORMATION_MESSAGE._serialized_end=162 +# @@protoc_insertion_point(module_scope) diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/__init__.py b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/basicMqtt.py b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/basicMqtt.py new file mode 100644 index 0000000..572e84e --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/basicMqtt.py @@ -0,0 +1,17 @@ +import paho.mqtt.client as mqtt +import time +class MQTTClient(mqtt.Client): + + def __init__(self,cname,**kwargs): + super().__init__(cname,**kwargs) + self.last_pub_time=time.time() + self.topic_ack=[] + self.run_flag=True + self.subscribe_flag=False + self.bad_connection_flag=False + self.connected_flag=True + self.disconnect_flag=False + self.disconnect_time=0.0 + self.pub_msg_count=0 + self.devices=[] + diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/proto_delayClientA_PUB.py b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/proto_delayClientA_PUB.py new file mode 100644 index 0000000..d412a67 --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/proto_delayClientA_PUB.py @@ -0,0 +1,28 @@ +import orjson +import time +import logging + +logger = logging.getLogger("__UAVLINKSUBPUB__") + +class Proto_msg_from_ros: + #Protobuf + flight_information_msg = None + sel = None + + + @classmethod + def callBack_gps(cls, GPS): + cls.flight_information_msg.gps.LAT = GPS.latitude + cls.flight_information_msg.gps.LON = GPS.longitude + cls.flight_information_msg.gps.ALT = GPS.altitude + + + @classmethod + def callBack_compass_hdg(cls, Compass): + cls.flight_information_msg.heading = Compass.data + flightInformationMsg = cls.flight_information_msg.SerializeToString() + cls.sel.write(b'\xf2' + flightInformationMsg + b'\x0d\x0a') + timePub = time.perf_counter_ns() + logger.info("{} {}".format(Compass.data,timePub)) + + diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/proto_delayClientA_SUB.py b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/proto_delayClientA_SUB.py new file mode 100644 index 0000000..d64cb31 --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/proto_delayClientA_SUB.py @@ -0,0 +1,25 @@ +import time + +import proto.flight_information_pb2 as flight_information_pb2 +import google.protobuf.json_format as json_format +import logging + +# TODO: use native ros type instead of json or str +logger = logging.getLogger("__UAVLINKSUB__") + +class Proto_msg_to_ros: + #Protobuf + flight_information_msg = None + + #Ros publisher + rate = None + publisher_Flight_Information = None + + + #Proto + @classmethod + def on_message_Flight_Information(cls, msg, timeSub): + proto = msg[1:-2] + proto_msg = cls.flight_information_msg.FromString(proto) + count = proto_msg.heading + logger.info("{} {}".format(count,timeSub)) \ No newline at end of file diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/proto_delayClientB_SUB.py b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/proto_delayClientB_SUB.py new file mode 100644 index 0000000..7543af3 --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/proto_delayClientB_SUB.py @@ -0,0 +1,47 @@ +import time + +import proto.flight_information_pb2 as flight_information_pb2 +import google.protobuf.json_format as json_format +import logging + +# TODO: use native ros type instead of json or str +logger = logging.getLogger("__UAVLINKSUB__") + +class Proto_msg_to_ros: + #Protobuf + flight_information_msg = None + + #Ros publisher + rate = None + publisher_Flight_Information = None + #uavlink + sel = None + payload = b"......................" + noEcho_code = b"\x0d\x0a" + echo_code = b"\x0d\x1a" + close_code = b"\x0d\x2a" + f1_code = b"\xf1" + f2_code = b"\xf2" + f1_close_code = f1_code + payload + close_code + f2_close_code = f2_code + payload + close_code + + # count = None + + #Proto + @classmethod + def on_message_Flight_Information(cls, msg, timeSub): + proto = msg[1:-2] + proto_msg = cls.flight_information_msg.FromString(proto) + # cls.sel.write(b'\xf2' + proto + b'\x0d\x0a') + timePub = time.perf_counter_ns() + # readTenByte = cls.sel.read_until(size=5) + timeDiff = timePub - timeSub + # cls.count = proto_msg.heading + logger.info("{} {}".format(proto_msg.heading, timeDiff)) + + @classmethod + def turnOffUavlink(cls): + time.sleep(0.5) + cls.sel.write(cls.f1_close_code) + time.sleep(0.5) + cls.sel.write(cls.f2_close_code) diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/readConfig.py b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/readConfig.py new file mode 100644 index 0000000..54386da --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/readConfig.py @@ -0,0 +1,152 @@ +import yaml + +class Config: + def __init__(self, inFileName): + self.sectionNames = ["MQTT","ROS", "LOG", "UAVLINK"] + self.options = {} + self.inFileName = inFileName + + def setAttribute(self): + with open(self.inFileName,"r") as f: + self.ymlcfg=yaml.safe_load(f) + + ecfgs = [self.ymlcfg.get(name) for name in self.sectionNames] + if None in ecfgs: + nameIndex = ecfgs.index(None) + raise Exception("Missing {} section in cfg file".format(self.sectionNames[nameIndex])) + #iterate over options + for opts, ecfg in zip(self.options, ecfgs): + for opt in self.options[opts]: + if opt in ecfg: + optval=ecfg[opt] + #verify parameter type + if type(optval) != self.options[opts][opt][0]: + raise Exception("Parameter {} has wrong type".format(self.opt)) + + #create attributes on the fly + setattr(self,opt,optval) + else: + if self.options[opts][opt][1]: + raise Exception("Missing mandatory parameter {}".format(self.opt)) + else: + setattr(self,opt,None) + + def __str__(self): + return str(yaml.dump(self.ymlcfg, default_flow_style=False)) + + +class Read_PUB_Config(Config): + def setAttribute(self): + super().setAttribute() + + def __init__(self, inFileName): + super().__init__(inFileName) + self.options = { + self.sectionNames[0]:{ + "msg_format": (str,False), + "MQTTClientNamePub": (str,False), + "host": (str,False), + "port": (int,False), + "keepalive": (int,False), + "willTopic":(str,False), + "lwt":(str, False), + "willRetain":(bool,False), + "willTopicQOS":(int,False), + "Flight_Information_topicToMqtt": (str,False), + "Fly_Formation_topicToMqtt": (str,False), + "Fly_Formation_topicToMqtt_QOS":(int,False)}, + self.sectionNames[1]:{ + "ROSClientNamePub": (str,True), + "ROStopicName_Flight_Information": (str,False), + "ROStopicName_Fly_Formation": (str,False)}, + self.sectionNames[2]:{ + "logFileName":(str,True)}, + self.sectionNames[3]:{ + "uavlink_msg_format": (str,False), + "uav_id": (str,False), + "baudrate": (int,False), + "ttyport": (str,False)}} + self.setAttribute() + + def __str__(self): + return super().__str__() + +class Read_SUB_Config(Config): + def setAttribute(self): + super().setAttribute() + + def __init__(self, inFileName): + super().__init__(inFileName) + self.options = { + self.sectionNames[0]:{ + "msg_format": (str,False), + "MQTTClientNameSub": (str,False), + "host": (str,False), + "port": (int,False), + "keepalive": (int,False), + "willTopic":(str,False), + "lwt":(str, False), + "willRetain":(bool,False), + "willTopicQOS":(int,False), + "Drone550_Flight_Information_topicToMqtt": (str,False), + "Drone380_Flight_Information_topicToMqtt":(str,False), + "Drone650_Flight_Information_topicToMqtt":(str,False), + "Drone888_Flight_Information_topicToMqtt":(str,False), + "Drone555_Flight_Information_topicToMqtt":(str,False), + "Fly_Formation_topicToMqtt": (str,False), + "Fly_Formation_topicToMqtt_QOS":(int,False)}, + self.sectionNames[1]:{ + "ROSClientNameSub": (str,True), + "Dron550_ROStopicName_Flight_Information": (str,False), + "Dron380_ROStopicName_Flight_Information": (str,False), + "Dron380_ROStopicName_Flight_Information": (str,False), + "Dron650_ROStopicName_Flight_Information": (str,False), + "Dron888_ROStopicName_Flight_Information": (str,False), + "Dron555_ROStopicName_Flight_Information": (str,False), + "Dron_ROStopicName_Flight_Information": (str,False), + "ROStopicName_Fly_Formation": (str,False)}, + self.sectionNames[2]:{ + "logFileName":(str,False)}, + self.sectionNames[3]:{ + "uavlink_msg_format": (str,False), + "uav_id": (str,False), + "baudrate": (int,False), + "ttyport": (str,False)}} + self.setAttribute() + + def __str__(self): + return super().__str__() + +class Read_CMD_Config(Config): + def setAttribute(self): + super().setAttribute() + + def __init__(self, inFileName): + super().__init__(inFileName) + self.options = { + self.sectionNames[0]:{ + "msg_format": (str,True), + "MQTTClientNameCmd": (str,True), + "host": (str,True), + "port": (int,True), + "keepalive": (int,True), + "Cmd_Broadcast_topicToMqtt": (str,True), + "Cmd_Direct_topicToMqtt": (str,False), + "Cmd_Broadcast_topicToMqtt_QOS":(int,True), + "Cmd_Direct_topicToMqtt_QOS":(int,False)}, + self.sectionNames[1]:{ + "ROSClientNameCmd": (str,True), + "ROStopicName_Cmd_Broadcast_Receiver": (str,True), + "ROStopicName_Cmd_Direct_Receiver": (str,False)}, + self.sectionNames[2]:{ + "logFileName":(str,False)}} + self.setAttribute() + + def __str__(self): + return super().__str__() + +if __name__ == "__main__": + cfg=Read_CMD_Config("mqttConfig_CMD.yml") + print(cfg) + + diff --git a/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/uavlinkConfig_PUB.yml b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/uavlinkConfig_PUB.yml new file mode 100644 index 0000000..f7d5723 --- /dev/null +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/uavlinkConfig_PUB.yml @@ -0,0 +1,12 @@ +UAVLINK: + uavlink_msg_format: Proto + uav_id: \x01\x01 + baudrate: 250000 + ttyport: /dev/ttyUSB0 +MQTT: "None" +#ROS +ROS: + ROSClientNamePub: Drone550UAVLINKPub + ROStopicName_Flight_Information: Flight_Information_reciver +LOG: + logFileName: ProtodelayA_PUB.log diff --git a/Stream/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_SUB.yml b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/uavlinkConfig_SUB.yml similarity index 87% rename from Stream/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_SUB.yml rename to Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/uavlinkConfig_SUB.yml index 4b57446..322b9c8 100644 --- a/Stream/RTL_test/uavlink_measrue_rtl/utils/uavlinkConfig_SUB.yml +++ b/Stream/experiment/datalose_test/uavlink_measrue_datalose/utils/uavlinkConfig_SUB.yml @@ -8,4 +8,4 @@ ROS: ROSClientNameSub: Drone550UAVLINKSub Dron550_ROStopicName_Flight_Information: Flight_Information_reciver LOG: - logFileName: ProtodelayA_SUB.log \ No newline at end of file + logFileName: ProtoloseA_SUB.log \ No newline at end of file diff --git a/Stream/uav_proto_msg/protomsg/Data/sizeData b/Stream/experiment/protomsg/Data/sizeData similarity index 100% rename from Stream/uav_proto_msg/protomsg/Data/sizeData rename to Stream/experiment/protomsg/Data/sizeData diff --git a/Stream/experiment/protomsg/Data/timeData b/Stream/experiment/protomsg/Data/timeData new file mode 100644 index 0000000..9552ce1 --- /dev/null +++ b/Stream/experiment/protomsg/Data/timeData @@ -0,0 +1 @@ +{"serialize":{"json":0.34479037301207427,"proto":1.0475460140005453},"deserializ":{"json":0.42335569999704603,"proto":0.5118989990005502}} \ No newline at end of file diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/duration_info_message b/Stream/experiment/protomsg/JsonProtosize/duration_info_message similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/duration_info_message rename to Stream/experiment/protomsg/JsonProtosize/duration_info_message diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/duration_info_message.bin b/Stream/experiment/protomsg/JsonProtosize/duration_info_message.bin similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/duration_info_message.bin rename to Stream/experiment/protomsg/JsonProtosize/duration_info_message.bin diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/flight_info_message b/Stream/experiment/protomsg/JsonProtosize/flight_info_message similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/flight_info_message rename to Stream/experiment/protomsg/JsonProtosize/flight_info_message diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/flight_info_message.bin b/Stream/experiment/protomsg/JsonProtosize/flight_info_message.bin similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/flight_info_message.bin rename to Stream/experiment/protomsg/JsonProtosize/flight_info_message.bin diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/fly_format_message b/Stream/experiment/protomsg/JsonProtosize/fly_format_message similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/fly_format_message rename to Stream/experiment/protomsg/JsonProtosize/fly_format_message diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/fly_format_message.bin b/Stream/experiment/protomsg/JsonProtosize/fly_format_message.bin similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/fly_format_message.bin rename to Stream/experiment/protomsg/JsonProtosize/fly_format_message.bin diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/flymode_info_message b/Stream/experiment/protomsg/JsonProtosize/flymode_info_message similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/flymode_info_message rename to Stream/experiment/protomsg/JsonProtosize/flymode_info_message diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/flymode_info_message.bin b/Stream/experiment/protomsg/JsonProtosize/flymode_info_message.bin similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/flymode_info_message.bin rename to Stream/experiment/protomsg/JsonProtosize/flymode_info_message.bin diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/imu_info_message b/Stream/experiment/protomsg/JsonProtosize/imu_info_message similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/imu_info_message rename to Stream/experiment/protomsg/JsonProtosize/imu_info_message diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/imu_info_message.bin b/Stream/experiment/protomsg/JsonProtosize/imu_info_message.bin similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/imu_info_message.bin rename to Stream/experiment/protomsg/JsonProtosize/imu_info_message.bin diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/odom_info_message b/Stream/experiment/protomsg/JsonProtosize/odom_info_message similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/odom_info_message rename to Stream/experiment/protomsg/JsonProtosize/odom_info_message diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/odom_info_message.bin b/Stream/experiment/protomsg/JsonProtosize/odom_info_message.bin similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/odom_info_message.bin rename to Stream/experiment/protomsg/JsonProtosize/odom_info_message.bin diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/timestamp_info_message b/Stream/experiment/protomsg/JsonProtosize/timestamp_info_message similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/timestamp_info_message rename to Stream/experiment/protomsg/JsonProtosize/timestamp_info_message diff --git a/Stream/uav_proto_msg/protomsg/JsonProtosize/timestamp_info_message.bin b/Stream/experiment/protomsg/JsonProtosize/timestamp_info_message.bin similarity index 100% rename from Stream/uav_proto_msg/protomsg/JsonProtosize/timestamp_info_message.bin rename to Stream/experiment/protomsg/JsonProtosize/timestamp_info_message.bin diff --git a/Stream/uav_proto_msg/protomsg/proto/duration.proto b/Stream/experiment/protomsg/proto/duration.proto similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/duration.proto rename to Stream/experiment/protomsg/proto/duration.proto diff --git a/Stream/uav_proto_msg/protomsg/proto/duration_pb2.py b/Stream/experiment/protomsg/proto/duration_pb2.py similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/duration_pb2.py rename to Stream/experiment/protomsg/proto/duration_pb2.py diff --git a/Stream/experiment/protomsg/proto/flight_information.proto b/Stream/experiment/protomsg/proto/flight_information.proto new file mode 100644 index 0000000..d377017 --- /dev/null +++ b/Stream/experiment/protomsg/proto/flight_information.proto @@ -0,0 +1,14 @@ +syntax = 'proto3'; + +// GPS + compass + +message GPS { + float LAT = 1; + float LON = 2; + float ALT = 3; +} + +message flight_information_message { + GPS gps = 1; + float heading = 2; +} \ No newline at end of file diff --git a/Stream/experiment/protomsg/proto/flight_information_pb2.py b/Stream/experiment/protomsg/proto/flight_information_pb2.py new file mode 100644 index 0000000..24e9adc --- /dev/null +++ b/Stream/experiment/protomsg/proto/flight_information_pb2.py @@ -0,0 +1,130 @@ +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: flight_information.proto + +import sys +_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1')) +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from google.protobuf import reflection as _reflection +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor.FileDescriptor( + name='flight_information.proto', + package='', + syntax='proto3', + serialized_options=None, + serialized_pb=_b('\n\x18\x66light_information.proto\",\n\x03GPS\x12\x0b\n\x03LAT\x18\x01 \x01(\x02\x12\x0b\n\x03LON\x18\x02 \x01(\x02\x12\x0b\n\x03\x41LT\x18\x03 \x01(\x02\"@\n\x1a\x66light_information_message\x12\x11\n\x03gps\x18\x01 \x01(\x0b\x32\x04.GPS\x12\x0f\n\x07heading\x18\x02 \x01(\x02\x62\x06proto3') +) + + + + +_GPS = _descriptor.Descriptor( + name='GPS', + full_name='GPS', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='LAT', full_name='GPS.LAT', index=0, + number=1, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='LON', full_name='GPS.LON', index=1, + number=2, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='ALT', full_name='GPS.ALT', index=2, + number=3, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=28, + serialized_end=72, +) + + +_FLIGHT_INFORMATION_MESSAGE = _descriptor.Descriptor( + name='flight_information_message', + full_name='flight_information_message', + filename=None, + file=DESCRIPTOR, + containing_type=None, + fields=[ + _descriptor.FieldDescriptor( + name='gps', full_name='flight_information_message.gps', index=0, + number=1, type=11, cpp_type=10, label=1, + has_default_value=False, default_value=None, + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + _descriptor.FieldDescriptor( + name='heading', full_name='flight_information_message.heading', index=1, + number=2, type=2, cpp_type=6, label=1, + has_default_value=False, default_value=float(0), + message_type=None, enum_type=None, containing_type=None, + is_extension=False, extension_scope=None, + serialized_options=None, file=DESCRIPTOR), + ], + extensions=[ + ], + nested_types=[], + enum_types=[ + ], + serialized_options=None, + is_extendable=False, + syntax='proto3', + extension_ranges=[], + oneofs=[ + ], + serialized_start=74, + serialized_end=138, +) + +_FLIGHT_INFORMATION_MESSAGE.fields_by_name['gps'].message_type = _GPS +DESCRIPTOR.message_types_by_name['GPS'] = _GPS +DESCRIPTOR.message_types_by_name['flight_information_message'] = _FLIGHT_INFORMATION_MESSAGE +_sym_db.RegisterFileDescriptor(DESCRIPTOR) + +GPS = _reflection.GeneratedProtocolMessageType('GPS', (_message.Message,), dict( + DESCRIPTOR = _GPS, + __module__ = 'flight_information_pb2' + # @@protoc_insertion_point(class_scope:GPS) + )) +_sym_db.RegisterMessage(GPS) + +flight_information_message = _reflection.GeneratedProtocolMessageType('flight_information_message', (_message.Message,), dict( + DESCRIPTOR = _FLIGHT_INFORMATION_MESSAGE, + __module__ = 'flight_information_pb2' + # @@protoc_insertion_point(class_scope:flight_information_message) + )) +_sym_db.RegisterMessage(flight_information_message) + + +# @@protoc_insertion_point(module_scope) diff --git a/Stream/uav_proto_msg/protomsg/proto/flyformatioln.proto b/Stream/experiment/protomsg/proto/flyformatioln.proto similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/flyformatioln.proto rename to Stream/experiment/protomsg/proto/flyformatioln.proto diff --git a/Stream/uav_proto_msg/protomsg/proto/flyformatioln_pb2.py b/Stream/experiment/protomsg/proto/flyformatioln_pb2.py similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/flyformatioln_pb2.py rename to Stream/experiment/protomsg/proto/flyformatioln_pb2.py diff --git a/Stream/uav_proto_msg/protomsg/proto/flymode.proto b/Stream/experiment/protomsg/proto/flymode.proto similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/flymode.proto rename to Stream/experiment/protomsg/proto/flymode.proto diff --git a/Stream/uav_proto_msg/protomsg/proto/flymode_pb2.py b/Stream/experiment/protomsg/proto/flymode_pb2.py similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/flymode_pb2.py rename to Stream/experiment/protomsg/proto/flymode_pb2.py diff --git a/Stream/uav_proto_msg/protomsg/proto/imu.proto b/Stream/experiment/protomsg/proto/imu.proto similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/imu.proto rename to Stream/experiment/protomsg/proto/imu.proto diff --git a/Stream/uav_proto_msg/protomsg/proto/imu_pb2.py b/Stream/experiment/protomsg/proto/imu_pb2.py similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/imu_pb2.py rename to Stream/experiment/protomsg/proto/imu_pb2.py diff --git a/Stream/uav_proto_msg/protomsg/proto/odom.proto b/Stream/experiment/protomsg/proto/odom.proto similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/odom.proto rename to Stream/experiment/protomsg/proto/odom.proto diff --git a/Stream/uav_proto_msg/protomsg/proto/odom_pb2.py b/Stream/experiment/protomsg/proto/odom_pb2.py similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/odom_pb2.py rename to Stream/experiment/protomsg/proto/odom_pb2.py diff --git a/Stream/uav_proto_msg/protomsg/proto/timestamp.proto b/Stream/experiment/protomsg/proto/timestamp.proto similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/timestamp.proto rename to Stream/experiment/protomsg/proto/timestamp.proto diff --git a/Stream/uav_proto_msg/protomsg/proto/timestamp_pb2.py b/Stream/experiment/protomsg/proto/timestamp_pb2.py similarity index 100% rename from Stream/uav_proto_msg/protomsg/proto/timestamp_pb2.py rename to Stream/experiment/protomsg/proto/timestamp_pb2.py diff --git a/Stream/uav_proto_msg/protomsg/protoMsg.py b/Stream/experiment/protomsg/protoMsg.py similarity index 100% rename from Stream/uav_proto_msg/protomsg/protoMsg.py rename to Stream/experiment/protomsg/protoMsg.py diff --git a/Stream/uav_proto_msg/protomsg/size_test.py b/Stream/experiment/protomsg/size_test.py similarity index 100% rename from Stream/uav_proto_msg/protomsg/size_test.py rename to Stream/experiment/protomsg/size_test.py diff --git a/Stream/uav_proto_msg/protomsg/timeit_test.py b/Stream/experiment/protomsg/timeit_test.py similarity index 100% rename from Stream/uav_proto_msg/protomsg/timeit_test.py rename to Stream/experiment/protomsg/timeit_test.py diff --git a/Stream/internet/internet_mqtt_pub_ros.py b/Stream/old_version_mqtt/internet/internet_mqtt_pub_ros.py similarity index 100% rename from Stream/internet/internet_mqtt_pub_ros.py rename to Stream/old_version_mqtt/internet/internet_mqtt_pub_ros.py diff --git a/Stream/internet/internet_mqtt_sub_ros.py b/Stream/old_version_mqtt/internet/internet_mqtt_sub_ros.py similarity index 100% rename from Stream/internet/internet_mqtt_sub_ros.py rename to Stream/old_version_mqtt/internet/internet_mqtt_sub_ros.py diff --git a/Stream/localRosData/local_mqtt_pub_data_to_ros.py b/Stream/old_version_mqtt/localRosData/local_mqtt_pub_data_to_ros.py similarity index 100% rename from Stream/localRosData/local_mqtt_pub_data_to_ros.py rename to Stream/old_version_mqtt/localRosData/local_mqtt_pub_data_to_ros.py diff --git a/Stream/localRosData/local_mqtt_sub_data_from_ros.py b/Stream/old_version_mqtt/localRosData/local_mqtt_sub_data_from_ros.py similarity index 100% rename from Stream/localRosData/local_mqtt_sub_data_from_ros.py rename to Stream/old_version_mqtt/localRosData/local_mqtt_sub_data_from_ros.py diff --git a/Stream/uav_proto_msg/flight_information.bin b/Stream/uav_proto_msg/flight_information.bin deleted file mode 100644 index 5da638e..0000000 --- a/Stream/uav_proto_msg/flight_information.bin +++ /dev/null @@ -1,2 +0,0 @@ - - KG?þ¶F~l=FEC \ No newline at end of file diff --git a/Stream/uav_proto_msg/flight_information.json b/Stream/uav_proto_msg/flight_information.json deleted file mode 100644 index 249c5cc..0000000 --- a/Stream/uav_proto_msg/flight_information.json +++ /dev/null @@ -1,6 +0,0 @@ -gps { - LAT: 34123.125 - LON: 23423.123046875 - ALT: 12123.123046875 -} -heading: 155.1221466064453 diff --git a/Stream/uav_proto_msg/fly_formation.bin b/Stream/uav_proto_msg/fly_formation.bin deleted file mode 100644 index 69768577ec7f77d52ae311d55bdbe8c98c405c57..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7 Ocmd;OU|?_-U<3dGOaNj4 diff --git a/Stream/uav_proto_msg/fly_formation.json b/Stream/uav_proto_msg/fly_formation.json deleted file mode 100644 index 45397cf..0000000 --- a/Stream/uav_proto_msg/fly_formation.json +++ /dev/null @@ -1,2 +0,0 @@ -velocity: 128.0 -fly_formation: FLY_FORMATION_v \ No newline at end of file diff --git a/Stream/uav_proto_msg/protomsg/Data/timeData b/Stream/uav_proto_msg/protomsg/Data/timeData deleted file mode 100644 index f87b524..0000000 --- a/Stream/uav_proto_msg/protomsg/Data/timeData +++ /dev/null @@ -1 +0,0 @@ -{"serialize":{"json":0.34842266000123345,"proto":1.0934251180005958},"deserializ":{"json":0.42545599799996126,"proto":0.48490119200141635}} \ No newline at end of file diff --git a/Stream/uav_proto_msg/protomsg/performancePlot/size.png b/Stream/uav_proto_msg/protomsg/performancePlot/size.png deleted file mode 100644 index 11516a73b4ca47a2d344ef4744f2c3108455ea2b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 246320 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 z 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 oSeRL%fWpiQ4HRZpsHkZFs?Mcp0TvE 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