LingxinMeng 8 ヶ月 前
コミット
5715cd4cfa

+ 13 - 0
src/python2/pjibot_patrol/README.md

@@ -0,0 +1,13 @@
+
+
+# pjibot
+nohup python2 pjibot_merge.py > log/pjibot_merge.out 2>&1 &
+nohup python2 pjibot_csv.py > log/pjibot_csv.log 2>&1 &
+nohup python2 pjibot_camera.py > log/pjibot_camera.log 2>&1 &
+nohup python2 pjibot_pcd.py > log/pjibot_pcd.log 2>&1 &
+nohup python2 pjibot_callback.py > log/pjibot_callback.log 2>&1 &
+
+
+
+# 轨迹生成工具部署
+source /root/workspace/devel/setup.bash

+ 8 - 0
src/python2/pjibot_patrol/callback-nohup.sh

@@ -0,0 +1,8 @@
+#!/bin/bash
+if [ ! -d "./log" ]; then
+    mkdir "./log"
+    echo "Directory './log' created."
+else
+    echo "Directory './log' already exists."
+fi
+nohup python2 callback-pjibot_patrol.py > log/callback.out 2>&1 &

+ 158 - 0
src/python2/pjibot_patrol/callback-pjibot_patrol.py

@@ -0,0 +1,158 @@
+# -*- coding: utf-8 -*-
+import json
+import time
+import urllib2
+import oss2
+from datetime import datetime, timedelta
+
+import logging
+
+path1 = '/mnt/disk001/dcl_data_process/src/python2/pjibot_patrol/'
+
+logging.basicConfig(filename=path1 + 'log/callback.log', level=logging.INFO,
+                    format='%(asctime)s - %(levelname)s - %(message)s')
+
+key1 = 'pjibot_patrol/'
+key2 = 'data/'
+key3 = 'data_merge/'
+key4 = 'data_parse/'
+path2 = 'data/'
+path3 = 'data_merge/'
+path4 = 'data_parse/'
+url1_private = "http://10.14.86.147:9081/device/auth"
+url2_private = "http://10.14.86.147:9081/device/data/callback"
+
+
+def add_hour(date_string, hour_number):
+    original_date = datetime.strptime(date_string, "%Y-%m-%d-%H-%M-%S")
+    new_date = original_date + timedelta(hours=hour_number)
+    return new_date.strftime("%Y-%m-%d-%H-%M-%S")
+
+
+'''
+cname:http://open-bucket.oss.icvdc.com
+内网endpoint: oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com
+oss桶名: open-bucket
+keyid:n8glvFGS25MrLY7j
+secret:xZ2Fozoarpfw0z28FUhtg8cu0yDc5d
+'''
+if __name__ == '__main__':
+    auth = oss2.Auth('n8glvFGS25MrLY7j', 'xZ2Fozoarpfw0z28FUhtg8cu0yDc5d')
+    endpoint = 'oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com'
+    bucket_name = 'pji-bucket1'
+    bucket = oss2.Bucket(auth, endpoint, bucket_name)
+    while True:
+        logging.info("开始新一轮扫描")
+        try:
+            local_delete_list = []
+            oss_delete_list = []
+            upload_completed_prefix_list = []
+            # 4 获取即将被合并的bag目录
+            for obj1 in oss2.ObjectIterator(bucket, prefix=key1):
+                try:
+                    if 'callback.json' in str(obj1.key):
+                        prefix = '/'.join(str(obj1.key).split('/')[:-1])
+
+                        file1 = False
+                        file2 = False
+                        file3 = False
+                        file4 = False
+                        file5 = False
+                        file7 = False
+                        file8 = False
+                        file9 = False
+                        for obj2 in oss2.ObjectIterator(bucket, prefix=prefix):
+                            if '/callback.json' in str(obj2.key):
+                                file1 = True
+                            if '/ego_pji.csv' in str(obj2.key):
+                                file2 = True
+                            if '/objects_pji.csv' in str(obj2.key):
+                                file3 = True
+                            if '/pcd_overlook.mp4' in str(obj2.key):
+                                file4 = True
+                            if '/pos_pji.csv' in str(obj2.key):
+                                file5 = True
+                            if '/scenario_orig.mp4' in str(obj2.key):
+                                file7 = True
+                            if '/simulation.xosc' in str(obj2.key):
+                                file8 = True
+                            if '/trajectory_pji.csv' in str(obj2.key):
+                                file9 = True
+                        if not file1 or not file2 or not file3 or not file4 or not file5 or not file7 or not file8 or not file9:
+                            continue
+                        time.sleep(1)
+                        logging.info("发送:%s", str(obj1.key))
+                        # 1 获取json内容
+                        json_content = bucket.get_object(str(obj1.key)).read()
+                        # 2 获取token
+                        json_object = json.loads(json_content)
+                        data1 = {
+                            "equipmentNo": json_object['equipmentNo'],
+                            "secretKey": json_object['secretKey']
+                        }
+                        json_data1 = json.dumps(data1)
+                        logging.info("授权接口请求中: %s" % url1_private)
+                        logging.info("授权发送参数为: %s" % str(data1))
+                        request1 = urllib2.Request(url1_private, json_data1,
+                                                   headers={'Content-Type': 'application/json'})
+                        response1 = urllib2.urlopen(request1)
+                        result_json1 = response1.read()
+                        result_object1 = json.loads(result_json1)
+                        logging.info("授权接口请求结果为: %s", result_object1)
+                        access_token = result_object1.get('data').get('accessToken')
+                        # 要发送的JSON参数
+                        try:
+                            # logging.info("bag文件为: %s", json_object['rosBagPath'])
+                            old_date = json_object['dataName']
+                            data_size = bucket.get_object_meta(json_object['rosBagPath']).content_length
+                            equipment_no = json_object['equipmentNo']
+                            old_file_path = json_object['filePath']
+                            old_ros_bag_path = json_object['rosBagPath']
+                            task_id = json_object['taskId']
+                            trigger_id = json_object['triggerId']
+                        except Exception as e:
+                            logging.exception("callback报错:%s", str(e))
+                            continue
+
+                        # 将时区统一(室外不需要需要加8,根据机器人终端的时区判断)
+                        # new_date = add_hour(old_date, 8)
+                        new_date = old_date
+                        old_delete_list = []
+                        for obj_old in oss2.ObjectIterator(bucket, prefix=old_file_path):
+                            old_delete_list.append(str(obj_old.key))
+                            if 'callback.json' in str(obj_old.key):
+                                bucket.copy_object(bucket_name, str(obj_old.key),
+                                                   str(obj_old.key).replace(old_date, new_date).replace('callback.json',
+                                                                                                        'callback_done.json'))
+                                bucket.delete_object(str(obj_old.key)) # 删除 callback.json
+                        # todo 时区不变也就不需要移动文件了
+                        #     else:
+                        #         bucket.copy_object(bucket_name, str(obj_old.key),
+                        #                            str(obj_old.key).replace(old_date, new_date))
+                        # bucket.copy_object(bucket_name, old_ros_bag_path, old_ros_bag_path.replace(old_date, new_date))
+                        # bucket.delete_object(old_ros_bag_path)
+                        # bucket.batch_delete_objects(old_delete_list)
+
+                        data2 = {
+                            "dataName": new_date,
+                            "dataSize": data_size,
+                            "equipmentNo": equipment_no,
+                            "filePath": old_file_path.replace(old_date, new_date),
+                            "rosBagPath": old_ros_bag_path.replace(old_date, new_date),
+                            "taskId": task_id,
+                            "triggerId": trigger_id
+                        }
+                        json_data2 = json.dumps(data2)
+                        logging.info("回调接口请求中:%s" % url2_private)
+                        request2 = urllib2.Request(url2_private, json_data2,
+                                                   headers={'Content-Type': 'application/json',
+                                                            'authorization': access_token})
+                        response2 = urllib2.urlopen(request2)
+                        result_json2 = response2.read()
+                        result_object2 = json.loads(result_json2)
+                        logging.info("回调接口请求结果为: %s", result_object2)
+                except Exception as e:
+                    logging.exception("局部异常处理: %s" % str(e))
+            time.sleep(2)
+        except Exception as e:
+            logging.exception("全局错误处理: %s" % str(e))

+ 2 - 0
src/python2/pjibot_patrol/callback-tail.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+tail -f log/callback.log

+ 8 - 0
src/python2/pjibot_patrol/camera-nohup.sh

@@ -0,0 +1,8 @@
+#!/bin/bash
+if [ ! -d "./log" ]; then
+    mkdir "./log"
+    echo "Directory './log' created."
+else
+    echo "Directory './log' already exists."
+fi
+nohup python2 camera-pjibot_patrol.py > log/camera.out 2>&1 &

+ 100 - 0
src/python2/pjibot_patrol/camera-pjibot_patrol.py

@@ -0,0 +1,100 @@
+# -*- coding: utf-8 -*-
+import os
+import time
+import oss2
+
+from resource import parse_robot_image
+
+import logging
+
+path1 = '/mnt/disk001/dcl_data_process/src/python2/pjibot_patrol/'
+
+logging.basicConfig(filename=path1 + 'log/camera.log', level=logging.INFO,
+                    format='%(asctime)s - %(levelname)s - %(message)s')
+
+key1 = 'pjibot_patrol/'
+sleep_time = 30  # 每多少秒扫描一次
+
+
+def parse_to_mp4(merged_bag_file_path, parse_prefix1, local_parse_dir2, local_delete_list3):
+    try:
+        flag,local_mp4_dir = parse_robot_image.parse(merged_bag_file_path,local_parse_dir2 + '/camera/')
+        if flag: # 没有话题就不生成视频了
+            mp4_file_name = 'camera'
+            local_mp4_file_path1 = local_mp4_dir + '/' + mp4_file_name + '.mp4'
+            local_delete_list3.append(local_mp4_file_path1)
+            oss_csv_object_key1 = parse_prefix1 + mp4_file_name + '.mp4'
+            bucket.put_object_from_file(oss_csv_object_key1, local_mp4_file_path1)
+        else:
+            logging.info("没有图像话题: %s", merged_bag_file_path)
+    except Exception as e2:
+        logging.exception("生成摄像头视频报错: %s", e2)
+
+
+# ------- 获取合并之后的bag包,解析出csv -------
+if __name__ == '__main__':
+    # 1 创建阿里云对象
+    auth = oss2.Auth('n8glvFGS25MrLY7j', 'xZ2Fozoarpfw0z28FUhtg8cu0yDc5d')
+    # cname = 'http://open-bucket.oss.icvdc.com'
+    # bucket = oss2.Bucket(auth, cname, 'open-bucket', is_cname=True)
+    endpoint = 'oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com'
+    bucket = oss2.Bucket(auth, endpoint, 'pji-bucket1')
+
+    while True:
+        logging.info("开始新一轮扫描")
+        try:
+            local_delete_list = []
+            oss_delete_list = []
+            prefix_list = []
+            # 2 获取已经上传完成的所有目录并分组
+            for obj1 in oss2.ObjectIterator(bucket, prefix=key1):
+                # 获取合并后的包
+                merged_bag_object_key = str(obj1.key)
+                # print(f'判断1{merged_bag_object_key}')
+                if 'data_merge' in str(obj1.key) and str(obj1.key).endswith('.bag'):
+                    merged_bag_object_key_split = merged_bag_object_key.split('/')
+                    merged_prefix = '/'.join(merged_bag_object_key_split[:-1])
+                    parse_prefix = merged_prefix.replace('data_merge', 'data_parse')
+                    parse_prefix_full = merged_bag_object_key.replace('data_merge', 'data_parse')[:-4] + '/'
+                    camera_done = False
+                    callback_done = False
+                    for obj2 in oss2.ObjectIterator(bucket, prefix=parse_prefix_full):
+                        if '/callback.json' in str(obj2.key):
+                            callback_done = True
+                        if '/camera.mp4' in str(obj2.key):
+                            camera_done = True
+                    if camera_done:
+                        continue
+                    if not callback_done:  # 不存在存在callback.json的就不处理了
+                        continue
+
+                    local_merged_bag_path = path1 + 'camera/' + merged_bag_object_key
+                    local_merged_dir = '/'.join(local_merged_bag_path.split('/')[:-1])
+                    local_parse_dir = local_merged_dir.replace('data_merge', 'data_parse')
+                    if not os.path.exists(local_merged_dir):
+                        os.makedirs(local_merged_dir)
+                    if not os.path.exists(local_parse_dir):
+                        os.makedirs(local_parse_dir)
+                    merged_bag_full_name = merged_bag_object_key_split[-1]
+                    merged_bag_name = merged_bag_full_name.split('.')[0]
+                    try:
+                        bucket.get_object_to_file(merged_bag_object_key, local_merged_bag_path)
+                    except Exception as e:
+                        logging.exception("下载合并后的bag包失败: %s" % str(e))
+
+                    local_delete_list.append(local_merged_bag_path)
+                    # 2 生成 pos_orig.csv 和 pos_hmi.csv
+                    logging.info("生成视频: %s" % str(obj1.key))
+                    parse_to_mp4(local_merged_bag_path, parse_prefix_full, local_parse_dir, local_delete_list)
+
+            # 删除本地临时文件
+            if len(local_delete_list) > 0:
+                for local_delete in local_delete_list:
+                    try:
+                        os.remove(local_delete)
+                    except Exception as e:
+                        pass
+                        # logging.exception("捕获到一个异常: %s" % str(e))
+            time.sleep(sleep_time)
+        except Exception as e:
+            logging.exception("全局错误处理: %s" % str(e))

+ 2 - 0
src/python2/pjibot_patrol/camera-tail.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+tail -f log/camera.log

+ 8 - 0
src/python2/pjibot_patrol/csv-nohup.sh

@@ -0,0 +1,8 @@
+#!/bin/bash
+if [ ! -d "./log" ]; then
+    mkdir "./log"
+    echo "Directory './log' created."
+else
+    echo "Directory './log' already exists."
+fi
+nohup python2 csv-pjibot_patrol.py > log/csv.out 2>&1 &

+ 174 - 0
src/python2/pjibot_patrol/csv-pjibot_patrol.py

@@ -0,0 +1,174 @@
+# -*- coding: utf-8 -*-
+import os
+import shutil
+import subprocess
+import time
+import oss2
+
+from resource import bagtocsv_robot
+
+import logging
+
+path1 = '/mnt/disk001/dcl_data_process/src/python2/pjibot_patrol/'
+path2 = '/mnt/disk001/dcl_data_process/src/python2/pjibot_patrol/resource/run/'
+path3 = '/mnt/disk001/dcl_data_process/src/python2/pjibot_patrol/csv/'
+logging.basicConfig(filename=path1 + 'log/csv.log', level=logging.INFO,
+                    format='%(asctime)s - %(levelname)s - %(message)s')
+
+key1 = 'pjibot_patrol/'
+sleep_time = 30  # 每多少秒扫描一次
+
+
+def parse_csv(data_bag, parse_prefix, local_parse_dir, local_delete_list):
+    try:
+        bagtocsv_robot.parse(data_bag, local_parse_dir + '/csv/')
+        bagname = data_bag.split('/')[-1].split('.')[0]
+        local_csv_dir = os.path.join(local_parse_dir + '/csv/', bagname)  # 最终生成四个csv文件的目录
+
+        csv_file_name1 = 'trajectory_pji'
+        local_csv_file_path1 = str(local_csv_dir) + '/' + str(csv_file_name1) + '.csv'
+        oss_csv_object_key1 = parse_prefix + csv_file_name1 + '.csv'
+        bucket.put_object_from_file(oss_csv_object_key1, local_csv_file_path1)
+
+        csv_file_name2 = 'ego_pji'
+        local_csv_file_path2 = str(local_csv_dir) + '/' + str(csv_file_name2) + '.csv'
+        local_delete_list.append(local_csv_file_path2)
+        oss_csv_object_key2 = parse_prefix + csv_file_name2 + '.csv'
+        bucket.put_object_from_file(oss_csv_object_key2, local_csv_file_path2)
+
+        csv_file_name3 = 'pos_pji'
+        local_csv_file_path3 = str(local_csv_dir) + '/' + str(csv_file_name3) + '.csv'
+        oss_csv_object_key3 = parse_prefix + csv_file_name3 + '.csv'
+        bucket.put_object_from_file(oss_csv_object_key3, local_csv_file_path3)
+
+        csv_file_name4 = 'objects_pji'
+        local_csv_file_path4 = str(local_csv_dir) + '/' + str(csv_file_name4) + '.csv'
+        oss_csv_object_key4 = parse_prefix + csv_file_name4 + '.csv'
+        bucket.put_object_from_file(oss_csv_object_key4, local_csv_file_path4)
+
+        # 生成pdf
+        try:
+            os.chdir(path2)
+            # 构造命令
+            command1 = ['./pji_outdoor_real',
+                        os.path.join(local_csv_dir, ''),  # 注意:这里可能不需要末尾的 '/',取决于程序要求
+                        os.path.join(local_csv_dir, ''),  # 同上
+                        os.path.join(local_csv_dir, 'trajectory.png'),
+                        bagname]
+
+            # 记录调用命令的信息
+            logging.info("调用生成pdf 报告命令: %s" % ' '.join(command1))
+
+            # 使用 subprocess.Popen 执行命令
+            process = subprocess.Popen(command1, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+            stdout, stderr = process.communicate()  # 等待命令执行完成
+
+            # 检查是否有输出或错误
+            if stdout:
+                logging.info("命令的标准输出:")
+                logging.info(stdout.decode('utf-8'))  # Python 2 中需要解码
+            if stderr:
+                logging.error("命令的错误输出:")
+                logging.error(stderr.decode('utf-8'))  # Python 2 中需要解码
+
+            # 检查命令是否成功执行
+            if process.returncode == 0:
+                logging.info("命令执行成功")
+            else:
+                logging.error("命令执行失败,退出码: %s" % process.returncode)
+
+        except OSError as e:
+            # 如果更改目录失败或命令不存在等
+            logging.error("在执行过程中发生错误: %s" % e)
+
+        oss_csv_object_key5 = parse_prefix + 'report.pdf'
+        bucket.put_object_from_file(oss_csv_object_key5, str(local_csv_dir) + '/report.pdf')
+        logging.info("pdf 报告生成并上传完成。")
+
+        # 记得删除
+        local_delete_list.append(local_csv_file_path1)
+        local_delete_list.append(local_csv_file_path2)
+        local_delete_list.append(local_csv_file_path3)
+        local_delete_list.append(local_csv_file_path4)
+        local_delete_list.append(str(local_csv_dir) + '/report.pdf')
+
+    except Exception as e2:
+        # 当出现异常时执行的代码
+        logging.exception("生成csv报错: %s", e2)
+
+
+# ------- 获取合并之后的bag包,解析出csv -------
+if __name__ == '__main__':
+    # 1 创建阿里云对象
+    auth = oss2.Auth('n8glvFGS25MrLY7j', 'xZ2Fozoarpfw0z28FUhtg8cu0yDc5d')
+    endpoint = 'oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com'
+    bucket = oss2.Bucket(auth, endpoint, 'pji-bucket1')
+    while True:
+        logging.info("开始新一轮扫描")
+        try:
+            local_delete_list = []
+            oss_delete_list = []
+            prefix_list = []
+            # 2 获取已经上传完成的所有目录并分组
+            for obj1 in oss2.ObjectIterator(bucket, prefix=key1):
+                # 获取合并后的包
+                merged_bag_object_key = str(obj1.key)
+                # print(f'判断1{merged_bag_object_key}')
+                if 'data_merge' in str(obj1.key) and str(obj1.key).endswith('.bag'):
+                    merged_bag_object_key_split = merged_bag_object_key.split('/')
+                    merged_prefix = '/'.join(merged_bag_object_key_split[:-1])
+                    parse_prefix = merged_prefix.replace('data_merge', 'data_parse')
+                    parse_prefix_full = merged_bag_object_key.replace('data_merge', 'data_parse')[:-4] + '/'
+                    callback_undone = False
+                    csv1_done = False
+                    csv2_done = False
+                    csv3_done = False
+                    csv4_done = False
+                    pdf_done = False
+                    for obj2 in oss2.ObjectIterator(bucket, prefix=parse_prefix_full):
+                        if '/callback.json' in str(obj2.key):
+                            callback_undone = True
+                        if '/trajectory_pji.csv' in str(obj2.key):
+                            csv1_done = True
+                        if '/ego_pji.csv' in str(obj2.key):
+                            csv2_done = True
+                        if '/pos_pji.csv' in str(obj2.key):
+                            csv3_done = True
+                        if '/objects_pji.csv' in str(obj2.key):
+                            csv4_done = True
+                        if '/report.pdf' in str(obj2.key):
+                            pdf_done = True
+                    if not callback_undone:  # 没有 callback.json
+                        continue
+                    if csv1_done and csv2_done and csv3_done and csv4_done and pdf_done:
+                        continue
+
+                    logging.info("开始生成场景还原csv: %s" % str(obj1.key))
+                    local_merged_bag_path = path3 + merged_bag_object_key
+                    local_merged_dir = '/'.join(local_merged_bag_path.split('/')[:-1])
+                    local_parse_dir = local_merged_dir.replace('data_merge', 'data_parse')
+                    if not os.path.exists(local_merged_dir):
+                        os.makedirs(local_merged_dir)
+                    if not os.path.exists(local_parse_dir):
+                        os.makedirs(local_parse_dir)
+                    merged_bag_full_name = merged_bag_object_key_split[-1]
+                    merged_bag_name = merged_bag_full_name.split('.')[0]
+                    try:
+                        bucket.get_object_to_file(merged_bag_object_key, local_merged_bag_path)
+                    except Exception as e:
+                        logging.exception("下载合并后的bag包失败: %s" % str(e))
+
+                    local_delete_list.append(local_merged_bag_path)
+                    # 2 生成 pos_orig.csv 和 pos_hmi.csv
+                    parse_csv(local_merged_bag_path, parse_prefix_full, local_parse_dir, local_delete_list)
+
+            # 删除本地临时文件
+            if len(local_delete_list) > 0:
+                for local_delete in local_delete_list:
+                    try:
+                        os.remove(local_delete)
+                    except Exception as e:
+                        logging.exception("捕获到一个异常: %s" % str(e))
+        except Exception as e:
+            logging.exception("全局错误处理: %s" % str(e))
+        time.sleep(sleep_time)

+ 2 - 0
src/python2/pjibot_patrol/csv-tail.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+tail -f log/csv.log

+ 8 - 0
src/python2/pjibot_patrol/merge-nohup.sh

@@ -0,0 +1,8 @@
+#!/bin/bash
+if [ ! -d "./log" ]; then
+    mkdir "./log"
+    echo "Directory './log' created."
+else
+    echo "Directory './log' already exists."
+fi
+nohup python2 merge-pjibot_patrol.py > log/merge.out 2>&1 &

+ 125 - 0
src/python2/pjibot_patrol/merge-pjibot_patrol.py

@@ -0,0 +1,125 @@
+# -*- coding: utf-8 -*-
+import os
+import time
+import oss2
+from rosbag import Bag, Compression
+import logging
+import rosbag
+from std_msgs.msg import Header
+import rospy
+
+path1 = '/mnt/disk001/dcl_data_process/src/python2/pjibot_patrol/'
+
+logging.basicConfig(filename=path1 + 'log/merge.log', level=logging.INFO,
+                    format='%(asctime)s - %(levelname)s - %(message)s')
+
+key1 = 'pjibot_patrol/'
+key2 = 'data/'
+key3 = 'data_merge/'
+key4 = 'data_parse/'
+
+sleep_time = 5  # 每多少秒扫描一次
+compress_way = Compression.BZ2
+
+
+# local_bags 合并前的包
+# merged_prefix oss路径
+# local_merged_dir 本地路径
+# 包名
+def merge(local_bags, merged_prefix, local_merged_dir, merged_bag_name):
+    try:
+        output_bag_file = local_merged_dir + merged_bag_name
+        with Bag(output_bag_file, 'w', compression=compress_way) as o:
+            for i in range(len(local_bags)):
+                with Bag(local_bags[i], 'r') as ib:
+                    for topic, msg, t in ib:
+                        o.write(topic, msg, t)
+        bucket.put_object_from_file(merged_prefix + merged_bag_name, output_bag_file)
+        return output_bag_file
+    except Exception as e:
+        logging.exception("bag包合并报错: %s" % str(e))
+
+
+'''
+cname:http://pji-bucket1.oss.icvdc.com
+内网endpoint: oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com
+keyid:n8glvFGS25MrLY7j
+secret:xZ2Fozoarpfw0z28FUhtg8cu0yDc5d
+oss桶名: pji-bucket1
+oss桶名: oss://pji-bucket1
+'''
+# ------- 获取未合并的bag包,合并 -------
+if __name__ == '__main__':
+    # 1 创建阿里云对象
+    auth = oss2.Auth('n8glvFGS25MrLY7j', 'xZ2Fozoarpfw0z28FUhtg8cu0yDc5d')
+    endpoint = 'oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com'
+    bucket = oss2.Bucket(auth, endpoint, 'pji-bucket1')
+    while True:
+        logging.info("开始新一轮扫描")
+        try:
+            prefix_list = []
+            # 2 获取已经上传完成的所有目录并分组
+            upload_completed_prefix_list = []
+            for obj1 in oss2.ObjectIterator(bucket, prefix=key1, delimiter='/'):
+                bag_list = []
+                target_path = ''
+                if str(obj1.key).count('/') == 2:  # pujin/robot-01/
+                    # 6 校验bag包个数
+                    for obj2 in oss2.ObjectIterator(bucket, prefix=str(obj1.key) + key2, delimiter='/'):
+                        if str(obj2.key).count(
+                                '/') == 4:  # pujin/robot-01/data/2023-12-20-02-16-56_obstacledetection_10/
+                            bag_need = str(obj2.key).split('_')[-1][:-1]
+                            count_bag = 0
+                            for obj3 in oss2.ObjectIterator(bucket, prefix=str(obj2.key)):
+                                if obj3.key[-3:] == 'bag':
+                                    count_bag = count_bag + 1
+                            if bag_need == str(count_bag):
+                                upload_completed_prefix_list.append(obj2.key)
+            # 处理
+            for prefix in upload_completed_prefix_list:
+                local_delete_list = []
+                oss_delete_list = []
+                # 获取要处理的包
+                oss_bags = []
+                local_bags = []
+                for obj in oss2.ObjectIterator(bucket, prefix=prefix):
+                    if str(obj.key).endswith('.bag'):
+                        oss_bags.append(str(obj.key))
+                split_list = prefix.replace(key2, key3).split('/')
+                merged_prefix = '/'.join(split_list[0:-2]) + '/'
+                local_merged_dir = path1 + merged_prefix
+                if not os.path.exists(local_merged_dir):
+                    os.makedirs(local_merged_dir)
+                merged_bag_name = split_list[-2]
+                merged_bag_full_name = merged_bag_name + '.bag'
+                local_bag_dir = path1 + '/'.join(split_list[0:-1]) + '/'
+                if not os.path.exists(local_bag_dir):
+                    os.makedirs(local_bag_dir)
+
+                # 下载
+                for oss_bag in oss_bags:
+                    bag_name = str(oss_bag).split('/')[-1]
+                    local_bag_path = local_bag_dir + bag_name
+                    bucket.get_object_to_file(oss_bag, local_bag_path)
+                    local_bags.append(local_bag_path)
+                    local_delete_list.append(local_bag_path)
+                    oss_delete_list.append(oss_bag)
+
+                # 1 合并bag
+                logging.info("合并文件,key前缀为: %s" % str(local_merged_dir))
+                merged_bag_file_path = merge(local_bags, merged_prefix, local_merged_dir, merged_bag_full_name)
+                local_delete_list.append(merged_bag_file_path)
+                # 删除本地临时文件
+                if len(local_delete_list) > 0:
+                    for local_delete in local_delete_list:
+                        try:
+                            os.remove(local_delete)
+                        except Exception as e:
+                            logging.exception("删除本地临时文件报错: %s" % str(e))
+
+                # 删除oss原始文件
+                if len(oss_delete_list) > 0:
+                    bucket.batch_delete_objects(oss_delete_list)
+            time.sleep(sleep_time)
+        except Exception as e:
+            logging.exception("全局错误处理: %s" % str(e))

+ 2 - 0
src/python2/pjibot_patrol/merge-tail.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+tail -f log/merge.log

+ 8 - 0
src/python2/pjibot_patrol/pcd-nohup.sh

@@ -0,0 +1,8 @@
+#!/bin/bash
+if [ ! -d "./log" ]; then
+    mkdir "./log"
+    echo "Directory './log' created."
+else
+    echo "Directory './log' already exists."
+fi
+nohup python2 pcd-pjibot_patrol.py > log/pcd.out 2>&1 &

+ 97 - 0
src/python2/pjibot_patrol/pcd-pjibot_partol.py

@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+import os
+import time
+import oss2
+
+from resource import pcdtovideo_monitor_overlook
+
+import logging
+
+path1 = '/mnt/disk001/dcl_data_process/src/python2/pjibot_patrol/'
+logging.basicConfig(filename=path1 + 'log/pcd.log', level=logging.INFO,
+                    format='%(asctime)s - %(levelname)s - %(message)s')
+
+key1 = 'pjibot_patrol/'
+path1 = '/root/'
+sleep_time = 30  # 每多少秒扫描一次
+
+
+def parse_to_pcd_mp4(merged_bag_file_path, parse_prefix2, local_parse_dir, local_delete_list):
+    global bucket
+    try:
+        local_pcd_mp4_dir = pcdtovideo_monitor_overlook.parse(merged_bag_file_path, local_parse_dir + '/pcd/')
+        pcd_mp4_file_name = 'pcd_overlook'
+        local_delete_list.append(str(local_pcd_mp4_dir) + '/pcd_overlook.mp4')
+        oss_csv_object_key3 = parse_prefix2 + pcd_mp4_file_name + '.mp4'
+        bucket.put_object_from_file(oss_csv_object_key3, str(local_pcd_mp4_dir) + '/' + pcd_mp4_file_name + '.mp4')
+        logging.info("上传点云视频到: %s", oss_csv_object_key3)
+    except Exception as e:
+        logging.exception("生成点云视频报错: %s" % str(e))
+
+
+'''
+cname:http://open-bucket.oss.icvdc.com
+内网endpoint: oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com
+oss桶名: open-bucket
+keyid:n8glvFGS25MrLY7j
+secret:xZ2Fozoarpfw0z28FUhtg8cu0yDc5d
+'''
+# ------- 获取合并之后的bag包,解析出csv -------
+if __name__ == '__main__':
+    # 1 创建阿里云对象
+    auth = oss2.Auth('n8glvFGS25MrLY7j', 'xZ2Fozoarpfw0z28FUhtg8cu0yDc5d')
+    endpoint = 'oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com'
+    bucket = oss2.Bucket(auth, endpoint, 'pji-bucket1')
+    while True:
+        logging.info("开始新一轮扫描")
+        try:
+            local_delete_list = []
+            oss_delete_list = []
+            prefix_list = []
+            # 2 获取已经上传完成的所有目录并分组
+            for obj1 in oss2.ObjectIterator(bucket, prefix=key1):
+                try:
+                    # 获取合并后的包
+                    merged_bag_object_key = str(obj1.key)
+                    if 'data_merge' in str(obj1.key) and str(obj1.key).endswith('.bag'):
+                        merged_bag_object_key_split = merged_bag_object_key.split('/')
+                        merged_prefix = '/'.join(merged_bag_object_key_split[:-1])
+                        parse_prefix = merged_prefix.replace('data_merge', 'data_parse')
+                        parse_prefix_full = merged_bag_object_key.replace('data_merge', 'data_parse')[:-4] + '/'
+                        pcd_done = False
+                        callback_done = False
+                        for obj2 in oss2.ObjectIterator(bucket, prefix=parse_prefix_full):
+                            if '/callback.json' in str(obj2.key):
+                                callback_done = True
+                            if '/pcd_overlook.mp4' in str(obj2.key):
+                                pcd_done = True
+                        if not callback_done:
+                            continue
+                        if pcd_done:
+                            continue
+                        logging.info("%s 需要生成点云视频 pcd_overlook.mp4" % str(parse_prefix_full))
+                        local_merged_bag_path = path1 + 'pcd/' + merged_bag_object_key
+                        local_merged_dir = '/'.join(local_merged_bag_path.split('/')[:-1])
+                        local_parse_dir = local_merged_dir.replace('data_merge', 'data_parse')
+                        if not os.path.exists(local_merged_dir):
+                            os.makedirs(local_merged_dir)
+                        if not os.path.exists(local_parse_dir):
+                            os.makedirs(local_parse_dir)
+                        merged_bag_full_name = merged_bag_object_key_split[-1]
+                        merged_bag_name = merged_bag_full_name.split('.')[0]
+                        bucket.get_object_to_file(merged_bag_object_key, local_merged_bag_path)
+                        local_delete_list.append(local_merged_bag_path)
+                        # 2 生成 pos_orig.csv 和 pos_hmi.csv
+                        parse_to_pcd_mp4(local_merged_bag_path, parse_prefix_full, local_parse_dir, local_delete_list)
+                except Exception as e:
+                    logging.exception("报错: %s" % str(e))
+            # 删除本地临时文件
+            if len(local_delete_list) > 0:
+                for local_delete in local_delete_list:
+                    try:
+                        os.remove(local_delete)
+                    except Exception as e:
+                        logging.exception("删除本地临时文件报错: %s" % str(e))
+            time.sleep(sleep_time)
+        except Exception as e:
+            logging.exception("全局异常处理: %s" % str(e))

+ 2 - 0
src/python2/pjibot_patrol/pcd-tail.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+tail -f log/pcd.log

+ 0 - 0
src/python2/pjibot_patrol/resource/__init__.py


+ 214 - 0
src/python2/pjibot_patrol/resource/bagtocsv_robot.py

@@ -0,0 +1,214 @@
+# coding: utf-8
+#!/usr/bin/env python2
+import os
+import rosbag
+import csv
+import math 
+import rospy
+import sys
+import time
+import numpy as np
+from datetime import datetime
+import argparse
+import pandas as pd
+
+
+def quaternion_to_euler(x, y, z, w):
+    # 将四元数归一化
+    try:
+        length = np.sqrt(x**2 + y**2 + z**2 + w**2)
+        x /= length
+        y /= length
+        z /= length
+        w /= length
+    
+        # 计算欧拉角
+        #roll = np.arctan2(2*(w*x + y*z), 1 - 2*(x**2 + y**2))
+        #pitch = np.arcsin(2*(w*y - z*x))
+        yaw = np.arctan2(2*(w*z + x*y), 1 - 2*(y**2 + z**2))  
+        return  yaw
+    except :
+        return 0
+
+
+
+def parsehancheng(input_dir, output_dir):   
+    dic_trajectory = ['Time','simTime','simFrame','PointNumber','posX','posY','posZ','posH',
+    'TargetX','TargetY','TargetZ','TargetH']
+    trajectory_file = open(output_dir + "/"+"trajectory_pji.csv", 'w')
+    writer_trajectory = csv.writer(trajectory_file)
+    writer_trajectory.writerow(dic_trajectory)
+    
+    dic_EgoState = ['Time','simTime','simFrame','posX','posY','posZ','posH','speedX','speedH','cmd_speedX','cmd_speedH','obstacle','task_error_code']
+    
+    EgoState_file = open(output_dir + "/"+"ego_pji.csv", 'w')
+    
+    writer_EgoState = csv.writer(EgoState_file)
+    writer_EgoState.writerow(dic_EgoState)
+
+    dic_robot_pos = ['Time','simtime','FrameID','HeadingAngle','X', 'Y' ,'Z']
+    robot_pos_file = open(output_dir + "/"+"pos_pji.csv", 'w')
+    writer_robot_pos = csv.writer(robot_pos_file)
+    writer_robot_pos.writerow(dic_robot_pos)
+
+    dic_objects = ['Time','simtime','FrameID','playerId','posH','posX', 'posY' ,'posZ','label','dimX','dimY','dimZ',
+                   'speedX','speedY','speedZ','speedH_X','speedH_Y','speedH_Z','accelX','accelY','accelZ','accelH_X','accelH_Y','accelH_Z']
+    objects_file = open(output_dir + "/"+"objects_pji.csv", 'w')
+    writer_objects = csv.writer(objects_file)
+    writer_objects.writerow(dic_objects)
+
+    frame_max=sys.maxsize
+    with rosbag.Bag(input_dir ,'r') as bag:
+        #wheel_odom_flag=False
+        #cmd_vel_flag=False
+        first_message_time = None
+        Frame_robot_pose=1
+        obstacle_state=0
+        speed_linear=0
+        speed_angular=0
+        cmd_speed_angular=0
+        cmd_speed_linear=0
+        first_message_time = None
+        framenum_ego = 1
+        task_error_code=0
+        #framenum_obj = 1
+        locationsimtime=' '
+        date_time=' '
+        simFrame=1
+        ego_posx,ego_posy,ego_posz,ego_posH=0,0,0,0
+        for topic,msg,t in bag.read_messages(topics=['/obstacle_detection','/wheel_odom','/cmd_vel','/robot_pose','/tracking/objects','/nav/task_feedback_info','/robot/final_trajectory']):   
+            
+            if first_message_time is None:  
+                first_message_time = t
+                first_message_time = rospy.Time.to_sec(first_message_time)
+                first_message_time = datetime.fromtimestamp(first_message_time)
+            
+            if topic == "/obstacle_detection":
+                obstacle_state=msg.data
+                #print(msg.data)
+
+
+            if topic == "/wheel_odom": 
+                #wheel_odom_flag=True 
+                speed_linear=msg.twist.twist.linear.x*3.6
+                speed_angular=msg.twist.twist.angular.z
+
+                
+            if topic == "/cmd_vel": 
+                #cmd_vel_flag=True
+                cmd_speed_linear=msg.linear.x*3.6
+                cmd_speed_angular=msg.angular.z
+                
+            if topic == "/nav/task_feedback_info":
+                task_error_code=msg.task_error_code
+                
+            if topic == "/robot_pose":
+                
+                timestamp = rospy.Time.to_sec(t)
+                date_time = datetime.fromtimestamp(timestamp)
+                locationsimtime=(date_time-first_message_time).total_seconds()
+                ego_posx=msg.pose.position.x
+                poseX=ego_posx-88.96626338170609
+                ego_posy=msg.pose.position.y
+                poseY=ego_posy-40.553671177476645
+                poseZ=msg.pose.position.z
+                orientationX=msg.pose.orientation.x
+                orientationY=msg.pose.orientation.y
+                orientationZ=msg.pose.orientation.z
+                orientationW=msg.pose.orientation.w
+                egoyaw=quaternion_to_euler(orientationX,orientationY,orientationZ,orientationW)
+                message_location =[date_time,locationsimtime,framenum_ego,egoyaw,poseX,poseY,poseZ]    
+                #print(f'date_time={date_time},  locationtime={locationsimtime}')
+                writer_robot_pos.writerow(message_location)
+                #if wheel_odom_flag and cmd_vel_flag:
+                message_EgoState =[date_time,locationsimtime,Frame_robot_pose,poseX,poseY,poseZ,egoyaw,
+                                   speed_linear,speed_angular,cmd_speed_linear,cmd_speed_angular,obstacle_state,task_error_code]
+             
+                writer_EgoState.writerow(message_EgoState)
+                framenum_ego+=1
+                Frame_robot_pose+=1
+
+        
+            if topic == "/tracking/objects":
+                msg_l = len(msg.objects)
+                if msg_l and (locationsimtime != ' ') and (date_time != ' '):
+                    #timestamp = rospy.Time.to_sec(t)
+                    #date_time = datetime.fromtimestamp(timestamp)
+                    #simtime=(date_time-first_message_time).total_seconds()
+                    for i in range(msg_l):
+                        obj_ID = msg.objects[i].id
+                        obj_x = msg.objects[i].pose.position.x-88.96626338170609
+                        obj_y = msg.objects[i].pose.position.y-40.553671177476645
+                        obj_z = msg.objects[i].pose.position.z
+                        obj_orientationX=msg.objects[i].pose.orientation.x
+                        obj_orientationY=msg.objects[i].pose.orientation.y
+                        obj_orientationZ=msg.objects[i].pose.orientation.z
+                        obj_orientationW=msg.objects[i].pose.orientation.w
+                        objyaw=quaternion_to_euler(obj_orientationX,obj_orientationY,obj_orientationZ,obj_orientationW)
+                        obj_lable=msg.objects[i].label
+                        obj_dimX=msg.objects[i].dimensions.x
+                        obj_dimY=msg.objects[i].dimensions.y
+                        obj_dimZ=msg.objects[i].dimensions.z
+                        velocity_linear_x=msg.objects[i].velocity.linear.x
+                        velocity_linear_y=msg.objects[i].velocity.linear.y
+                        velocity_linear_z=msg.objects[i].velocity.linear.z
+                        
+                        velocity_angular_x=msg.objects[i].velocity.angular.x
+                        velocity_angular_y=msg.objects[i].velocity.angular.y
+                        velocity_angular_z=msg.objects[i].velocity.angular.z
+                        
+                        acceleration_linear_x=msg.objects[i].acceleration.linear.x
+                        acceleration_linear_y=msg.objects[i].acceleration.linear.y
+                        acceleration_linear_z=msg.objects[i].acceleration.linear.z
+                        
+                        acceleration_angular_x=msg.objects[i].acceleration.angular.x
+                        acceleration_angular_y=msg.objects[i].acceleration.angular.y
+                        acceleration_angular_z=msg.objects[i].acceleration.angular.z
+                        
+                        message_obj =[date_time,locationsimtime,Frame_robot_pose,obj_ID,objyaw,obj_x,obj_y,obj_z,obj_lable,obj_dimX,obj_dimY,obj_dimZ,
+                                      velocity_linear_x,velocity_linear_y,velocity_linear_z,velocity_angular_x,velocity_angular_y,
+                                      velocity_angular_z,acceleration_linear_x,acceleration_linear_y,acceleration_linear_z,
+                                      acceleration_angular_x,acceleration_angular_y,acceleration_angular_z]
+                        #print(f'{date_time},  {locationsimtime}')
+                        writer_objects.writerow(message_obj)
+                    #framenum_obj+=1 
+            if topic == "/robot/final_trajectory":
+                PointNumber=1
+                timestamp1 = rospy.Time.to_sec(t)
+                date_time1 = datetime.fromtimestamp(timestamp1)
+                locationsimtime1=(date_time1-first_message_time).total_seconds()
+                if ego_posx!=0 or ego_posy!=0:
+                    for i in range(len(msg.waypoints)):
+                        Targetx=msg.waypoints[i].pose.pose.position.x
+                        Targety=msg.waypoints[i].pose.pose.position.y
+                        Targetz=msg.waypoints[i].pose.pose.position.z
+                        orientationX=msg.waypoints[i].pose.pose.orientation.x
+                        orientationY=msg.waypoints[i].pose.pose.orientation.y
+                        orientationZ=msg.waypoints[i].pose.pose.orientation.z
+                        orientationW=msg.waypoints[i].pose.pose.orientation.w
+                        TargetH=quaternion_to_euler(orientationX,orientationY,orientationZ,orientationW)
+                        message_trajectory =[date_time1,locationsimtime1,simFrame,PointNumber,ego_posx,ego_posy,poseZ,egoyaw,Targetx,Targety,Targetz,TargetH]
+                        writer_trajectory.writerow(message_trajectory)
+                        PointNumber+=1
+                    simFrame+=1
+                
+        robot_pos_file.close()
+        objects_file.close()
+        EgoState_file.close()
+        trajectory_file.close()
+        
+        
+
+def parse(input_dir, output_dir):
+   #input_dir='/media/dell/HIKSEMI/pji_DGNC/pjioutrobot_2024-08-21-15-12-04.bag'
+   #output_dir='/media/dell/HIKSEMI/pji_DGNC'
+   # input_dir=sys.argv[1]
+   # output_dir = sys.argv[2]
+   bagname=input_dir.split('/')[-1].split('.')[0]
+
+   
+   output_dir=os.path.join(output_dir, bagname)
+   if not os.path.exists(output_dir):
+       os.makedirs(output_dir)
+   parsehancheng(input_dir, output_dir)
+

+ 73 - 0
src/python2/pjibot_patrol/resource/parse_robot_image.py

@@ -0,0 +1,73 @@
+# coding: utf-8
+# !/usr/bin/env python2
+
+import sys
+
+import os
+import rospy
+import rosbag
+import csv
+import cv2
+from cv_bridge import CvBridge, CvBridgeError
+import argparse
+import struct
+import subprocess
+from subprocess import Popen, PIPE
+
+bridge = CvBridge()
+
+
+def parsebag(f, output_dir, target_topic):
+    rosbag_name = f.split("/")[-1].split(".")[0]
+    output_path = os.path.join(output_dir, rosbag_name)
+    camera_exist_flag = False
+
+    with rosbag.Bag(f, 'r') as bag:
+        count = 0
+        start_time = bag.get_start_time()
+        end_time = bag.get_end_time()
+        duration = end_time - start_time
+        print('duration', duration)
+        topics = bag.get_type_and_topic_info()[1].keys()
+        if target_topic in topics:
+            for topic, msg, t in bag.read_messages(topics=[target_topic]):
+                camera_exist_flag = True
+                img = bridge.imgmsg_to_cv2(msg, 'bgr8')
+                img_resized = cv2.resize(img, (1920, 1080))
+                # img = bridge.compressed_imgmsg_to_cv2(msg, 'bgr8')
+                timestr = msg.header.stamp.to_nsec()
+                image_name = str(timestr) + ".jpg"
+                if not os.path.exists(output_path + '_' + 'image'):
+                    os.makedirs(output_path + '_' + 'image')
+                output_path_img = os.path.join(output_path + '_' + 'image', image_name)
+                cv2.imwrite(output_path_img, img_resized)
+                # print(count)
+                count = count + 1
+
+    return count, duration, camera_exist_flag
+
+
+def parse(input_dir, output_dir):
+    # input_dir=sys.argv[1]
+    # output_dir = sys.argv[2]
+    topic = '/image_raw'  # /camera/color/image_raw
+
+    num_count, duration, flag = parsebag(input_dir, output_dir, topic)
+
+    if flag:
+        dirt = os.path.join(output_dir, input_dir.split('/')[-1].split('.')[0] + '_' + 'image')
+        bagtime = duration
+        hz = str(float(num_count) / bagtime)
+        print('bagtime=', bagtime)
+        print('num_count=', num_count)
+
+        command = ['ffmpeg', '-f', 'image2', '-r', hz, '-pattern_type', 'glob', '-i'] + [dirt + '/*.jpg'] + ['-tag:v',
+                                                                                                             'avc1',
+                                                                                                             '-y'] + [
+                      dirt + '/camera.mp4']
+        p = Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        p.communicate()
+        print('done')
+        return flag, dirt
+    else:
+        return flag, ''

+ 132 - 0
src/python2/pjibot_patrol/resource/pcdtovideo_monitor_overlook.py

@@ -0,0 +1,132 @@
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+"""
+Created on Wed Nov  1 13:38:28 2023
+
+@author: dell
+"""
+from __future__ import print_function
+import subprocess
+from subprocess import Popen, PIPE
+import os
+import sys
+import math
+import cv2
+import numpy as np
+import shutil
+import rosbag
+from multiprocessing import Pool
+import datetime
+
+
+def draw_points(pic, filename):
+    colormap = np.array([[128, 130, 120], 
+             [235, 0, 205], 
+             [0, 215, 0], 
+             [235, 155, 0]]) / 255.0 
+    f = open(filename, "r")
+    ff = f.readlines()[11:]
+
+    for i in range(0, len(ff)):
+        point = ff[i].split()[:4]
+        point_x = float(point[0])
+        point_y = -float(point[1])
+        point_z = float(point[2])
+        points_intensity = float(point[2])
+        if math.isnan(point_x):
+            pass
+        else:
+            cv2.circle(pic, (int(800 - point_x * 10), int(400 - point_y * 10)), 0, colormap[int(points_intensity) % colormap.shape[0]]*255, 2)
+
+def process_file(file):
+
+    root = file[0]
+    inputFilePath = root + "/" + file[1]
+    tempFilePath = root[:-3] + "pcd_ascii/" + file[1]
+    outputFilePath = root[:-3] + "jpg/" + file[1][:-3] + "jpg"
+
+    command = "pcl_convert_pcd_ascii_binary " + inputFilePath + " " + tempFilePath + " 0"
+    os.system(command)
+
+    if not os.path.exists(tempFilePath):
+        return
+
+    pic = np.zeros([800, 1600, 3])
+    draw_points(pic, tempFilePath)
+    cv2.imwrite(outputFilePath, pic)
+
+
+
+
+def parse(input_dir, output_dir):
+    s_time=datetime.datetime.now()
+    #input_dir = sys.argv[1]
+    # input_dir='/media/dell/HIKSEMI/2024-09-06-11-54-36.bag'
+    #output_dir = sys.argv[2]
+    # output_dir = '/media/dell/HIKSEMI'
+
+
+    bag_name = input_dir.split('/')[-1].split('.')[0]
+    output_dir = os.path.join(output_dir, bag_name + '_pcd' + '/pcd')
+    if not os.path.exists(output_dir):
+        os.makedirs(output_dir)
+    
+    with rosbag.Bag(input_dir, 'r') as bag:
+        num_count = 0
+        for topic, msg, t in bag.read_messages():
+            if topic == "/velodyne_points": #/camera/depth/points   # /scan_map_icp_amcl_node/scan_point_transformed
+                num_count += 1
+        start_time = bag.get_start_time()
+        end_time = bag.get_end_time()
+        # 计算rosbag的持续时间
+        duration = end_time - start_time
+
+    bagtime = duration
+    hz = str(float(float(num_count) / bagtime))
+    print(hz)
+    
+    #######################解析rosbag中的点云point_concat话题,获得原始pcd文件#######################
+    command = ['rosrun', 'pcl_ros', 'bag_to_pcd'] + [input_dir] + ['/velodyne_points'] + [output_dir]
+    command = ' '.join(command)
+    os.system(command)
+    file1 = os.path.join(output_dir[0:-4], 'pcd_ascii')
+    file2 = os.path.join(output_dir[0:-4], 'jpg')
+    if not os.path.exists(file1):
+        os.makedirs(file1)
+    if not os.path.exists(file2):
+        os.makedirs(file2)
+    
+    #######################将原始pcd文件转化成pcd-ascii格式,并生成jpg文件#######################
+    # Create a list of files to be processed
+    files_to_process = []
+    for root, dirs, files in os.walk(output_dir[:-4]):
+        for file in files:
+            if file.endswith(".pcd"):
+                files_to_process.append((root, file))
+    
+
+    num_processes = 4
+
+    pool = Pool(num_processes)
+    pool.map(process_file, files_to_process)
+    pool.close()
+    pool.join()
+    
+    #######################将转化的点云jpg合成视频#######################
+    jpg_list = os.listdir(file2)
+    if not jpg_list == []:
+        command = ['ffmpeg', '-f', 'image2', '-r', hz, '-pattern_type', 'glob', '-i'] + ['"jpg/*.jpg"'] + ['-tag:v',
+                                                                                                           'avc1',
+                                                                                                           '-y'] + [
+                      'pcd_overlook.mp4']
+        result_string = " ".join(command)
+        p = Popen(result_string, shell=True, cwd=output_dir[0:-4] + '/', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+        p.wait()
+    
+    e_time=datetime.datetime.now()
+    print("using "+str(e_time-s_time)+ "s")
+    #shutil.rmtree(file1)
+    #shutil.rmtree(file2)
+    #shutil.rmtree(output_dir)
+    return output_dir[0:-4]
+

+ 8 - 0
src/python2/pjibot_patrol/simulation-nohup.sh

@@ -0,0 +1,8 @@
+#!/bin/bash
+if [ ! -d "./log" ]; then
+    mkdir "./log"
+    echo "Directory './log' created."
+else
+    echo "Directory './log' already exists."
+fi
+nohup python2 simulation-pjibot_patrol.py > log/simulation.out 2>&1 &

+ 180 - 0
src/python2/pjibot_patrol/simulation-pjibot_partol.py

@@ -0,0 +1,180 @@
+# -*- coding: utf-8 -*-
+import os
+import time
+import oss2
+import xml.etree.ElementTree as ET
+import shutil
+import docker
+import logging
+
+key1 = 'pjibot_patrol/'
+path1 = '/scenarios4/'
+path2 = '/mnt/disk001/dcl_data_process/src/python2/pjibot_patrol/'
+path3 = '/mnt/disk001/dcl_data_process/src/python2/pjibot_patroly/resource/'
+vehicle_name = 'PuJin_distribution'  # 配送 PuJin_distribution 巡检 PuJin_patrol_robot
+
+logging.basicConfig(filename=path2 + 'log/simulation.log', level=logging.INFO,
+                    format='%(asctime)s - %(levelname)s - %(message)s')
+
+sleep_time = 60  # 每多少秒扫描一次
+
+
+def move_xosc_before_simulation(root_path):
+    try:
+
+        xodr = 'thq_1116.xodr'
+        osgb = 'thq_1116.opt.osgb'
+
+        tree1 = ET.parse(root_path + 'scenario_orig.xosc')
+        root1 = tree1.getroot()
+        for node0 in root1:
+            if node0.tag == 'RoadNetwork':
+                for node1 in node0:
+                    # 打印根元素的标签名
+                    src_file_prefix = path3
+                    if 'LogicFile' == node1.tag:
+                        if xodr in node1.get('filepath'):
+                            dst_file = root_path + xodr
+                            shutil.copy(src_file_prefix + xodr, dst_file)
+                            node1.set('filepath', dst_file)
+                        if xodr in node1.get('filepath'):
+                            dst_file = root_path + xodr
+                            shutil.copy(src_file_prefix + xodr, dst_file)
+                            node1.set('filepath', dst_file)
+                        if xodr in node1.get('filepath'):
+                            dst_file = root_path + xodr
+                            shutil.copy(src_file_prefix + xodr, dst_file)
+                            node1.set('filepath', dst_file)
+                    if 'SceneGraphFile' == node1.tag:
+                        if osgb in node1.get('filepath'):
+                            dst_file = root_path + osgb
+                            shutil.copy(src_file_prefix + osgb, dst_file)
+                            node1.set('filepath', dst_file)
+                        if osgb in node1.get('filepath'):
+                            dst_file = root_path + osgb
+                            shutil.copy(src_file_prefix + osgb, dst_file)
+                            node1.set('filepath', dst_file)
+                        if osgb in node1.get('filepath'):
+                            dst_file = root_path + osgb
+                            shutil.copy(src_file_prefix + osgb, dst_file)
+                            node1.set('filepath', dst_file)
+            if node0.tag == 'Entities':
+                for node1 in node0:
+                    if node1.get("name") == 'Ego':
+                        for node2 in node1:
+                            if node2.tag == 'Vehicle':
+                                node2.set('name', vehicle_name)
+        tree1.write(root_path + 'openx0.xosc')
+
+    except Exception as e:
+        logging.exception("修改xosc报错: %s" % str(e))
+
+
+def upload_simulation(parse_prefix, mp41):
+    try:
+        bucket.put_object_from_file(parse_prefix + 'scenario_orig.mp4', mp41)
+        logging.info('上传仿真视频到 %s' % parse_prefix + 'scenario_orig.mp4')
+        shutil.rmtree(path1)  # 仿真完就删除
+    except Exception as e:
+        logging.exception("上传视频报错 %s" % str(e))
+
+
+def simulation(parse_prefix, mp41):
+    try:
+        os.system("docker start vtd4")
+        # 实例化Docker客户端
+        client = docker.from_env()
+        while True:
+            time.sleep(5)
+            # 获取容器列表
+            containers = client.containers.list()
+            run = False
+            # 打印容器列表
+            for container in containers:
+                if 'vtd4' == container.name:
+                    run = True
+                    break
+            if not run:
+                break
+        time.sleep(5)
+        upload_simulation(parse_prefix, mp41)
+    except Exception as e:
+        logging.exception("生成仿真视频报错 %s" % str(e))
+
+
+def is_upload_completed(bucket, prefix):
+    target_number = str(prefix).split('_')[-1][:-1]
+    count = 0
+    for obj in oss2.ObjectIterator(bucket, prefix=prefix):
+        if obj.key != prefix:
+            count += 1
+    return int(count) == int(target_number)
+
+
+'''
+cname:http://open-bucket.oss.icvdc.com
+keyid:n8glvFGS25MrLY7j
+secret:xZ2Fozoarpfw0z28FUhtg8cu0yDc5d
+oss桶名: oss://open-bucket
+
+oss桶名: open-bucket
+内网endpoint: oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com
+'''
+# ------- 获取合并之后的bag包,解析出csv -------
+if __name__ == '__main__':
+    # 1 创建阿里云对象
+    auth = oss2.Auth('n8glvFGS25MrLY7j', 'xZ2Fozoarpfw0z28FUhtg8cu0yDc5d')
+    endpoint = 'oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com'
+    bucket = oss2.Bucket(auth, endpoint, 'pji-bucket1')
+    while True:
+        try:
+            logging.info("开始新一轮扫描")
+            local_delete_list = []
+            oss_delete_list = []
+            prefix_list = []
+            # 2 获取已经上传完成的所有目录并分组
+            for obj1 in oss2.ObjectIterator(bucket, prefix=key1):
+                try:
+                    # 获取合并后的包
+                    merged_bag_object_key = str(obj1.key)
+                    if 'data_merge' in str(obj1.key) and str(obj1.key).endswith('.bag'):
+                        merged_bag_object_key_split = merged_bag_object_key.split('/')
+                        merged_prefix = '/'.join(merged_bag_object_key_split[:-1])
+                        parse_prefix = merged_prefix.replace('data_merge', 'data_parse')
+                        parse_prefix_full = merged_bag_object_key.replace('data_merge', 'data_parse')[:-4] + '/'
+                        xosc_done = False
+                        mp4_done = False
+                        for obj3 in oss2.ObjectIterator(bucket, prefix=str(parse_prefix_full)):
+                            if '/simulation.xosc' in str(obj3.key):
+                                xosc_done = True
+                            if '/scenario_orig.mp4' in str(obj3.key):
+                                mp4_done = True
+                        if not xosc_done:
+                            continue
+                        if mp4_done:
+                            continue
+                        logging.info("需要生成仿真视频: %s" % str(parse_prefix_full))
+                        parse_prefix_full = str(parse_prefix_full)
+                        local_dir_full = path1 + parse_prefix_full
+                        if not os.path.exists(local_dir_full):
+                            os.makedirs(local_dir_full)
+                        # 下载两个csv
+                        root_path1 = local_dir_full + 'orig/'
+                        if not os.path.exists(root_path1):
+                            os.makedirs(root_path1)
+                        bucket.get_object_to_file(parse_prefix_full + 'simulation.xosc', root_path1 + 'scenario_orig.xosc')
+                        local_delete_list.append(root_path1 + 'scenario_orig.xosc')
+                        move_xosc_before_simulation(root_path1)
+                        simulation(parse_prefix_full, root_path1 + 'simulation.mp4')
+                except Exception as e:
+                    logging.exception("局部异常处理: %s", str(e))
+            # 删除本地临时文件
+            if len(local_delete_list) > 0:
+                for local_delete in local_delete_list:
+                    try:
+                        os.remove(local_delete)
+                    except Exception as e:
+                        pass
+            time.sleep(sleep_time)
+        except Exception as e:
+            logging.exception("全局异常处理: %s", str(e))

+ 2 - 0
src/python2/pjibot_patrol/simulation-tail.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+tail -f log/simulation.log

+ 8 - 0
src/python2/pjibot_patrol/xosc-nohup.sh

@@ -0,0 +1,8 @@
+#!/bin/bash
+if [ ! -d "./log" ]; then
+    mkdir "./log"
+    echo "Directory './log' created."
+else
+    echo "Directory './log' already exists."
+fi
+nohup python2 xosc-pjibot_patrol.py > log/xosc.out 2>&1 &

+ 97 - 0
src/python2/pjibot_patrol/xosc-pjibot_partol.py

@@ -0,0 +1,97 @@
+# -*- coding: utf-8 -*-
+import os
+import time
+import oss2
+import logging
+
+path1 = '/mnt/disk001/dcl_data_process/src/python2/pjibot_patrol/'
+path2 = '/mnt/disk001/dcl_data_process/src/python3/pjibot_outdoor/'
+
+logging.basicConfig(filename=path1 + 'log/xosc.log', level=logging.INFO,
+                    format='%(asctime)s - %(levelname)s - %(message)s')
+
+key1 = 'pjibot_patrol/'
+sleep_time = 60  # 每多少秒扫描一次
+
+
+def generate_xosc(parse_prefix, local_parse_dir, local_delete_list):
+    try:
+        os.chdir(path2)
+        command2 = 'python3 jiqiren_outdoor.py ' + local_parse_dir[:-1] + ' 0'  # 配送机器人0 巡检机器人1
+        logging.info("调用命令2: %s" % str(command2))
+        os.system(command2)
+        local_xosc_path2 = local_parse_dir + 'simulation/xosc/openx_outdoor0.xosc'
+        bucket.put_object_from_file(parse_prefix + 'simulation.xosc', local_xosc_path2)
+        logging.info("上传 simulation.xosc 成功: %s" % str(parse_prefix + 'simulation.xosc'))
+        local_delete_list.append(local_xosc_path2)
+    except Exception as e:
+        logging.exception("生成xosc报错: %s" % str(e))
+
+
+'''
+cname:http://open-bucket.oss.icvdc.com
+内网endpoint: oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com
+oss桶名: open-bucket
+keyid:n8glvFGS25MrLY7j
+secret:xZ2Fozoarpfw0z28FUhtg8cu0yDc5d
+'''
+# ------- 获取合并之后的bag包,解析出csv -------
+if __name__ == '__main__':
+    # 1 创建阿里云对象
+    auth = oss2.Auth('n8glvFGS25MrLY7j', 'xZ2Fozoarpfw0z28FUhtg8cu0yDc5d')
+    endpoint = 'oss-cn-beijing-gqzl-d01-a.ops.gqzl-cloud.com'
+    bucket = oss2.Bucket(auth, endpoint, 'pji-bucket1')
+    while True:
+        try:
+            logging.info("开始新一轮扫描")
+            local_delete_list = []
+            oss_delete_list = []
+            prefix_list = []
+            # 2 获取已经上传完成的所有目录并分组
+            for obj1 in oss2.ObjectIterator(bucket, prefix=key1):
+                try:
+                    # 获取合并后的包
+                    merged_bag_object_key = str(obj1.key)
+                    if 'data_merge' in str(obj1.key) and str(obj1.key).endswith('.bag'):
+                        merged_bag_object_key_split = merged_bag_object_key.split('/')
+                        merged_prefix = '/'.join(merged_bag_object_key_split[:-1])
+                        parse_prefix = merged_prefix.replace('data_merge', 'data_parse')
+                        parse_prefix_full = merged_bag_object_key.replace('data_merge', 'data_parse')[:-4] + '/'
+                        xosc_done = False
+                        csv1_done = False
+                        csv2_done = False
+                        for obj3 in oss2.ObjectIterator(bucket, prefix=str(parse_prefix_full)):
+                            if '/simulation.xosc' in str(obj3.key):
+                                xosc_done = True
+                            if '/objects_pji.csv' in str(obj3.key):
+                                csv1_done = True
+                            if '/pos_pji.csv' in str(obj3.key):
+                                csv2_done = True
+                        if xosc_done:
+                            logging.info("存在simulation.xosc: %s" % str(parse_prefix_full))
+                            continue
+                        if not csv1_done:
+                            logging.info("不存在/objects_pji.csv: %s" % str(parse_prefix_full))
+                            continue
+                        if not csv2_done:
+                            logging.info("不存在/pos_pji.csv: %s" % str(parse_prefix_full))
+                            continue
+                        logging.info("需要生成simulation.xosc: %s" % str(parse_prefix_full))
+                        local_dir_full = path1 + parse_prefix_full
+                        if not os.path.exists(local_dir_full):
+                            os.makedirs(local_dir_full)
+                        bucket.get_object_to_file(parse_prefix_full + 'objects_pji.csv', local_dir_full + 'objects_pji.csv')
+                        bucket.get_object_to_file(parse_prefix_full+'pos_pji.csv', local_dir_full+'pos_pji.csv')
+                        generate_xosc(parse_prefix_full, local_dir_full, local_delete_list)
+                except Exception as e:
+                    logging.exception("局部异常处理: %s", str(e))
+            # 删除本地临时文件
+            if len(local_delete_list) > 0:
+                for local_delete in local_delete_list:
+                    try:
+                        os.remove(local_delete)
+                    except Exception as e:
+                        logging.exception("删除本地临时文件报错: %s" % str(e))
+            time.sleep(sleep_time)
+        except Exception as e:
+            logging.exception("全局异常处理: %s", str(e))

+ 2 - 0
src/python2/pjibot_patrol/xosc-tail.sh

@@ -0,0 +1,2 @@
+#!/bin/bash
+tail -f log/xosc.log