大疆上云API示例代码部署小记

  最近接手了一个项目,在不增加新的预算的前提下,实现将大疆无人机里拍摄的照片自动上传到服务器。

  上其官网研究了一翻,再加上几个好友的沟通,目前已知有两种方法,一种是使用MSDK,自己开发一个APP安装到手柄上,自行实现照片下载至手柄与上传至服务器。第二种则是使用上云API,自己开发服务端,按协议要求实现指定接口实现图传。两种方案的差异可由下图所示。由于大疆已提供服务端样例,加之目前需求非常简单,故采用方案二。

 

  一、准备上云API

  首先,上大疆官网注册,先注册开发者账号,再注册APP,过程不详述,最后可得到APP的ID、KEY、License,备用。

  对于我来讲,使用docker模式更容易实现产品部署。首先,在服务器上下载样例包。

axel -n 20 https://terra-sz-hc1pro-cloudapi.oss-cn-shenzhen.aliyuncs.com/c0af9fe0d7eb4f35a8fe5b695e4d0b96/docker/cloud_api_sample_docker.zip

 

  解压至同名目录

unzip cloud_api_sample_docker.zip

 

  二、编排Minio

  目前上云API是将图片存储在对像存储器中,私有化方案目前只能选择minio。本处采用docker-compose方式布署。首先将docker源更新为国内源,加快拉取速度。打开配置文件

sudo ne /etc/docker/daemon.json

 

  将国内常见的源地址加入

{
  "data-root": "/opt/docker",
  "registry-mirrors": ["https://hub-mirror.c.163.com/", "https://dockerproxy.com/", "https://quay.mirrors.ustc.edu.cn"]
}

 

  最后,更新系统环境变量并重启

sudo systemctl daemon-reload
sudo systemctl restart docker

 

  打开解压后根目录下现有编排文件 docker-compose.yml  ,将minio段添加进入,并加入相同网桥与启动依赖

services:
  cloud_api_sample:
    depends_on:
      - minio
  minio:
    image: "minio/minio:latest"
    ports:
      - "9000:9000"
      - "9001:9001"
    volumes:
      - "/opt/minio/data:/data1"
      - "/opt/minio/config:/data2"
    environment:
      - MINIO_ROOT_USER=minioadmin
      - MINIO_ROOT_PASSWORD=minioadmin
    command: server --console-address ":9001" /data1
    hostname: cloud_api_sample_minio
    networks:
      - cloud_service_bridge

 

  三、部署官网组件

  将根目录的镜像加载至docker中,里面包含了mysql、redis等组件

sudo docker load < cloud_api_sample_docker_v1.1.0.tar

 

  修改后端配置文件 cloud_api_sample/source/backend_service/sample/src/main/resources/application.yml ,为mysql、redis、mqtt配置访问ip。docker-compose编排文件中使用桥接方式指定的网段为 192.168.6.0/24 ,所以宿主机分配的ip为 192.168.6.1,为cloud-api配置前面申请的id、key、license。oss启用minio,其endpoint需配成宿主机固有的ip。由于不存在直播需求,将livestream中的gb28181配置节注释,否则系统启动报错。

spring:
  datasource:
    druid:
      url: jdbc:mysql://192.168.6.1:3306/cloud_sample?useSSL=false&allowPublicKeyRetrieval=true

  redis:
    host: 192.168.6.1

mqtt:
  BASIC:
    host: 192.168.6.1
  DRC:
    host: 192.168.6.1

oss:
  endpoint: http://192.168.192.254:9000

cloud-api:
  app:
    id: 按需
    key:按需 
    license: 按需


livestream:
  url:
#    gb28181:
#      serverIP: Please enter the server ip.
#      serverPort: Please enter the server port.
#      serverID: Please enter the server id.
#      agentID: Please enter the agent id.
#      agentPassword: Please enter the agent password.
#      localPort: Please enter the local port.
#      channel: Please enter the channel.
#
#    # Webrtc: Only supports using whip standard

 

  为了加快编译速度,建议将maven源修改为国内。打开 cloud_api_sample/source/backend_service/pom.xml ,增加 repositories 配置节,我实际配置为阿里源,如下所示

<project>
……

    <repositories>  
        <repository>  
          <id>aliyun</id>  
          <name>aliyun</name>  
          <url>https://maven.aliyun.com/repository/public/</url>  
          <releases>  
            <enabled>true</enabled>  
          </releases>  
          <snapshots>  
            <enabled>false</enabled>  
          </snapshots>  
        </repository>  
      </repositories>  
      <pluginRepositories>  
        <pluginRepository>  
          <id>aliyunPlugin</id>  
          <name>aliyunPlugin</name>  
          <url>https://maven.aliyun.com/repository/public/</url>  
          <releases>  
            <enabled>true</enabled>  
          </releases>  
          <snapshots>  
            <enabled>false</enabled>  
          </snapshots>      
        </pluginRepository>  
      </pluginRepositories>

</project>

 

  修改镜像打包文件 cloud_api_sample/source/backend_service/Dockerfile ,使用2倍线程数打包jar包,实测可加快30%的打包速度。

RUN mvn clean package -T 2C -Dmaven.test.skip=true

 

  完成上述修改后,在解压根目录下执行后台编译命令

./update_backend.sh

 

  修改前端配置文件 cloud_api_sample/source/nginx/front_page/src/api/http/config.ts ,为license节配置前面申请的id、key、license。为http节配置客户端访问后台服务的基地址及webSocket基地址(需配成宿主机固有的ip)。目前不存在直播需求,不需配置livestreaming节。配置高德地图Web端应用key,相关知识可自行查阅。

// license
appId: '按需', // You need to go to the development website to apply.
appKey: '按需', // You need to go to the development website to apply.
appLicense: '按需', // You need to go to the development website to apply.

// http
baseURL: 'http://192.168.192.254:6789/', // This url must end with "/". Example: 'http://192.168.1.1:6789/'
websocketURL: 'ws://192.168.192.254:6789/api/v1/ws', // Example: 'ws://192.168.1.1:6789/api/v1/ws'

// map
amapKey: '按需',

 

  为修复编译错误,打开 cloud_api_sample/source/nginx/front_page/package-lock.json ,将所有 https://registry.nlark.com/ 统一替换为 https://registry.npmmirror.com/ 。

  完成上述修改后,在解压根目录下执行前台编译命令

./update_front.sh

 

  网站默认采用8080端口访问。如服务器中已有冲突,可修改根目录下 dock-compose.yml 文件参数调整为合适端口。如下方修改为8088。

services:
  nginx:
    ports:
      - "8088:8080"

 

  最后,在解压根目录下执行启动命令

sudo docker-compose up -d

 

  四、修改界面标题

  在交付使用前,需要将界面上显示的如 Test 或 Demo等字样替换为客户实际名称。

  打开数据库表 manage_workspace ,将workspace_name、workspace_desc、platform_name修改为实际的工作空间名、工作空间描述、平台名称,这里可影响web端的logo名称,遥控器pilot 2主界面云端名称显示,云端界面标题及界面显示。

  打开前端代码文件 cloud_api_sample/source/nginx/front_page/index.html,修改第7行title标签内容,可影响web端网页标题

  打开 cloud_api_sample/source/nginx/front_page/src/pages/page-web/index.html,修改第8行p标签内容,可影响web端登录界面系统名称

  打开 cloud_api_sample/source/nginx/front_page/src/pages/page-pilot/pilot-index.html,修改第7行p标签内容,可影响遥控器端pilot 2登录界面系统名称。遥控器无缓存清理功能,如果使用后再更新代码,可能会出现编译后文件名依然一样,然后遥控器依然读取本地缓存的情况。这个时候可通过反复增减空格等方式修改文件然后编译,直至编译后文件名不同,并配合nginx添加请求头强制让浏览器所有缓存过期,达到更新遥控器本地缓存的目的。

 

  五、模拟测试

  首选测试minio可用性。在引入 MinIO Java SDK、Hotool工具集后,在resources/imgs下存放图片,则使用如下代码可实现文件的上传下载删除。

private static String url = "http://192.168.192.254:9000";
private static String accessKey = "minioadmin";
private static String secretKey = "minioadmin";
private static String bucketName = "cloud-bucket";
private static String regionName = "us-east-1";

try (MinioClient minioClient = MinioClient.builder()
        .endpoint(url).credentials(accessKey, secretKey).build();
        Scanner sc = new Scanner(System.in);) {

    System.out.println("开始执行");
    // 上传文件
    for (File file : FileUtil.loopFiles("imgs")) {
        UploadObjectArgs upArgs = UploadObjectArgs.builder().bucket(bucketName)
                .object(file.getName()).filename(file.getAbsolutePath())
                .build();
        minioClient.uploadObject(upArgs);
        System.out.println("上传图片:" + file.getName());
    }

    System.out.println("图片已上传完毕");
    sc.nextLine();

    // 下载文件
    ListObjectsArgs listArgs = ListObjectsArgs.builder()
            .bucket(bucketName).recursive(true).build();
    List<DeleteObject> delList = new LinkedList<>();
    for (Result<Item> item : minioClient.listObjects(listArgs)) {
        DownloadObjectArgs downArgs = DownloadObjectArgs.builder()
                .bucket(bucketName).object(item.get().objectName())
                .filename(item.get().objectName().replace("/", "_"))
                .overwrite(true).build();
        minioClient.downloadObject(downArgs);
        delList.add(new DeleteObject(item.get().objectName()));
        System.out.println("下载图片:" + item.get().objectName());
    }
    System.out.println("图片已下载完毕");
    sc.nextLine();

    // 删除文件
    RemoveObjectsArgs reArgs = RemoveObjectsArgs.builder().bucket(bucketName).objects(delList).build();
    for (Result<DeleteError> error : minioClient.removeObjects(reArgs)) {
        System.out.println(error.get().message());
    }

    System.out.println("图片已删除完毕");
    sc.nextLine();

    System.out.println("结束执行");
}

 

  在上云方面,使用工具连上mysql数据库,在media_file表中插入对应图片数据。以1.jpg为例,插入语句如下

INSERT INTO `cloud_sample`.`media_file` (`id`, `file_id`, `file_name`, `file_path`, `workspace_id`, `fingerprint`, `tinny_fingerprint`, `object_key`, `sub_file_type`, `is_original`, `drone`, `payload`, `job_id`, `create_time`, `update_time`) VALUES (1, '7858e36e-d62d-41dd-bee9-824521e6c810', '1.jpg', 'b', 'e3dea0f5-37f2-4d79-ae58-490af3228069', '', '', '1.jpg', NULL, 1, '3', '4', '5', 1719893248236, 1719893248236);

 

  使用上述代码上传图片1.jpg,并在库中插入上述数据后,登录上云API,进入 Workspace -> Media Files页面,即可看到1.jpg图片数据。点击Action下的按钮如下载成功,则说明上云API与minio连通成功。

 

  六、域名访问

  上述描述均为直接使用ip访问的场景,即无人机遥控器、上云API、minio、管理端电脑均在内网。可通过如下修改,使其支持外网域名访问。

  首先,修改 cloud_api_sample/source/nginx/default.conf 文件,建议所有外网请求均通过相同端口接收,然后通过不同地址转发至不同服务。如下示例中,在原有基础上, sample管理后台接口请求(注意其 proxy_pass 必须已斜杠结尾,使转发后的地址将不附带sample段), /api/v1/ws 管理ws请求,如下所示:

server {
    listen   8080 default_server;
    server_name  "";

    error_log /var/log/nginx/error.log;
    access_log /var/log/nginx/access.log main;

    location /sample/ {
        proxy_pass http://192.168.6.1:6789/;
        #proxy_set_header Host $host;
        #proxy_set_header X-Real-IP $remote_addr;
        #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }

    location /api/v1/ws {
        proxy_pass http://192.168.6.1:6789/api/v1/ws;
        proxy_http_version 1.1;  
        proxy_set_header Upgrade $http_upgrade;  
        proxy_set_header Connection "Upgrade"; 
        #proxy_set_header Host $host;
        #proxy_set_header X-Real-IP $remote_addr;
        #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
    
    #location /minio/ {  #cloud-bucket
    #    proxy_pass http://192.168.6.1:9000/;
    #    proxy_set_header Host $http_host;
    #    #proxy_set_header X-Real-IP $remote_addr;
    #    #proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    #}
    
    location / {
        #expires -1;
        #add_header Cache-Control "private, no-store, no-cache, must-revalidate, proxy-revalidate";
        proxy_set_header X-Forwarded-For $remote_addr;
        root /home/vue_server/;
        try_files $uri $uri/ /index.html;
    }
}

 

  与之对应的,前端配置文件 config.ts 中,其 baseURL 与 websocketURL 需修改为域名,注意 baseURL需增加/sample/地址段用于nginx转发识别,所下所示:

baseURL: 'http://域名:端口/sample/', // This url must end with "/". Example: 'http://192.168.1.1:6789/'
websocketURL: 'ws://域名:端口/api/v1/ws', // Example: 'ws://192.168.1.1:6789/api/v1/ws'

 

  后端配置文件 application.yml 中,将对像存储oss的 endPoint 修改为域名,将mqtt的 host 与 port修改为域名。注意,此域名需保证后台服务也能访问。由于nginx是将根目录转发到前端,非根目录的http或ws请求转发到后台,mqtt是处理tcp请求,oss(minio)不允许在endpoint中配置路径,导致上传文件的地址是在根目录与nginx有冲突,这三者需要使用不同的端口号。

mqtt:
  BASIC:
    host: 域名
    port: 端口

oss: endpoint: http:
//域名:端口

 

  七、无人机连接

  完成上述准备后,打开无人机及遥控器,使两者之间正常连接,然后打开遥控器飞控软件 DJI Pilot 2, 上云功能区默认显示Not Logged In即未登录,点击后界面将跳转至地址页,如下图所示:

 

  在URL输入框中输入上云后台地址,格式为http://地址:端口/pilot-login,基于配置地址为域名或ip均可,然后点击右上角的connection按钮。如下图所示

 

  界面将跳到至登录页,输入用户名与密码后点击蓝色Login按钮,如下图所示

 

 

  登录成功后,遥控器会发送mqtt消息,服务端收到后会回复mqtt消息,遥控器收到后即完成连接,自动读取并显示遥控器云端SN号与无人机SN号,如下图所示:

 

  点击Device Binding按钮,系统跳转至绑定界面,点击Bind按钮后实现无人机与云端的绑定,方便后续操作。

 

  点击左上角的 Test Group One 按钮,可以查看各个模块的连接信息,显示绿色的 Connected 则表示已完成连接初始化。

 

 

  八、无人机传图

  在主界面点击Media File Upload按钮,进入图像传输配置页面,如下图所示:

 

  打开 Auto Photo Upload开关,选择默认的Original Photo选择,实现原始图像的自动上传。(默认已打开)

 

   当拍摄后,图库里的照片将自动传输至云端,如拍摄界面的左上侧红框显示,上下小箭头消失后即上传完成。

 

  可在云端查看上传的照片,如照片所示

 

  如果不想自动传输,则关闭选项后,进入图库后,点击打开需要上传的照片,将自动实现上传,右下角显示上传进度,当到达100%时,完成上传。

 

  依然可在云端查看上传的照片,如照片所示

 

  点击明细后可在云端查看图片

 

参考

上云API官方文档

上云API基本介绍

零基础小白本地部署大疆上云api(个人记录供参考)

centos 7 端口占用查看进程、根据进程名称查询进程信息、根据进程编号查询进程信息、杀掉进程操作

linux rhel虚拟机中如何给磁盘动态扩容(硬盘直接扩展)

Linux - 通过LVM对磁盘进行动态扩容 (Linux的逻辑卷)

maven 开启使用多线程打包

修改Docker容器内文件的三种方式

Docker 仓库国内镜像加速源(2024年3月21日)

Docker compose快速部署minio服务

docker-compose 搭建 minio 分布式对象存储 最新版(使用教程)

Java整合minio实现文件预览上传和下载

[docker] 浅谈Docker:网络模式及从容器内部访问宿主机的IP地址

docker容器访问宿主服务的几种方式

nginx中斜杠(‘/‘)总结

minio报错SignatureDoesNotMatch解决方案

docker安装 MinIO对象存储(已解决 走nginx代理情况下, SignatureDesNotMatch签名不一致问题)

Nginx配置域名反向代理MQTT 配置mqtt /ws /wss访问域名连接。

no path allowed in endpoint http://my-ip-address:9000/xxx/

nginx服务器上发布的新版本代码总需要清除浏览器缓存问题

posted @ 2024-07-09 16:19  永远的阿哲  阅读(17)  评论(0编辑  收藏  举报