实时传输 RVC v1.0

更新时间:2025-01-24 08:25:49下载pdf

本文详细介绍基于 tuyaos_robot_rvc_sdk 激光扫地机的实时地图与路径传输的业务流程、API 及地图坐标系说明。

业务介绍

对于激光扫地机,目前支持三种类型的文件:

  • 全量地图文件
  • 清扫路径文件
  • AI 物体识别文件

缩略图数据及原始高清图片属于 AI 物体识别的能力,需要扫地机硬件上带有摄像头功能。开发者根据硬件条件,可在业务上选配。

业务流程说明

扫地机实时文件传输

涂鸦 AppTuyaOS SDK应用创建独立线程周期性循-序异步发送数据到App客户端(根据机器的运-行状态或者地图及路径-更新情况来判断是否继-续周期性传输数据)通过 RVC_TRANS_EVENT_CB回调传递开始传输的状态通过 ty_rvc_rt_map_send_v2发送地图数据发送文件数据回复发送结果通过ty_rvc_rt_cleanpath_send_v2发送路径数据发送文件数据回复发送结果通过ty_rvc_rt_ai_thumbnails_send发送缩略图数据发送文件数据回复发送结果下发原始高清图片文件名通过 original_sets_handler回调,传递原始高清图片文件名称给-业务端通过 ty_rvc_ai_original_send发送原始高清图片数据发送文件数据回复发送结果通过 RVC_TRANS_EVENT_CB回调传递结束传输的状态后应用暂停-传输涂鸦 AppTuyaOS SDK应用
  • 由于上述接口都是阻塞模式上报,应用上需要在独立线程中异步调用实时地图、路径、缩略图及原始高清图片传输接口。
  • 实时地图、路径及缩略图的上报,开发者只需要关心注册 TuyaOS SDK 的状态回调 ty_rvc_event_cb,状态只有两种:开始结束
  • 原始高清图片的上报,开发者需要结合 App 下发的文件名 aiHD_XXXX_YYYY.bin,通过 TuyaOS SDK 传输到应用端。其中 XXXX_YYYY 是真实的物体坐标点,应用上根据真实的坐标点获取正确的原始高清图片数据,并调用发送原始高清图片数据接口,上报给 App 。

数据类型

OBJECT_POINT_S

/**
 * @brief Structure for coordinate points
 */
typedef struct {
    int x; // X value of the coordinate point
    int y; // Y value of the coordinate point
} OBJECT_POINT_S;

RVC_AI_OBJECT_THUMBNAILS_INFO

/**
 * @brief AI thumbnail data structure
 */
typedef struct {
    int map_id; // Map ID
    int object_num; // Number of objects
    OBJECT_POINT_S* points; // Points of objects
    int* object_type; // Recognized objects
    int* accuracy; // Recognition accuracy, report FF if not used
} RVC_AI_OBJECT_THUMBNAILS_INFO;

RVC_AI_OBJECT_THUMBNAILS_INFO 结构体用来存放一张地图上所有物体的坐标、类型及准确率。

AI_OBJECTS_TYPE_E

/**
 * @brief Names of recognized objects
 */
typedef enum {
    OBJECTS_TYPE_WIRE = 0, // Wire
    OBJECTS_TYPE_SHOES, // Shoes
    OBJECTS_TYPE_SOCKS, // Socks
    OBJECTS_TYPE_TOYS, // Toys
    OBJECTS_TYPE_CHAIR, // Chair
    OBJECTS_TYPE_TABLE, // Table
    OBJECTS_TYPE_TRASH_CAN, // Trash can
    OBJECTS_TYPE_POTTED_PLANT, // Potted plant
    OBJECTS_TYPE_OTHER, // Other
    OBJECTS_TYPE_MAX,
} AI_OBJECTS_TYPE_E;

物体类型 TuyaOS SDK 只定义了标准的几种方式,开发者如有新增的物体类型,需要在 OBJECTS_TYPE_OTHER 之后增加,并且需要与面板端的物体类型定义对齐。

RVC_MAP_HEAD_INFO_S

/**
 * @brief Parameters for the map protocol header of the vacuum cleaner
 */
typedef struct {
    unsigned short map_id;           // Map ID
    int status;                      // Map status, 0 indicates unstable, 1 indicates stable
    int height;                      // Height of the map in pixels
    int width;                       // Width of the map in pixels
    int resolution;                  // Map resolution (width/length of each grid), reported as original value, unit: meters
    POINT_COOR_S origin;             // Machine origin X/Y coordinates, given relative to the screen coordinate system, reported as original value
    POINT_COOR_S charge_point;       // Charging station X/Y coordinates, given relative to the screen coordinate system, reported as original value
    int charge_angle;                // Orientation of the charging station
} RVC_MAP_HEAD_INFO_S;

RVC_MAP_HEAD_INFO_S 是地图数据 RVC_MAP_DATA_S 结构体中的成员,表示扫地机地图数据的头部参数。

PATH_POINT_S

typedef struct {
    int type;                //path point type
    POINT_COOR_S coordinates;  //Path coordinate array, given with reference to the machine coordinate system
} PATH_POINT_S;

RVC_PATH_INFO_S

/**
 * @brief Parameters for the path protocol of the vacuum cleaner
 */
typedef struct {
    unsigned short path_id;           // path ID Roadmap identification for a complete sweep
    int type;                        //0x01 full path (normal mode) ,0x02 full path (complex mode), 0x03 Navigation path
    int count;                       // Total number of waypoints (full)
    int direction;                   // Device Heading Angle
    PATH_POINT_S*path_point;        //Path coordinate array, given with reference to the machine coordinate system, the original value  is reported 
} RVC_PATH_INFO_S;

RVC_PATH_INFO_S 结构体是地图路径数据,请参考 地图及路径数据结构说明

MAP_OBS_E

/**
 * @brief Pixel Point Types
 */
typedef enum {
    OBS_FREE = 0, // Background Area
    OBS_IS,       // Obstacle
    OBS_CARPET,   // Carpet Area
    OBS_CLEAN,    // Cleaning Area
    OBS_UNKNOW,   // Unknown Area
    OBS_CHARGE_ST, // Charging Station
} MAP_OBS_E;

MAP_OBS_E 是地图中像素点的枚举值。

svc_robot_point_s

/**
 * @brief Point in the corresponding coordinate system
 */
struct svc_robot_point_s {
    float x;    // X-axis coordinate in the corresponding coordinate system, unit: meters
    float y;    // Y-axis coordinate in the corresponding coordinate system, unit: meters
    float z;    // Z-axis coordinate in the corresponding coordinate system, unit: meters
};

room_polygon_s

/**
 * @brief Polygon parameters
 */
struct room_polygon_s {
    struct svc_robot_point_s* points;   // Polygon points
    int points_size;                    // Number of points
};

RVC_ROOM_POLYGON_S

/** 
 * @brief Area polygon parameters
 */
typedef struct {
    int id;                                                 // Area ID
    struct room_polygon_s polygon;      // Polygon
} RVC_ROOM_POLYGON_S;

RVC_ROOM_POLYGON_S 结构体用来存放多房间边界栅格坐标点信息,需要申请结构体的内存空间。注意该结构体内的 polygon 成员是个指针,需要给该指针对象赋值。

RVC_MAP_DATA_S

/**
 * @brief map data structer
 */
typedef struct{
    RVC_MAP_HEAD_INFO_S header;  //Parameters for the map protocol header of the vacuum cleaner
    unsigned char** map_buff;  //Pixel data on the map
    int room_polygons_count;   //Number of Room Zones
    RVC_ROOM_POLYGON_S* room_polygons_data;  //Area polygon parameters
}RVC_MAP_DATA_S;

RVC_MAP_DATA_S 结构体是用来存放一张地图数据,结构体成员包含地图开头固定数据、像素点数据、房间分区数量及边界栅格坐标点数据。

API 接口

初始化媒体流服务

用于流媒体服务初始化。只有调用了该接口,才能正常的进行实时地图及路径的传输。

/**
 * @brief real time map and path treans cb
 */
typedef INT_T (*RVC_TRANS_EVENT_CB)(IN CONST int onoff);

/***********************************************************
 *@Function: tuya_sdk_media_server_init
 *@brief  initialize media server init
 *@param[in] handler The status callback for real-time data transmission, 
             with statuses including: start and end.
 *@return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 ***********************************************************/

OPERATE_RET ty_rvc_server_init(RVC_TRANS_EVENT_CB handler);

参数说明

参数 说明
handler 实时地图及路径传输状态,开发者可根据状态值来判断是否开始上报数据

实时地图数据上报接口

将实时地图结构化数据发送给 App 端显示,详细请参照 设备角度说明

/***********************************************************
 *@function: ty_rvc_rt_map_send_v2
 *@brief:  Send real-time structured map data to the app
 *@param[in] map_info: map data, including fixed header data, pixel data, 
                       the number of room zones, and boundary grid coordinate point data.
 *@return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 ** *********************************************************/
OPERATE_RET ty_rvc_rt_map_send_v2(RVC_MAP_DATA_S* map_info)

参数说明

参数 说明
map_info 地图数据,具体请参考 RVC_MAP_DATA_S 结构体

针对以上入参,详细请参照 地图及路径数据结构说明

当开发者需要清空 App 端显示的地图时,调用该接口上报空地图。关于空地图的格式,在 RVC_MAP_DATA_S 结构体中:

  • header 成员赋值 0
  • map_buff 成员赋值 NULL
  • room_polygons_data 成员赋值 NULL
  • room_polygons_count 成员赋值 0

实时路径数据上报接口

将实时路径结构化数据发送给 App 端显示。

/***********************************************************
 *@function: ty_rvc_rt_cleanpath_send
 *@brief send realtime cleanpath data to app
 *@param[in] path_info: realtime path data which is need to be upload
 *@return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 ***********************************************************/
OPERATE_RET ty_rvc_rt_cleanpath_send_v2(IN RVC_PATH_INFO_S* path_info);

参数说明

参数 说明
path_infof 实时路径数据的内容 ,详细请参照 地图及路径数据结构说明

当开发者需要清空 App 端显示的路径时,调用该接口上报空路径。关于空路径的格式,在 RVC_PATH_INFO_S 结构体中,type 路径类型填普通模式,即 1,其余都填 0 即可。

缩略图数据上报接口

将 AI 缩略图文件数据发送给 App。 开发者根据 RVC_AI_OBJECT_THUMBNAILS_INFO 结构体的要求,将数据传给 TuyaOS SDK 即可,TuyaOS SDK 内部会对数据进行转化之后传输给 App。

/***********************************************************
 *@function: ty_rvc_rt_ai_thumbnails_send
 *@brief send realtime ai thumbnails to app
 *@param[in] object_info:ai object thumbnails param
 *@return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 ***********************************************************/
OPERATE_RET ty_rvc_rt_ai_thumbnails_send(IN RVC_AI_OBJECT_THUMBNAILS_INFO* object_info);

参数说明

参数 说明
object_info 缩略图数据内容

原始高清图片文件名称注册回调

用于注册 AI 原始高清图文件名获取回调。开发者根据 App 下发的文件名,通过 sets_handler 回调通知到业务端,业务端根据文件名获取对应的原始高清图片数据。

/**
 * @brief AI 高清图片数据回调,App 下发的 AI 高清图片文件名称 `ai_name`
 */
typedef INT_T (*RVC_AI_LOAD_DATA_CB)(CHAR_T *ai_name);

/***********************************************************
 *@function: ty_rvc_ai_original_init
 *@brief Callback function for get aiHD name
 *@param[in] sets_handler: set unpload aiHD name cb
 *@return OPERATE_RET: 0 for success, other error codes indicate failure
 ***********************************************************/
OPERATE_RET ty_rvc_ai_original_init(RVC_AI_LOAD_DATA_CB sets_handler);

原始高清图片上报接口

将原始高清图片数据发送给 App。开发者根据 App 下发的文件名,通过 sets_handler 回调通知到业务端,业务端根据文件名获取对应的原始高清图片数据,传回 TuyaOS SDK 发送出去。开发者只需要将 jpg 格式的原始高清图片用文件打开并读取所有数据传给 TuyaOS SDKTuyaOS SDK 内部会对数据进行转化之后传输给 App。

/***********************************************************
 *@Function: ty_rvc_ai_original_send
 *@brief send ai origina to app
*@param[in] file_type: ai origina types include jpg, png, gif, svg, bmp, ico
 *@param[in] fileBuff: ai origina buff
 *@param[in] fileLen: ai origina len
 *@return OPRT_OK on success. Others on error, please refer to tuya_error_code.h
 ***********************************************************/
OPERATE_RET ty_rvc_ai_original_send(IN CHAR_T* file_type, IN CHAR_T* fileBuff, IN INT_T fileLen);

参数说明

参数 说明
file_type 高清图片类型目前支持以下六种方式: jpg、png、gif、svg、bmp、ico。如需支持其他的图片类型,请找涂鸦项目经理咨询
fileBuff 实时高清图片数据的内容
fileLen 实时高清图片数据的长度

地图及路径数据结构说明

地图数据说明

地图数据 RVC_MAP_DATA_S 由以下几类组成:

  • 地图固定的头部数据,是由 RVC_MAP_HEAD_INFO_S 结构体成员组成。

    序号 字段 数据类型 说明
    1 map_id UINT16_T
    • 一份清扫地图的标识,同一份地图,只是更新,ID 不变。
    • 地图丢失或者其他情况,需要重新建图的,ID 累加。
    • 上电重启,需要存储关机前的 ID。上电后,继续使用该 ID 号。
    2 status UINT32_T 用于 App 控制面板 UI 交互使用:
    • 0x00:地图非稳定状态(例如建图不完整,还在继续建图中)
    • 0x01:地图稳定状态(建图完成,达到一个环境完整的地图)
    3 height UINT32_T 地图像素高度,如当前无地图,该参数则为 0
    4 width UINT32_T 地图像素宽度,如当前无地图,该参数则为 0
    5 resolution UINT32_T 地图分辨率(每个格子的宽长度),原始值上报,单位:厘米
    6 origin UINT32_T 机器原点 X/Y 坐标,参照屏幕坐标系给出,原始值上报,详细请参照 地图坐标系说明
    7 charge_point UINT32_T 充电桩 X/Y 坐标,参照屏幕坐标系给出,原始值上报,充电座坐标点 X 和 Y 同时等于 0 则不显示,详细请参照 地图坐标系说明
    8 charge_angle UINT32_T 当前点的设备航向角,详细请参照 设备角度说明
  • 地图中所有的像素点数据,由 map_buff 成员表示,像素值可参考 MAP_OBS_E 枚举值的定义。
    根据地图的像素宽和像素高,按照二维扫描的方式在其区域内的左上角 R(0,0) 填入对应的像素点枚举值。如果当前像素点是障碍物,就用 1 表示;如果当前像素点是地毯,则用 2 表示。

  • 地图中区域外边界信息由 RVC_ROOM_POLYGON_S 成员表示,它是指房间分区的边界点坐标。
    如下图边界点:
    实时传输 RVC v1.0

    • 边界栅格坐标点需要从起点开始按照顺序填入内存空间中,最后回到起点,中间不要跳跃,否则面板端会出错。
    • 开发者需要根据分辨率及原点 O 坐标,对边界栅格坐标点进行转换后上报给面板端,具体转换逻辑可以参考地图上报例程。
  • 地图上报例程

    int main_test(void)
    {
        RVC_MAP_DATA_S rvc_map_info = { 0 };
        int i = 0;  int j = 0;
        /*地图协议头部固定字节赋值*/
        rvc_map_info.header.map_id = 0;   //地图 ID
        rvc_map_info.header.status = 1;    //0 表示地图非稳定状态,1 表示地图稳定状态
        rvc_map_info.header.width = 121;   //地图像素宽度
        rvc_map_info.header.height = 152;  //地图像素高度    
        rvc_map_info.header.origin.x = 564; //机器原点 X 坐标
        rvc_map_info.header.origin.y = 1357; //机器原点 Y 坐标
        rvc_map_info.header.resolution = 5; //分辨率              
        rvc_map_info.header.charge_point.x = 0; //充电桩 X 坐标
        rvc_map_info.header.charge_point.y = 0; //充电桩 Y 坐标
        rvc_map_info.header.charge_angle = 0; //充电桩朝向
        // 调用函数分配内存
        rvc_map_info.map_buff = NULL;
        char strFileInfo_buff[];   //开发者提供的原始像素点数据,按照以下二维数组的方式填充
        //申请一个二维数组的内存,给 temp_map_buf 使用
        for (i = 0; i < rvc_map_info.header.height; i++) {
            for (j = 0; j < rvc_map_info.header.width; j++) {
                rvc_map_info.map_buff[i][j] =     strFileInfo_buff[rvc_map_info.header.width* i + j];
            }
        }
        char map_buf_info[];  //开发者提供房间轮廓坐标点信息
        if (map_buf_info!= NULL) {    //判断数据是否有效
            int room_count = 2;    //开发者需要提供房间分区数量
            RVC_ROOM_POLYGON_S *tmp_room_polygon = NULL;   
            int tmp_points_size = 0;
            int offset_len = 0;        //数据偏移
            int all_points_size = 0;   //所有坐标数量
            for (i = 0; i < room_count; i++) {     //遍历房间轮廓信息
                  all_points_size += xxxx ;//开发者提供所有房间内的边界点坐标数量
            }
            tmp_room_polygon = (RVC_ROOM_POLYGON_S*)Malloc(room_count * sizeof(RVC_ROOM_POLYGON_S) + all_points_size * sizeof(struct svc_robot_point_s));  //需要申请结构体的内存空间;注意该结构体内的 `polygon` 成员是个指针,需要给该指针对象赋值。
            rvc_map_info.room_polygons_data = tmp_room_polygon;
            float tmp_origin_x = (float)map_header.origin.x /10.0f;    //获取原点坐标
            float tmp_origin_y = (float)map_header.origin.y /10.0f;
            struct svc_robot_point_s* points_memory =(struct svc_robot_point_s*)(tmp_room_polygon + room_count);  //坐标点数据指向二级指针
            for ( i = 0; i < room_count; i++) {     //遍历房间轮廓信息
                tmp_room_polygon->id = (map_buf_info[4 + 8 * i ] << 24) | (map_buf_info[3 + 8 * i] << 16) | (map_buf_info[2 + 8 * i] << 8) | map_buf_info[1 + 8 * i];
                tmp_room_polygon->polygon.points_size = (map_buf_info[8 + 8 * i] << 24) | (map_buf_info[7 + 8 * i] << 16) | (map_buf_info[6 + 8 * i] << 8) | map_buf_info[5 + 8 * i];
                PR_DEBUG("room id :%d, points size :%d", tmp_room_polygon->id, tmp_room_polygon->polygon.points_size);
                offset_len = 1 + 8 * room_count + tmp_points_size; //数据偏移
                tmp_room_polygon->polygon.points = points_memory;
                for (j = 0; j < tmp_room_polygon->polygon.points_size; j++) {
                    memcpy(&tmp_room_polygon->polygon.points[j].x, map_buf_info.buff + (offset_len + j * 12), sizeof(struct svc_robot_point_s));
                    tmp_room_polygon->polygon.points[j].x = tmp_room_polygon->polygon.points[j].x * 100 / 5 + (tmp_origin_x);   //根据分辨率及原点坐标计算出坐标数据上报面板显示。
                    tmp_room_polygon->polygon.points[j].y = (tmp_origin_y) - (tmp_room_polygon->polygon.points[j].y * 100 / 5) ;
                    tmp_room_polygon->polygon.points[j].z = tmp_room_polygon->polygon.points[j].z * 100 / 5;  
                  // PR_DEBUG("point[%d] x:%f,y:%f, z:%f", j, tmp_room_polygon->polygon.points[j].x, tmp_room_polygon->polygon.points[j].y,tmp_room_polygon->polygon.points[j].z);
                 }
                 tmp_points_size += (tmp_room_polygon->polygon.points_size * sizeof(struct svc_robot_point_s));   //累加上房间的坐标点数量 
                 points_memory += tmp_room_polygon->polygon.points_size;   //二级指针地址偏移
                 tmp_room_polygon++;         //获取下一个房间轮廓信息
             }
             rvc_map_info.room_polygons_count = room_count;
             int  ret = ty_rvc_rt_map_send_v2(&rvc_map_info);   //地图数据上报
             if(rvc_map_info.room_polygons_data != NULL) {
                Free(rvc_map_info.room_polygons_data);
             }
        }
          //申请的内存在后面需要释放
        return ret;
    }
    

路径数据说明

路径数据的格式,可参考 RVC_PATH_INFO_S 结构体。

序号 字段 数据类型 说明
1 path_id UINT16_T 一次完整清扫的路径图标识
2 type UINT32_T 路径类型:
  • 0x01:全量路径(普通模式)
  • 0x02:全量路径(复杂模式)
  • 0x03:导航路径
3 direction UINT32_T 设备航向角,详细请参照 设备角度说明
4 count UINT32_T 路径点总个数(全量)
5 path_point PATH_POINT_S 路径坐标数组大小是 Count * 8,可参照 机器坐标系

PATH_POINT_S 结构体中的 coordinates 成员是路径坐标数组,即 X 点、Y 点,每个点 [x,y] = 1 X 8 Bytes;type 成员是路径点类型。当路径类型的值 0x01 时,代表普通仅正常清扫点路径,路径点类型只有 0x00;当路径类型为 0x02时,代表复杂路径。
路径点类型:

  • 0:清扫路径点
  • 1:转场路径点
  • 2:回充路径点
  • 3:拖地路径点(暂未支持)

地图坐标系说明

机器人进行一次新清扫任务时,以机器人从初始位置出发,边清扫边建图,形成清扫地图和清扫路径。地图逐渐扩大,路径不断累积,过程中涉及世界坐标系、机器坐标系以及 App 显示的屏幕坐标系统,其关系如下:

实时传输 RVC v1.0

世界坐标系

实际的物理坐标系,即房间的平面坐标系,机器人每次清扫时,以世界坐标系的某一个点作为起始点,而且在本次清扫中,这个起始点在世界坐标系中的位置是不变的。世界坐标系,用于参照和理解机器坐标系。

机器坐标系

机器人以初始点为原点,参照世界坐标系,建立机器坐标系。清扫过程中,路径点均参照以该原点,得到坐标值。

屏幕坐标系

App 绘图时使用,以屏幕左上角 R(0,0) 为坐标系原点。

地图坐标的转换

地图数据

  • 机器清扫后形成的地图是一个不规则的多边形,为方便处理,取多边形的外接矩形,作为机器的地图。地图数据,是 UINT8_T 形式的数组,地图总像素点为 Map_width * Map_height,地图数组第一个数据点 UINT8_T0,即为左上角 R(0,0)
  • 机器原点 O(x,y)x/y 为相对于 R 的像素个数。随着清扫的进行,地图宽高会改变,原点 O 在地图数组的位置也会变化(x/y 值改变)。

App 绘图时,以原点 O 作为固定,等同于世界坐标系下,机器人初始位置不变。

路径数据

路径数据是走过的位置点的集合,其坐标为 INT32 的值,当前位置点为 P(x,y)x/y 为 P 点相对于 O 点的值。

路径坐标传输值 = 路径坐标原值 * 10,以兼顾精度与效率。

区域框等数据

区域清扫框、禁区框、虚拟墙线、指哪扫哪点等坐标数据,其坐标为 INT32 的值,坐标点 M(x,y)x/y为 M 点相对于 O 点的值,基于绘制坐标系。

区域框坐标传输值 = 区域框坐标原值 * 10,以兼顾精度与效率。

设备角度说明

  • 设备方向(前撞朝向),是以世界坐标为原点,逆时针增加角度。
  • 角度取值范围是:0-360°(0x00-0x168)。
  • 0 度表示世界坐标的 X 轴方向