mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2025-12-17 13:01:12 +00:00
* add biomek.py demo implementation * 更新LiquidHandlerBiomek类,添加资源创建功能,优化协议创建方法,修复部分代码格式问题,更新YAML配置以支持新功能。 * Test * fix biomek success type * Convert LH action to biomek. * Update biomek.py * 注册表上报handle和schema (param input) * 修复biomek缺少的字段 * delete 's' * Remove warnings * Update biomek.py * Biomek test * Update biomek.py * 新增transfer_biomek的msg * New transfer_biomek * Updated transfer_biomek * 更新transfer_biomek的msg * 更新transfer_biomek的msg * 支持Biomek创建 * new action * fix key name typo * New parameter for biomek to run. * Refine * Update * new actions * new actions * 1 * registry * fix biomek startup add action handles * fix handles not as default entry * biomek_test.py biomek_test.py是最新的版本,运行它会生成complete_biomek_protocol.json * Update biomek.py * biomek_test.py * fix liquid_handler.biomek handles * host node新增resource add时间统计 create_resource新增handle bump version to 0.9.2 * 修正物料上传时间 改用biomek_test 增加ResultInfoEncoder 支持返回结果上传 * 正确发送return_info结果 * 同步执行状态信息 * 取消raiseValueError提示 * Update biomek_test.py * 0608 DONE * 同步了Biomek.py 现在应可用 * biomek switch back to non-test * temp disable initialize resource * 37-biomek-i5i7 (#40) * add biomek.py demo implementation * 更新LiquidHandlerBiomek类,添加资源创建功能,优化协议创建方法,修复部分代码格式问题,更新YAML配置以支持新功能。 * Test * fix biomek success type * Convert LH action to biomek. * Update biomek.py * 注册表上报handle和schema (param input) * 修复biomek缺少的字段 * delete 's' * Remove warnings * Update biomek.py * Biomek test * Update biomek.py * 新增transfer_biomek的msg * New transfer_biomek * Updated transfer_biomek * 更新transfer_biomek的msg * 更新transfer_biomek的msg * 支持Biomek创建 * new action * fix key name typo * New parameter for biomek to run. * Refine * Update * new actions * new actions * 1 * registry * fix biomek startup add action handles * fix handles not as default entry * biomek_test.py biomek_test.py是最新的版本,运行它会生成complete_biomek_protocol.json * Update biomek.py * biomek_test.py * fix liquid_handler.biomek handles * host node新增resource add时间统计 create_resource新增handle bump version to 0.9.2 * 修正物料上传时间 改用biomek_test 增加ResultInfoEncoder 支持返回结果上传 * 正确发送return_info结果 * 同步执行状态信息 * 取消raiseValueError提示 * Update biomek_test.py * 0608 DONE * 同步了Biomek.py 现在应可用 * biomek switch back to non-test * temp disable initialize resource * Refine biomek * Refine copy issue * Refine --------- Co-authored-by: Junhan Chang <changjh@pku.edu.cn> Co-authored-by: Guangxin Zhang <guangxin.zhang.bio@gmail.com> Co-authored-by: qxw138 <qxw@stu.pku.edu.cn> * Device visualization (#39) * Update README and MQTTClient for installation instructions and code improvements * feat: 支持local_config启动 add: 增加对crt path的说明,为传入config.py的相对路径 move: web component * add: registry description * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * feat: node_info_update srv fix: OTDeck cant create * close #12 feat: slave node registry * feat: show machine name fix: host node registry not uploaded * feat: add hplc registry * feat: add hplc registry * fix: hplc status typo * fix: devices/ * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * fix: device.class possible null * fix: HPLC additions with online service * fix: slave mode spin not working * fix: slave mode spin not working * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * feat: 多ProtocolNode 允许子设备ID相同 feat: 上报发现的ActionClient feat: Host重启动,通过discover机制要求slaveNode重新注册,实现信息及时上报 * feat: 支持env设置config * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * Device visualization (#14) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: missing hostname in devices_names fix: upload_file for model file * fix: missing paho-mqtt package bump version to 0.9.0 * fix startup add ResourceCreateFromOuter.action * fix type hint * update actions * update actions * host node add_resource_from_outer fix cmake list * pass device config to device class * add: bind_parent_ids to resource create action fix: message convert string * fix: host node should not be re_discovered * feat: resource tracker support dict * feat: add more necessary params * feat: fix boolean null in registry action data * feat: add outer resource * 编写mesh添加action * feat: append resource * add action * feat: vis 2d for plr * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate * Device visualization (#22) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * 编写mesh添加action * add action * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: multi channel * fix: aspirate * fix: aspirate * fix: aspirate * fix: aspirate * 提交 * fix: jobadd * fix: jobadd * fix: msg converter * tijiao * add resource creat easy action * identify debug msg * mq client id * 提取lh的joint发布 * unify liquid_handler definition * 修改物料跟随与物料添加逻辑 修改物料跟随与物料添加逻辑 将joint_publisher类移出lh的backends,但仍需要对lh的backends进行一些改写 * Revert "修改物料跟随与物料添加逻辑" This reverts commit498c997ad7. * Reapply "修改物料跟随与物料添加逻辑" This reverts commit3a60d2ae81. * Revert "Merge remote-tracking branch 'upstream/dev' into device_visualization" This reverts commitfa727220af, reversing changes made to498c997ad7. * 修改物料放下时的方法,如果选择 修改物料放下时的方法, 如果选择drop_trash,则删除物料显示 如果选择drop,则让其解除连接 * add biomek.py demo implementation * 更新LiquidHandlerBiomek类,添加资源创建功能,优化协议创建方法,修复部分代码格式问题,更新YAML配置以支持新功能。 * Test * fix biomek success type * Convert LH action to biomek. * Update biomek.py * 注册表上报handle和schema (param input) * 修复biomek缺少的字段 * delete 's' * Remove warnings * Update biomek.py * Biomek test * Update biomek.py * 新增transfer_biomek的msg * New transfer_biomek * Updated transfer_biomek * 更新transfer_biomek的msg * 更新transfer_biomek的msg * 支持Biomek创建 * new action * fix key name typo * New parameter for biomek to run. * Refine * Update * new actions * new actions * 1 * registry * fix biomek startup add action handles * fix handles not as default entry * unilab添加moveit启动 1,整合所有moveit节点到一个move_group中,并整合所有的controller依次激活 2,添加pymoveit2的节点,使用json可直接启动 3,修改机械臂规划方式,添加约束,让冗余关节不会进行过多移动 * biomek_test.py biomek_test.py是最新的版本,运行它会生成complete_biomek_protocol.json * Update biomek.py * biomek_test.py * fix liquid_handler.biomek handles * 修改物体attach时,多次赋值当前时间导致卡顿问题, * Revert "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit56d45b94f5. * Reapply "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit07d9db20c3. * 添加缺少物料:"plate_well_G12", * host node新增resource add时间统计 create_resource新增handle bump version to 0.9.2 * 修正物料上传时间 改用biomek_test 增加ResultInfoEncoder 支持返回结果上传 * 正确发送return_info结果 * 同步执行状态信息 * 取消raiseValueError提示 * Update biomek_test.py * 0608 DONE * 同步了Biomek.py 现在应可用 * biomek switch back to non-test * temp disable initialize resource * add * fix tip resource data * liquid states * change to debug level * Revert "change to debug level" This reverts commit5d9953c3e5. * Reapply "change to debug level" This reverts commit2487bb6ffc. * fix tip resource data * add full device * add moveit yaml * 修复moveit 增加post_init阶段,给予ros_node反向 * remove necessary node * fix moveit action client * remove necessary imports * Update moveit_interface.py * fix handler_key uppercase * json add liquids * fix setup * add * change to "sources" and "targets" for lh * bump version * remove parent's parent link --------- Co-authored-by: Harvey Que <Q-Query@outlook.com> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: Junhan Chang <changjh@pku.edu.cn> Co-authored-by: Guangxin Zhang <guangxin.zhang.bio@gmail.com> Co-authored-by: qxw138 <qxw@stu.pku.edu.cn> * Device visualization (#41) * Update README and MQTTClient for installation instructions and code improvements * feat: 支持local_config启动 add: 增加对crt path的说明,为传入config.py的相对路径 move: web component * add: registry description * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * feat: node_info_update srv fix: OTDeck cant create * close #12 feat: slave node registry * feat: show machine name fix: host node registry not uploaded * feat: add hplc registry * feat: add hplc registry * fix: hplc status typo * fix: devices/ * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * fix: device.class possible null * fix: HPLC additions with online service * fix: slave mode spin not working * fix: slave mode spin not working * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * feat: 多ProtocolNode 允许子设备ID相同 feat: 上报发现的ActionClient feat: Host重启动,通过discover机制要求slaveNode重新注册,实现信息及时上报 * feat: 支持env设置config * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * Device visualization (#14) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: missing hostname in devices_names fix: upload_file for model file * fix: missing paho-mqtt package bump version to 0.9.0 * fix startup add ResourceCreateFromOuter.action * fix type hint * update actions * update actions * host node add_resource_from_outer fix cmake list * pass device config to device class * add: bind_parent_ids to resource create action fix: message convert string * fix: host node should not be re_discovered * feat: resource tracker support dict * feat: add more necessary params * feat: fix boolean null in registry action data * feat: add outer resource * 编写mesh添加action * feat: append resource * add action * feat: vis 2d for plr * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate * Device visualization (#22) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * 编写mesh添加action * add action * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: multi channel * fix: aspirate * fix: aspirate * fix: aspirate * fix: aspirate * 提交 * fix: jobadd * fix: jobadd * fix: msg converter * tijiao * add resource creat easy action * identify debug msg * mq client id * 提取lh的joint发布 * unify liquid_handler definition * 修改物料跟随与物料添加逻辑 修改物料跟随与物料添加逻辑 将joint_publisher类移出lh的backends,但仍需要对lh的backends进行一些改写 * Revert "修改物料跟随与物料添加逻辑" This reverts commit498c997ad7. * Reapply "修改物料跟随与物料添加逻辑" This reverts commit3a60d2ae81. * Revert "Merge remote-tracking branch 'upstream/dev' into device_visualization" This reverts commitfa727220af, reversing changes made to498c997ad7. * 修改物料放下时的方法,如果选择 修改物料放下时的方法, 如果选择drop_trash,则删除物料显示 如果选择drop,则让其解除连接 * add biomek.py demo implementation * 更新LiquidHandlerBiomek类,添加资源创建功能,优化协议创建方法,修复部分代码格式问题,更新YAML配置以支持新功能。 * Test * fix biomek success type * Convert LH action to biomek. * Update biomek.py * 注册表上报handle和schema (param input) * 修复biomek缺少的字段 * delete 's' * Remove warnings * Update biomek.py * Biomek test * Update biomek.py * 新增transfer_biomek的msg * New transfer_biomek * Updated transfer_biomek * 更新transfer_biomek的msg * 更新transfer_biomek的msg * 支持Biomek创建 * new action * fix key name typo * New parameter for biomek to run. * Refine * Update * new actions * new actions * 1 * registry * fix biomek startup add action handles * fix handles not as default entry * unilab添加moveit启动 1,整合所有moveit节点到一个move_group中,并整合所有的controller依次激活 2,添加pymoveit2的节点,使用json可直接启动 3,修改机械臂规划方式,添加约束,让冗余关节不会进行过多移动 * biomek_test.py biomek_test.py是最新的版本,运行它会生成complete_biomek_protocol.json * Update biomek.py * biomek_test.py * fix liquid_handler.biomek handles * 修改物体attach时,多次赋值当前时间导致卡顿问题, * Revert "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit56d45b94f5. * Reapply "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit07d9db20c3. * 添加缺少物料:"plate_well_G12", * host node新增resource add时间统计 create_resource新增handle bump version to 0.9.2 * 修正物料上传时间 改用biomek_test 增加ResultInfoEncoder 支持返回结果上传 * 正确发送return_info结果 * 同步执行状态信息 * 取消raiseValueError提示 * Update biomek_test.py * 0608 DONE * 同步了Biomek.py 现在应可用 * biomek switch back to non-test * temp disable initialize resource * add * fix tip resource data * liquid states * change to debug level * Revert "change to debug level" This reverts commit5d9953c3e5. * Reapply "change to debug level" This reverts commit2487bb6ffc. * fix tip resource data * add full device * add moveit yaml * 修复moveit 增加post_init阶段,给予ros_node反向 * remove necessary node * fix moveit action client * remove necessary imports * Update moveit_interface.py * fix handler_key uppercase * json add liquids * fix setup * add * change to "sources" and "targets" for lh * bump version * remove parent's parent link * change arm's name * change name --------- Co-authored-by: Harvey Que <Q-Query@outlook.com> Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: q434343 <73513873+q434343@users.noreply.github.com> Co-authored-by: Junhan Chang <changjh@pku.edu.cn> Co-authored-by: Guangxin Zhang <guangxin.zhang.bio@gmail.com> Co-authored-by: qxw138 <qxw@stu.pku.edu.cn> * fix move it * fix move it * create_resource * bump ver modify slot type * 增加modbus支持 调整protocol node以更好支持多种类型的read和write * 调整protocol node以更好支持多种类型的read和write * 补充日志 * Device visualization (#42) * Update README and MQTTClient for installation instructions and code improvements * feat: 支持local_config启动 add: 增加对crt path的说明,为传入config.py的相对路径 move: web component * add: registry description * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * feat: node_info_update srv fix: OTDeck cant create * close #12 feat: slave node registry * feat: show machine name fix: host node registry not uploaded * feat: add hplc registry * feat: add hplc registry * fix: hplc status typo * fix: devices/ * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * fix: device.class possible null * fix: HPLC additions with online service * fix: slave mode spin not working * fix: slave mode spin not working * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * feat: 多ProtocolNode 允许子设备ID相同 feat: 上报发现的ActionClient feat: Host重启动,通过discover机制要求slaveNode重新注册,实现信息及时上报 * feat: 支持env设置config * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * Device visualization (#14) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: missing hostname in devices_names fix: upload_file for model file * fix: missing paho-mqtt package bump version to 0.9.0 * fix startup add ResourceCreateFromOuter.action * fix type hint * update actions * update actions * host node add_resource_from_outer fix cmake list * pass device config to device class * add: bind_parent_ids to resource create action fix: message convert string * fix: host node should not be re_discovered * feat: resource tracker support dict * feat: add more necessary params * feat: fix boolean null in registry action data * feat: add outer resource * 编写mesh添加action * feat: append resource * add action * feat: vis 2d for plr * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate * Device visualization (#22) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * 编写mesh添加action * add action * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: multi channel * fix: aspirate * fix: aspirate * fix: aspirate * fix: aspirate * 提交 * fix: jobadd * fix: jobadd * fix: msg converter * tijiao * add resource creat easy action * identify debug msg * mq client id * 提取lh的joint发布 * unify liquid_handler definition * 修改物料跟随与物料添加逻辑 修改物料跟随与物料添加逻辑 将joint_publisher类移出lh的backends,但仍需要对lh的backends进行一些改写 * Revert "修改物料跟随与物料添加逻辑" This reverts commit498c997ad7. * Reapply "修改物料跟随与物料添加逻辑" This reverts commit3a60d2ae81. * Revert "Merge remote-tracking branch 'upstream/dev' into device_visualization" This reverts commitfa727220af, reversing changes made to498c997ad7. * 修改物料放下时的方法,如果选择 修改物料放下时的方法, 如果选择drop_trash,则删除物料显示 如果选择drop,则让其解除连接 * unilab添加moveit启动 1,整合所有moveit节点到一个move_group中,并整合所有的controller依次激活 2,添加pymoveit2的节点,使用json可直接启动 3,修改机械臂规划方式,添加约束,让冗余关节不会进行过多移动 * 修改物体attach时,多次赋值当前时间导致卡顿问题, * Revert "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit56d45b94f5. * Reapply "修改物体attach时,多次赋值当前时间导致卡顿问题," This reverts commit07d9db20c3. * 添加缺少物料:"plate_well_G12", * add * fix tip resource data * liquid states * change to debug level * Revert "change to debug level" This reverts commit5d9953c3e5. * Reapply "change to debug level" This reverts commit2487bb6ffc. * fix tip resource data * add full device * add moveit yaml * 修复moveit 增加post_init阶段,给予ros_node反向 * remove necessary node * fix moveit action client * remove necessary imports * Update moveit_interface.py * fix handler_key uppercase * json add liquids * fix setup * add * change to "sources" and "targets" for lh * bump version * remove parent's parent link * change arm's name * change name * fix ik error --------- Co-authored-by: Harvey Que <Q-Query@outlook.com> Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: q434343 <73513873+q434343@users.noreply.github.com> Co-authored-by: Junhan Chang <changjh@pku.edu.cn> * Add Mock Device for Organic Synthesis\添加有机合成的虚拟仪器和Protocol (#43) * Add Device MockChiller Add device MockChiller * Add Device MockFilter * Add Device MockPump * Add Device MockRotavap * Add Device MockSeparator * Add Device MockStirrer * Add Device MockHeater * Add Device MockVacuum * Add Device MockSolenoidValve * Add Device Mock \_init_.py * 规范模拟设备代码与注册表信息 * 更改Mock大写文件夹名 * 删除大写目录 * Edited Mock device json * Match mock device with action * Edit mock device yaml * Add new action * Add Virtual Device, Action, YAML, Protocol for Organic Syn * 单独分类测试的protocol文件夹 * 更名Action --------- Co-authored-by: Xuwznln <18435084+Xuwznln@users.noreply.github.com> * bump version & protocol fix * hotfix: Add macos_sdk_config (#46) Co-authored-by: quehh <scienceol@outlook.com> * include device_mesh when pip install * 测试自动构建 * try build fix * try build * test artifacts * hotfix: Add .certs in .gitignore * create container * container 添加和更新完成 * Device registry port (#49) * Update README and MQTTClient for installation instructions and code improvements * feat: 支持local_config启动 add: 增加对crt path的说明,为传入config.py的相对路径 move: web component * add: registry description * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * feat: node_info_update srv fix: OTDeck cant create * close #12 feat: slave node registry * feat: show machine name fix: host node registry not uploaded * feat: add hplc registry * feat: add hplc registry * fix: hplc status typo * fix: devices/ * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * fix: device.class possible null * fix: HPLC additions with online service * fix: slave mode spin not working * fix: slave mode spin not working * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * feat: 多ProtocolNode 允许子设备ID相同 feat: 上报发现的ActionClient feat: Host重启动,通过discover机制要求slaveNode重新注册,实现信息及时上报 * feat: 支持env设置config * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * Device visualization (#14) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: missing hostname in devices_names fix: upload_file for model file * fix: missing paho-mqtt package bump version to 0.9.0 * fix startup add ResourceCreateFromOuter.action * fix type hint * update actions * update actions * host node add_resource_from_outer fix cmake list * pass device config to device class * add: bind_parent_ids to resource create action fix: message convert string * fix: host node should not be re_discovered * feat: resource tracker support dict * feat: add more necessary params * feat: fix boolean null in registry action data * feat: add outer resource * 编写mesh添加action * feat: append resource * add action * feat: vis 2d for plr * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate * Device visualization (#22) * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * add 3d visualization * 完成在main中启动设备可视化 完成在main中启动设备可视化,并输出物料ID:mesh的对应关系resource_model 添加物料模型管理类,遍历物料与resource_model,完成TF数据收集 * 完成TF发布 * 修改模型方向,在yaml中添加变换属性 * 添加物料tf变化时,发送topic到前端 另外修改了物料初始化的方法,防止在tf还未发布时提前建立物料模型与发布话题 * 添加关节发布节点与物料可视化节点进入unilab * 使用json启动plr与3D模型仿真 * 完成启动OT并联动rviz * 修复rviz位置问题, 修复rviz位置问题, 在无tf变动时减缓发送频率 在backend中添加物料跟随方法 * fix: running logic * fix: running logic * fix: missing ot * 在main中直接初始化republisher和物料的mesh节点 * 将joint_republisher和resource_mesh_manager添加进 main_slave_run.py中 * 编写mesh添加action * add action * fix * fix: browser on rviz * fix: cloud bridge error fallback to local * fix: salve auto run rviz * 初始化两个plate --------- Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> * fix: multi channel * fix: aspirate * fix: aspirate * fix: aspirate * fix: aspirate * 提交 * fix: jobadd * fix: jobadd * fix: msg converter * tijiao * add resource creat easy action * identify debug msg * mq client id * unify liquid_handler definition * Update virtual_device.yaml * 更正了stir和heater的连接方式 * 区分了虚拟仪器中的八通阀和电磁阀,添加了两个阀门的驱动 * 修改了add protocol * 修复了阀门更新版的bug * 修复了添加protocol前缀导致的不能启动的bug * Fix handles * bump version to 0.9.6 * add resource edge upload * update container registry and handles * add virtual_separator virtual_rotavap fix transfer_pump * fix container value add parent_name to edge device id * 大图的问题都修复好了,添加了gassource和vacuum pump的驱动以及注册表 * default resource upload mode is false * 添加了icon的文件名在注册表里面 * 修改了json图中link的格式 * fix resource and edge upload * fix device ports * Fix edge id * 移除device的父节点关联 * separate registry sync and resource_add * 默认不进行注册表报送,通过命令unilabos-register或者增加启动参数 * 完善tip * protocol node不再嵌套显示 * bump version to 0.9.7 新增一个测试PumpTransferProtocol的teststation,亲测可以运行,将八通阀们和转移泵与pump_protocol适配 * protocol node 执行action不应携带自身device id * 添加了一套简易双八通阀工作站JSON,亲测能跑 * 修复了很多protocol,亲测能跑 * 添加了run column和filter through的protocol,亲测能跑 * fix mock_reactor * 修改了大图和小图的json,但是在前端上没看到改变 --------- Co-authored-by: Harvey Que <Q-Query@outlook.com> Co-authored-by: wznln <18435084+Xuwznln@users.noreply.github.com> Co-authored-by: zhangshixiang <@zhangshixiang> Co-authored-by: q434343 <73513873+q434343@users.noreply.github.com> Co-authored-by: Junhan Chang <changjh@pku.edu.cn> * 更新workstation注册表 * 添加了两个protocol的检索功能 (#51) * 添加了两个protocol的检索liquid type功能 * fix workstation registry * 修复了没连接的几个仪器的link,添加了container的icon * 修改了json和注册表,现在大图全部的device都链接上了 * 修复了小图的json图,线全部连上了 * add work_station protocol handles (ports) * fix workstation action handle --------- Co-authored-by: Xuwznln <18435084+Xuwznln@users.noreply.github.com> Co-authored-by: Junhan Chang <changjh@dp.tech> * 新增注册表补全功能,修复Protocol执行失败 * 支持通过导入方式补全注册表,新增工作流unilabos_device_id字段 * 修复不启用注册表补充就无法启动的bug * 修复部分识别error * 修复静态方法识别get status,注册表支持python类型 * status types对于嵌套类型返回的对象,暂时处理成字符串,无法直接进行转换 * 支持通过list[int],list[float]进行Int64MultiArray,Float64MultiArray的替换 * 成功动态导入的不再需要使用静态导入 * Fix handle names (#55) * fix handle names * improve evacuateAndRefill gas source finding * add camera and dependency (#56) * 修复auto-的Action在protocol node下错误注册 --------- Co-authored-by: Junhan Chang <changjh@pku.edu.cn> Co-authored-by: Guangxin Zhang <guangxin.zhang.bio@gmail.com> Co-authored-by: qxw138 <qxw@stu.pku.edu.cn> Co-authored-by: q434343 <73513873+q434343@users.noreply.github.com> Co-authored-by: Harvey Que <Q-Query@outlook.com> Co-authored-by: Kongchang Feng <2100011801@stu.pku.edu.cn> Co-authored-by: hh. <103566763+Mile-Away@users.noreply.github.com> Co-authored-by: quehh <scienceol@outlook.com> Co-authored-by: Harvey Que <quehaohui@dp.tech> Co-authored-by: Junhan Chang <changjh@dp.tech>
809 lines
28 KiB
Python
809 lines
28 KiB
Python
"""
|
||
消息转换器
|
||
|
||
该模块提供了在Python对象(dataclass, Pydantic模型)和ROS消息类型之间进行转换的功能。
|
||
使用ImportManager动态导入和管理所需模块。
|
||
"""
|
||
|
||
import json
|
||
import traceback
|
||
from io import StringIO
|
||
from typing import Iterable, Any, Dict, Type, TypeVar, Union
|
||
|
||
import yaml
|
||
from pydantic import BaseModel
|
||
from dataclasses import asdict, is_dataclass
|
||
|
||
from rosidl_parser.definition import UnboundedSequence, NamespacedType, BasicType, UnboundedString
|
||
|
||
from unilabos.utils import logger
|
||
from unilabos.utils.import_manager import ImportManager
|
||
from unilabos.config.config import ROSConfig
|
||
|
||
# 定义泛型类型
|
||
T = TypeVar("T")
|
||
DataClassT = TypeVar("DataClassT")
|
||
|
||
# 从配置中获取需要导入的模块列表
|
||
ROS_MODULES = ROSConfig.modules
|
||
|
||
msg_converter_manager = ImportManager(ROS_MODULES)
|
||
|
||
|
||
"""geometry_msgs"""
|
||
Point = msg_converter_manager.get_class("geometry_msgs.msg:Point")
|
||
Pose = msg_converter_manager.get_class("geometry_msgs.msg:Pose")
|
||
"""std_msgs"""
|
||
Float64 = msg_converter_manager.get_class("std_msgs.msg:Float64")
|
||
Float64MultiArray = msg_converter_manager.get_class("std_msgs.msg:Float64MultiArray")
|
||
Int32 = msg_converter_manager.get_class("std_msgs.msg:Int32")
|
||
Int64 = msg_converter_manager.get_class("std_msgs.msg:Int64")
|
||
String = msg_converter_manager.get_class("std_msgs.msg:String")
|
||
Bool = msg_converter_manager.get_class("std_msgs.msg:Bool")
|
||
"""nav2_msgs"""
|
||
NavigateToPose = msg_converter_manager.get_class("nav2_msgs.action:NavigateToPose")
|
||
NavigateThroughPoses = msg_converter_manager.get_class("nav2_msgs.action:NavigateThroughPoses")
|
||
SingleJointPosition = msg_converter_manager.get_class("control_msgs.action:SingleJointPosition")
|
||
"""unilabos_msgs"""
|
||
Resource = msg_converter_manager.get_class("unilabos_msgs.msg:Resource")
|
||
SendCmd = msg_converter_manager.get_class("unilabos_msgs.action:SendCmd")
|
||
"""unilabos"""
|
||
imsg = msg_converter_manager.get_module("unilabos.messages")
|
||
Point3D = msg_converter_manager.get_class("unilabos.messages:Point3D")
|
||
|
||
# 基本消息类型映射
|
||
_msg_mapping: Dict[Type, Type] = {
|
||
float: Float64,
|
||
list[float]: Float64MultiArray,
|
||
int: Int32,
|
||
str: String,
|
||
bool: Bool,
|
||
Point3D: Point,
|
||
}
|
||
|
||
# Action类型映射
|
||
_action_mapping: Dict[Type, Dict[str, Any]] = {
|
||
float: {
|
||
"type": SingleJointPosition,
|
||
"goal": {"position": "position", "max_velocity": "max_velocity"},
|
||
"feedback": {"position": "position"},
|
||
"result": {},
|
||
},
|
||
str: {
|
||
"type": SendCmd,
|
||
"goal": {"command": "position"},
|
||
"feedback": {"status": "status"},
|
||
"result": {},
|
||
},
|
||
Point3D: {
|
||
"type": NavigateToPose,
|
||
"goal": {"pose.pose.position": "position"},
|
||
"feedback": {
|
||
"current_pose.pose.position": "position",
|
||
"navigation_time.sec": "time_spent",
|
||
"estimated_time_remaining.sec": "time_remaining",
|
||
},
|
||
"result": {},
|
||
},
|
||
list[Point3D]: {
|
||
"type": NavigateThroughPoses,
|
||
"goal": {"poses[].pose.position": "positions[]"},
|
||
"feedback": {
|
||
"current_pose.pose.position": "position",
|
||
"navigation_time.sec": "time_spent",
|
||
"estimated_time_remaining.sec": "time_remaining",
|
||
"number_of_poses_remaining": "pose_number_remaining",
|
||
},
|
||
"result": {},
|
||
},
|
||
}
|
||
|
||
# 添加Protocol action类型到映射
|
||
for py_msgtype in imsg.__all__:
|
||
if py_msgtype not in _action_mapping and (py_msgtype.endswith("Protocol") or py_msgtype.startswith("Protocol")):
|
||
try:
|
||
protocol_class = msg_converter_manager.get_class(f"unilabos.messages.{py_msgtype}")
|
||
action_name = py_msgtype.replace("Protocol", "")
|
||
action_type = msg_converter_manager.get_class(f"unilabos_msgs.action.{action_name}")
|
||
|
||
if action_type:
|
||
_action_mapping[protocol_class] = {
|
||
"type": action_type,
|
||
"goal": {k: k for k in action_type.Goal().get_fields_and_field_types().keys()},
|
||
"feedback": {
|
||
(k if "time" not in k else f"{k}.sec"): k
|
||
for k in action_type.Feedback().get_fields_and_field_types().keys()
|
||
},
|
||
"result": {k: k for k in action_type.Result().get_fields_and_field_types().keys()},
|
||
}
|
||
except Exception:
|
||
traceback.print_exc()
|
||
logger.debug(f"Failed to load Protocol class: {py_msgtype}")
|
||
|
||
# Python到ROS消息转换器
|
||
_msg_converter: Dict[Type, Any] = {
|
||
float: float,
|
||
Float64: lambda x: Float64(data=float(x)),
|
||
Float64MultiArray: lambda x: Float64MultiArray(data=[float(i) for i in x]),
|
||
int: int,
|
||
Int32: lambda x: Int32(data=int(x)),
|
||
Int64: lambda x: Int64(data=int(x)),
|
||
bool: bool,
|
||
Bool: lambda x: Bool(data=bool(x)),
|
||
str: str,
|
||
String: lambda x: String(data=str(x)),
|
||
Point: lambda x: Point(x=x.x, y=x.y, z=x.z) if not isinstance(x, dict) else Point(x=x.get("x", 0.0), y=x.get("y", 0.0), z=x.get("z", 0.0)),
|
||
Resource: lambda x: Resource(
|
||
id=x.get("id", ""),
|
||
name=x.get("name", ""),
|
||
sample_id=x.get("sample_id", "") or "",
|
||
children=list(x.get("children", [])),
|
||
parent=x.get("parent", "") or "",
|
||
type=x.get("type", ""),
|
||
category=x.get("class", "") or x.get("type", ""),
|
||
pose=(
|
||
Pose(position=Point(x=float(x.get("position", {}).get("x", 0.0)), y=float(x.get("position", {}).get("y", 0.0)), z=float(x.get("position", {}).get("z", 0.0))))
|
||
if x.get("position", None) is not None
|
||
else Pose()
|
||
),
|
||
config=json.dumps(x.get("config", {})),
|
||
data=json.dumps(x.get("data", {})),
|
||
),
|
||
}
|
||
|
||
def json_or_yaml_loads(data: str) -> Any:
|
||
try:
|
||
return json.loads(data)
|
||
except Exception as e:
|
||
try:
|
||
return yaml.safe_load(StringIO(data))
|
||
except:
|
||
pass
|
||
raise e
|
||
|
||
# ROS消息到Python转换器
|
||
_msg_converter_back: Dict[Type, Any] = {
|
||
float: float,
|
||
Float64: lambda x: x.data,
|
||
Float64MultiArray: lambda x: x.data,
|
||
int: int,
|
||
Int32: lambda x: x.data,
|
||
Int64: lambda x: x.data,
|
||
bool: bool,
|
||
Bool: lambda x: x.data,
|
||
str: str,
|
||
String: lambda x: x.data,
|
||
Point: lambda x: Point3D(x=x.x, y=x.y, z=x.z),
|
||
Resource: lambda x: {
|
||
"id": x.id,
|
||
"name": x.name,
|
||
"sample_id": x.sample_id if x.sample_id else None,
|
||
"children": list(x.children),
|
||
"parent": x.parent if x.parent else None,
|
||
"type": x.type,
|
||
"class": x.category,
|
||
"position": {"x": x.pose.position.x, "y": x.pose.position.y, "z": x.pose.position.z},
|
||
"config": json_or_yaml_loads(x.config or "{}"),
|
||
"data": json_or_yaml_loads(x.data or "{}"),
|
||
},
|
||
}
|
||
|
||
# 消息数据类型映射
|
||
_msg_data_mapping: Dict[str, Type] = {
|
||
"double": float,
|
||
"float": float,
|
||
"int": int,
|
||
"bool": bool,
|
||
"str": str,
|
||
}
|
||
|
||
|
||
def compare_model_fields(cls1: Any, cls2: Any) -> bool:
|
||
"""比较两个类的字段是否相同"""
|
||
|
||
def get_class_fields(cls: Any) -> set:
|
||
if hasattr(cls, "__annotations__"):
|
||
return set(cls.__annotations__.keys())
|
||
else:
|
||
return set(cls.__dict__.keys())
|
||
|
||
fields1 = get_class_fields(cls1)
|
||
fields2 = get_class_fields(cls2)
|
||
return fields1 == fields2
|
||
|
||
|
||
def get_msg_type(datatype: Type) -> Type:
|
||
"""
|
||
获取与Python数据类型对应的ROS消息类型
|
||
|
||
Args:
|
||
datatype: Python数据类型、Pydantic模型或dataclass
|
||
|
||
Returns:
|
||
对应的ROS消息类型
|
||
|
||
Raises:
|
||
ValueError: 如果不支持的消息类型
|
||
"""
|
||
# 直接匹配已知类型
|
||
if isinstance(datatype, type) and datatype in _msg_mapping:
|
||
return _msg_mapping[datatype]
|
||
|
||
# 尝试通过字段比较匹配
|
||
for k, v in _msg_mapping.items():
|
||
if compare_model_fields(k, datatype):
|
||
return v
|
||
|
||
raise ValueError(f"Unsupported message type: {datatype}")
|
||
|
||
|
||
def get_action_type(datatype: Type) -> Dict[str, Any]:
|
||
"""
|
||
获取与Python数据类型对应的ROS动作类型
|
||
|
||
Args:
|
||
datatype: Python数据类型、Pydantic模型或dataclass
|
||
|
||
Returns:
|
||
对应的ROS动作类型配置
|
||
|
||
Raises:
|
||
ValueError: 如果不支持的动作类型
|
||
"""
|
||
# 直接匹配已知类型
|
||
if isinstance(datatype, type) and datatype in _action_mapping:
|
||
return _action_mapping[datatype]
|
||
|
||
# 尝试通过字段比较匹配
|
||
for k, v in _action_mapping.items():
|
||
if compare_model_fields(k, datatype):
|
||
return v
|
||
|
||
raise ValueError(f"Unsupported action type: {datatype}")
|
||
|
||
|
||
def get_ros_type_by_msgname(msgname: str) -> Type:
|
||
"""
|
||
通过消息名称获取ROS类型
|
||
|
||
Args:
|
||
msgname: ROS消息名称,格式为 'package_name/(action,msg,srv)/TypeName'
|
||
|
||
Returns:
|
||
对应的ROS类型
|
||
|
||
Raises:
|
||
ValueError: 如果无效的ROS消息名称
|
||
ImportError: 如果无法加载类型
|
||
"""
|
||
parts = msgname.split("/")
|
||
if len(parts) != 3 or parts[1] not in ("action", "msg", "srv"):
|
||
raise ValueError(
|
||
f"Invalid ROS message name: {msgname}. Format should be 'package_name/(action,msg,srv)/TypeName'"
|
||
)
|
||
|
||
package_name, msg_type, type_name = parts
|
||
full_module_path = f"{package_name}.{msg_type}"
|
||
|
||
try:
|
||
# 尝试通过ImportManager获取
|
||
return msg_converter_manager.get_class(f"{full_module_path}.{type_name}")
|
||
except KeyError:
|
||
# 尝试动态导入
|
||
try:
|
||
msg_converter_manager.load_module(full_module_path)
|
||
return msg_converter_manager.get_class(f"{full_module_path}.{type_name}")
|
||
except Exception as e:
|
||
raise ImportError(f"Failed to load type {type_name}. Make sure the package is installed.") from e
|
||
|
||
|
||
def _extract_data(obj: Any) -> Dict[str, Any]:
|
||
"""提取对象数据为字典"""
|
||
if is_dataclass(obj) and not isinstance(obj, type) and hasattr(obj, "__dataclass_fields__"):
|
||
return asdict(obj)
|
||
elif isinstance(obj, BaseModel):
|
||
return obj.model_dump()
|
||
elif isinstance(obj, dict):
|
||
return obj
|
||
else:
|
||
return {"data": obj}
|
||
|
||
|
||
def convert_to_ros_msg(ros_msg_type: Union[Type, Any], obj: Any) -> Any:
|
||
"""
|
||
将Python对象转换为ROS消息实例
|
||
|
||
Args:
|
||
ros_msg_type: 目标ROS消息类型
|
||
obj: Python对象(基本类型、dataclass或Pydantic实例)
|
||
|
||
Returns:
|
||
ROS消息实例
|
||
"""
|
||
# 尝试使用预定义转换器
|
||
try:
|
||
if isinstance(ros_msg_type, type) and ros_msg_type in _msg_converter:
|
||
return _msg_converter[ros_msg_type](obj)
|
||
except Exception as e:
|
||
logger.error(f"Converter error: {type(ros_msg_type)} -> {obj}")
|
||
traceback.print_exc()
|
||
|
||
# 创建ROS消息实例
|
||
ros_msg = ros_msg_type() if isinstance(ros_msg_type, type) else ros_msg_type
|
||
|
||
# 提取数据
|
||
extract_data = dict(_extract_data(obj))
|
||
|
||
# 转换数据到ROS消息
|
||
for ind, data in enumerate(ros_msg.get_fields_and_field_types().items()):
|
||
key, type_name = data
|
||
if key not in extract_data:
|
||
continue
|
||
value = extract_data[key]
|
||
if hasattr(ros_msg, key):
|
||
attr = getattr(ros_msg, key)
|
||
if isinstance(attr, (float, int, str, bool)):
|
||
setattr(ros_msg, key, value)
|
||
elif isinstance(attr, (list, tuple)) and isinstance(value, Iterable):
|
||
td = ros_msg.SLOT_TYPES[ind].value_type
|
||
if isinstance(td, NamespacedType):
|
||
target_class = msg_converter_manager.get_class(f"{'.'.join(td.namespaces)}.{td.name}")
|
||
setattr(ros_msg, key, [convert_to_ros_msg(target_class, v) for v in value])
|
||
elif isinstance(td, UnboundedString):
|
||
setattr(ros_msg, key, value)
|
||
else:
|
||
logger.warning(f"Not Supported type: {td}")
|
||
setattr(ros_msg, key, []) # FIXME
|
||
elif "array.array" in str(type(attr)):
|
||
if attr.typecode == "f":
|
||
setattr(ros_msg, key, [float(i) for i in value])
|
||
else:
|
||
setattr(ros_msg, key, value)
|
||
else:
|
||
nested_ros_msg = convert_to_ros_msg(type(attr)(), value)
|
||
setattr(ros_msg, key, nested_ros_msg)
|
||
else:
|
||
# 跳过不存在的字段,防止报错
|
||
continue
|
||
|
||
return ros_msg
|
||
|
||
|
||
def convert_to_ros_msg_with_mapping(ros_msg_type: Type, obj: Any, value_mapping: Dict[str, str]) -> Any:
|
||
"""
|
||
根据字段映射将Python对象转换为ROS消息
|
||
|
||
Args:
|
||
ros_msg_type: 目标ROS消息类型
|
||
obj: Python对象
|
||
value_mapping: 字段名映射关系字典
|
||
|
||
Returns:
|
||
ROS消息实例
|
||
"""
|
||
# 创建ROS消息实例
|
||
ros_msg = ros_msg_type() if isinstance(ros_msg_type, type) else ros_msg_type
|
||
|
||
# 提取数据
|
||
data = _extract_data(obj)
|
||
|
||
# 按照映射关系处理每个字段
|
||
for msg_name, attr_name in value_mapping.items():
|
||
msg_path = msg_name.split(".")
|
||
attr_base = attr_name.rstrip("[]")
|
||
|
||
if attr_base not in data:
|
||
continue
|
||
|
||
value = data[attr_base]
|
||
if value is None:
|
||
continue
|
||
|
||
try:
|
||
if not attr_name.endswith("[]"):
|
||
# 处理单值映射,如 {"pose.position": "position"}
|
||
current = ros_msg
|
||
for i, name in enumerate(msg_path[:-1]):
|
||
current = getattr(current, name)
|
||
|
||
last_field = msg_path[-1]
|
||
field_type = type(getattr(current, last_field))
|
||
setattr(current, last_field, convert_to_ros_msg(field_type, value))
|
||
else:
|
||
# 处理列表值映射,如 {"poses[].position": "positions[]"}
|
||
if not isinstance(value, Iterable) or isinstance(value, (str, dict)):
|
||
continue
|
||
|
||
items = list(value)
|
||
if not items:
|
||
continue
|
||
|
||
# 仅支持简单路径的数组映射
|
||
if len(msg_path) <= 2:
|
||
array_field = msg_path[0]
|
||
if hasattr(ros_msg, array_field):
|
||
if len(msg_path) == 1:
|
||
# 直接设置数组
|
||
setattr(ros_msg, array_field, items)
|
||
else:
|
||
# 设置数组元素的属性
|
||
target_field = msg_path[1]
|
||
array_items = getattr(ros_msg, array_field)
|
||
|
||
# 确保数组大小匹配
|
||
while len(array_items) < len(items):
|
||
# 添加新元素类型
|
||
if array_items:
|
||
elem_type = type(array_items[0])
|
||
array_items.append(elem_type())
|
||
else:
|
||
# 无法确定元素类型时中断
|
||
break
|
||
|
||
# 设置每个元素的属性
|
||
for i, val in enumerate(items):
|
||
if i < len(array_items):
|
||
setattr(array_items[i], target_field, val)
|
||
except Exception as e:
|
||
# 忽略映射错误
|
||
logger.debug(f"Mapping error for {msg_name} -> {attr_name}: {str(e)}")
|
||
continue
|
||
|
||
return ros_msg
|
||
|
||
|
||
def convert_from_ros_msg(msg: Any) -> Any:
|
||
"""
|
||
将ROS消息对象递归转换为Python对象
|
||
|
||
Args:
|
||
msg: ROS消息实例
|
||
|
||
Returns:
|
||
Python对象(字典或基本类型)
|
||
"""
|
||
# 使用预定义转换器
|
||
if type(msg) in _msg_converter_back:
|
||
return _msg_converter_back[type(msg)](msg)
|
||
|
||
# 处理标准ROS消息
|
||
elif hasattr(msg, "__slots__") and hasattr(msg, "_fields_and_field_types"):
|
||
result = {}
|
||
for field in msg.__slots__:
|
||
field_value = getattr(msg, field)
|
||
field_name = field[1:] if field.startswith("_") else field
|
||
result[field_name] = convert_from_ros_msg(field_value)
|
||
return result
|
||
|
||
# 处理列表或元组
|
||
elif isinstance(msg, (list, tuple)):
|
||
return [convert_from_ros_msg(item) for item in msg]
|
||
|
||
# 返回基本类型
|
||
else:
|
||
return msg
|
||
|
||
|
||
def convert_from_ros_msg_with_mapping(ros_msg: Any, value_mapping: Dict[str, str]) -> Dict[str, Any]:
|
||
"""
|
||
根据字段映射将ROS消息转换为Python字典
|
||
|
||
Args:
|
||
ros_msg: ROS消息实例
|
||
value_mapping: 字段名映射关系字典
|
||
|
||
Returns:
|
||
Python字典
|
||
"""
|
||
data: Dict[str, Any] = {}
|
||
|
||
for msg_name, attr_name in value_mapping.items():
|
||
msg_path = msg_name.split(".")
|
||
current = ros_msg
|
||
|
||
try:
|
||
if not attr_name.endswith("[]"):
|
||
# 处理单值映射
|
||
for name in msg_path:
|
||
current = getattr(current, name)
|
||
data[attr_name] = convert_from_ros_msg(current)
|
||
else:
|
||
# 处理列表值映射
|
||
for name in msg_path:
|
||
if name.endswith("[]"):
|
||
base_name = name[:-2]
|
||
if hasattr(current, base_name):
|
||
current = list(getattr(current, base_name))
|
||
else:
|
||
current = []
|
||
break
|
||
else:
|
||
if isinstance(current, list):
|
||
next_level = []
|
||
for item in current:
|
||
if hasattr(item, name):
|
||
next_level.append(getattr(item, name))
|
||
current = next_level
|
||
elif hasattr(current, name):
|
||
current = getattr(current, name)
|
||
else:
|
||
current = []
|
||
break
|
||
|
||
attr_key = attr_name[:-2]
|
||
if current:
|
||
data[attr_key] = [convert_from_ros_msg(item) for item in current]
|
||
except (AttributeError, TypeError):
|
||
logger.debug(f"Mapping conversion error for {msg_name} -> {attr_name}")
|
||
continue
|
||
|
||
return data
|
||
|
||
|
||
def set_msg_data(dtype_str: str, data: Any) -> Any:
|
||
"""
|
||
将数据转换为指定消息类型
|
||
|
||
Args:
|
||
dtype_str: 消息类型字符串
|
||
data: 要转换的数据
|
||
|
||
Returns:
|
||
转换后的数据
|
||
"""
|
||
converter = _msg_data_mapping.get(dtype_str, str)
|
||
return converter(data)
|
||
|
||
|
||
"""
|
||
ROS Action 到 JSON Schema 转换器
|
||
|
||
该模块提供了将 ROS Action 定义转换为 JSON Schema 的功能,
|
||
用于规范化 Action 接口和生成文档。
|
||
"""
|
||
|
||
import json
|
||
import yaml
|
||
from typing import Any, Dict, Type, Union, Optional
|
||
|
||
from unilabos.utils import logger
|
||
from unilabos.utils.import_manager import ImportManager
|
||
from unilabos.config.config import ROSConfig
|
||
|
||
basic_type_map = {
|
||
'bool': {'type': 'boolean'},
|
||
'int8': {'type': 'integer', 'minimum': -128, 'maximum': 127},
|
||
'uint8': {'type': 'integer', 'minimum': 0, 'maximum': 255},
|
||
'int16': {'type': 'integer', 'minimum': -32768, 'maximum': 32767},
|
||
'uint16': {'type': 'integer', 'minimum': 0, 'maximum': 65535},
|
||
'int32': {'type': 'integer', 'minimum': -2147483648, 'maximum': 2147483647},
|
||
'uint32': {'type': 'integer', 'minimum': 0, 'maximum': 4294967295},
|
||
'int64': {'type': 'integer'},
|
||
'uint64': {'type': 'integer', 'minimum': 0},
|
||
'double': {'type': 'number'},
|
||
'float': {'type': 'number'},
|
||
'float32': {'type': 'number'},
|
||
'float64': {'type': 'number'},
|
||
'string': {'type': 'string'},
|
||
'boolean': {'type': 'boolean'},
|
||
'char': {'type': 'string', 'maxLength': 1},
|
||
'byte': {'type': 'integer', 'minimum': 0, 'maximum': 255},
|
||
}
|
||
|
||
|
||
def ros_field_type_to_json_schema(type_info: Type | str, slot_type: str=None) -> Dict[str, Any]:
|
||
"""
|
||
将 ROS 字段类型转换为 JSON Schema 类型定义
|
||
|
||
Args:
|
||
type_info: ROS 类型
|
||
slot_type: ROS 类型
|
||
|
||
Returns:
|
||
对应的 JSON Schema 类型定义
|
||
"""
|
||
if isinstance(type_info, UnboundedSequence):
|
||
return {
|
||
'type': 'array',
|
||
'items': ros_field_type_to_json_schema(type_info.value_type)
|
||
}
|
||
if isinstance(type_info, NamespacedType):
|
||
cls_name = ".".join(type_info.namespaces) + ":" + type_info.name
|
||
type_class = msg_converter_manager.get_class(cls_name)
|
||
return ros_field_type_to_json_schema(type_class)
|
||
elif isinstance(type_info, BasicType):
|
||
return ros_field_type_to_json_schema(type_info.typename)
|
||
elif isinstance(type_info, UnboundedString):
|
||
return basic_type_map['string']
|
||
elif isinstance(type_info, str):
|
||
if type_info in basic_type_map:
|
||
return basic_type_map[type_info]
|
||
|
||
# 处理时间和持续时间类型
|
||
if type_info in ('time', 'duration', 'builtin_interfaces/Time', 'builtin_interfaces/Duration'):
|
||
return {
|
||
'type': 'object',
|
||
'properties': {
|
||
'sec': {'type': 'integer', 'description': '秒'},
|
||
'nanosec': {'type': 'integer', 'description': '纳秒'}
|
||
},
|
||
'required': ['sec', 'nanosec']
|
||
}
|
||
else:
|
||
return ros_message_to_json_schema(type_info)
|
||
# # 处理数组类型
|
||
# if field_type.endswith('[]'):
|
||
# item_type = field_type[:-2]
|
||
# return {
|
||
# 'type': 'array',
|
||
# 'items': ros_field_type_to_json_schema(item_type)
|
||
# }
|
||
|
||
|
||
|
||
# # 处理复杂类型(尝试加载并处理)
|
||
# try:
|
||
# # 如果它是一个完整的消息类型规范 (包名/msg/类型名)
|
||
# if '/' in field_type:
|
||
# msg_class = get_ros_type_by_msgname(field_type)
|
||
# return ros_message_to_json_schema(msg_class)
|
||
# else:
|
||
# # 可能是相对引用或简单名称
|
||
# return {'type': 'object', 'description': f'复合类型: {field_type}'}
|
||
# except Exception as e:
|
||
# # 如果无法解析,返回通用对象类型
|
||
# logger.debug(f"无法解析类型 {field_type}: {str(e)}")
|
||
# return {'type': 'object', 'description': f'未知类型: {field_type}'}
|
||
|
||
def ros_message_to_json_schema(msg_class: Any) -> Dict[str, Any]:
|
||
"""
|
||
将 ROS 消息类转换为 JSON Schema
|
||
|
||
Args:
|
||
msg_class: ROS 消息类
|
||
|
||
Returns:
|
||
对应的 JSON Schema 定义
|
||
"""
|
||
schema = {
|
||
'type': 'object',
|
||
'properties': {},
|
||
'required': []
|
||
}
|
||
|
||
# 获取类名作为标题
|
||
if hasattr(msg_class, '__name__'):
|
||
schema['title'] = msg_class.__name__
|
||
|
||
# 获取消息的字段和字段类型
|
||
try:
|
||
for ind, slot_info in enumerate(msg_class._fields_and_field_types.items()):
|
||
slot_name, slot_type = slot_info
|
||
type_info = msg_class.SLOT_TYPES[ind]
|
||
field_schema = ros_field_type_to_json_schema(type_info, slot_type)
|
||
schema['properties'][slot_name] = field_schema
|
||
schema['required'].append(slot_name)
|
||
# if hasattr(msg_class, 'get_fields_and_field_types'):
|
||
# fields_and_types = msg_class.get_fields_and_field_types()
|
||
#
|
||
# for field_name, field_type in fields_and_types.items():
|
||
# # 将 ROS 字段类型转换为 JSON Schema
|
||
# field_schema = ros_field_type_to_json_schema(field_type)
|
||
#
|
||
# schema['properties'][field_name] = field_schema
|
||
# schema['required'].append(field_name)
|
||
# elif hasattr(msg_class, '__slots__') and hasattr(msg_class, '_fields_and_field_types'):
|
||
# # 直接从实例属性获取
|
||
# for field_name in msg_class.__slots__:
|
||
# # 移除前导下划线(如果有)
|
||
# clean_name = field_name[1:] if field_name.startswith('_') else field_name
|
||
#
|
||
# # 从 _fields_and_field_types 获取类型
|
||
# if clean_name in msg_class._fields_and_field_types:
|
||
# field_type = msg_class._fields_and_field_types[clean_name]
|
||
# field_schema = ros_field_type_to_json_schema(field_type)
|
||
#
|
||
# schema['properties'][clean_name] = field_schema
|
||
# schema['required'].append(clean_name)
|
||
except Exception as e:
|
||
# 如果获取字段类型失败,添加错误信息
|
||
schema['description'] = f"解析消息字段时出错: {str(e)}"
|
||
logger.error(f"解析 {msg_class.__name__} 消息字段失败: {str(e)}")
|
||
|
||
return schema
|
||
|
||
def ros_action_to_json_schema(action_class: Any) -> Dict[str, Any]:
|
||
"""
|
||
将 ROS Action 类转换为 JSON Schema
|
||
|
||
Args:
|
||
action_class: ROS Action 类
|
||
|
||
Returns:
|
||
完整的 JSON Schema 定义
|
||
"""
|
||
if not hasattr(action_class, 'Goal') or not hasattr(action_class, 'Feedback') or not hasattr(action_class, 'Result'):
|
||
raise ValueError(f"{action_class.__name__} 不是有效的 ROS Action 类")
|
||
|
||
# 创建基础 schema
|
||
schema = {
|
||
'title': action_class.__name__,
|
||
'description': f"ROS Action {action_class.__name__} 的 JSON Schema",
|
||
'type': 'object',
|
||
'properties': {
|
||
'goal': {
|
||
'description': 'Action 目标 - 从客户端发送到服务器',
|
||
**ros_message_to_json_schema(action_class.Goal)
|
||
},
|
||
'feedback': {
|
||
'description': 'Action 反馈 - 执行过程中从服务器发送到客户端',
|
||
**ros_message_to_json_schema(action_class.Feedback)
|
||
},
|
||
'result': {
|
||
'description': 'Action 结果 - 完成后从服务器发送到客户端',
|
||
**ros_message_to_json_schema(action_class.Result)
|
||
}
|
||
},
|
||
'required': ['goal']
|
||
}
|
||
|
||
return schema
|
||
|
||
def convert_ros_action_to_jsonschema(
|
||
action_name_or_type: Union[str, Type],
|
||
output_file: Optional[str] = None,
|
||
format: str = 'json'
|
||
) -> Dict[str, Any]:
|
||
"""
|
||
将 ROS Action 类型转换为 JSON Schema,并可选地保存到文件
|
||
|
||
Args:
|
||
action_name_or_type: ROS Action 类型名称或类
|
||
output_file: 可选,输出 JSON Schema 的文件路径
|
||
format: 输出格式,'json' 或 'yaml'
|
||
|
||
Returns:
|
||
JSON Schema 定义(字典)
|
||
"""
|
||
# 处理输入参数
|
||
if isinstance(action_name_or_type, str):
|
||
# 如果是字符串,尝试加载 Action 类型
|
||
action_type = get_ros_type_by_msgname(action_name_or_type)
|
||
else:
|
||
action_type = action_name_or_type
|
||
|
||
# 生成 JSON Schema
|
||
schema = ros_action_to_json_schema(action_type)
|
||
|
||
# 如果指定了输出文件,将 Schema 保存到文件
|
||
if output_file:
|
||
if format.lower() == 'json':
|
||
with open(output_file, 'w', encoding='utf-8') as f:
|
||
json.dump(schema, f, indent=2, ensure_ascii=False)
|
||
elif format.lower() == 'yaml':
|
||
with open(output_file, 'w', encoding='utf-8') as f:
|
||
yaml.safe_dump(schema, f, default_flow_style=False, allow_unicode=True)
|
||
else:
|
||
raise ValueError(f"不支持的格式: {format},请使用 'json' 或 'yaml'")
|
||
|
||
return schema
|
||
|
||
|
||
# 示例用法
|
||
if __name__ == "__main__":
|
||
# 示例:转换 NavigateToPose action
|
||
try:
|
||
from nav2_msgs.action import NavigateToPose
|
||
|
||
# 转换为 JSON Schema 并打印
|
||
schema = convert_ros_action_to_jsonschema(NavigateToPose)
|
||
print(json.dumps(schema, indent=2, ensure_ascii=False))
|
||
|
||
# 保存到文件
|
||
# convert_ros_action_to_jsonschema(NavigateToPose, "navigate_to_pose_schema.json")
|
||
|
||
# 或者使用字符串形式的 action 名称
|
||
# schema = convert_ros_action_to_jsonschema("nav2_msgs/action/NavigateToPose")
|
||
except ImportError:
|
||
print("无法导入 NavigateToPose action,请确保已安装相关 ROS 包。")
|