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下错误注册 * 匹配init param schema格式 * Add channel_sources config in conda_build_config.yaml (#58) * 修复任务执行传参 * Create 5 new protocols & bump version 0.9.8 (#59) * 添加了5个缺失的protocol,验证了可以运行 * bump version to 0.9.8 * 修复新增的Action的字段缺失 --------- Co-authored-by: Xuwznln <18435084+Xuwznln@users.noreply.github.com> * 转换到ros消息时,要进行基础类型转换 * Update work_station.yaml (#60) * Update work_station.yaml * Checklist里面有XDL跟protocol之间没对齐的问题,工作量有点大找时间写完 * Create prcxi.py * Update prcxi.py * Update Prcxi * 更新中析仪器,以及启动示例 * 修改moveit_interface,并在mqtt上报时发送一个时间戳,方便网页端对数据的筛选 (#62) * 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 * 修改moveit_interface,并在mqtt上报时发送一个时间戳 --------- 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> * 更新实例 * 更新实例 * 更新实例 * 修正prcxi启动 * 更新PRCXI配置,修改主机地址和设置状态,并添加示例用法 * add pickup tips for prcxi * 任意执行错误都应该返回failed * 任意执行错误都应该返回failed * Add plateT6 to PRCXI configuration and enhance error handling in liquid handling * prcxi blending * assert blending_times > 0 * update prcxi * update prcxi registry * Update prcxi.py to fit the function in unilabos. * 不生成已配置action的动作,增加prcxi的debug模式 * 增加注册表版本参数,支持将auto-指令人工检查后非auto,不生成人工已检查的指令,取消不必要的description生成 * 增加注册表版本参数,支持将auto-指令人工检查后非auto,不生成人工已检查的指令,取消不必要的description生成 * Update prcxi.py * 修复了部分的protocol因为XDL更新导致的问题 (#61) * 修复了部分的protocol因为XDL更新导致的问题 但是pumptransfer,add,dissolve,separate还没修,后续还需要写virtual固体加料器 * 补充了四个action * 添加了固体加样器,丰富了json,修改了add protocol * bump version to 0.9.9 * fix bugs from new actions * protocol完整修复版本& bump version to 0.9.10 * 修补了一些单位处理,bump version to 0.9.11 * 优化了全protocol的运行时间,除了pumptransfer相关的还没 * 补充了剩下的几个protocol --------- Co-authored-by: Junhan Chang <changjh@dp.tech> Co-authored-by: Xuwznln <18435084+Xuwznln@users.noreply.github.com> * 修复action移除时的报错,更新注册表 * Update prcxi.py * Update prcxi.py * 新增simulator * Update prcxi.py * Update trash * Update prcxi.py * Update prcxi.py * Update for discard tips * Update prcxi.py * Update PRCXI * 更新axis等参数 * Update 9320 * get_well_container&get_tip_rack * update * Update 9320 * update * deck * 更新注册表&增加资源,parent应为resources字段 * Update 9320 * update * 新增set liquid方法 * 新增set liquid方法 * action to resource & 0.9.12 (#64) * action to resource & 0.9.12 * stir和adjustph的中的bug修不好 * modify prcxi * 0.9.12 update registry * update * update * registry upadte * Update * update * container_for_nothing * mix * registry fix * registry fix * registry fix * Update * Update prcxi.py * SET TIP RACK * bump version * update registry version & category * update set tip rack * yaml dump支持ordered dict,支持config_info * fix devices * fix resource check serialize * fix: Protocol node resource run (#65) * stir和adjustph的中的bug修不好 * fix sub-resource query in protocol node compiling * add resource placeholder to vessels * add the rest yaml * Update work_station.yaml --------- Co-authored-by: KCFeng425 <2100011801@stu.pku.edu.cn> * 采用http报送resource * 采用http报送resource * update * Update .gitignore * bump version to 0.10.0 * default param simulator * slim * Update * Update for prcxi * Update * Update * Refactor PRCXI9300Deck initialization and update plate configurations - Changed deck name from "PRCXI_Deck" to "PRCXI_Deck_9300". - Updated plate4 initialization to use get_well_container instead of get_tip_rack. - Modified plate4 material details with new UUID, code, and name. - Renamed output JSON file to "deck_9300_new.json". - Uncommented and adjusted liquid handling operations for clarity and future use. * test * update * Update prcxi_9300.json This one is good * update * fix protocol_node communication transfer * 修复注册表handles类型错误的问题 * 物料添加失败应该直接raise ValueError,不要等待 * 更正注册表中的数字类型 * Delete unnecessary files. * 新增lab_id直接传入 * fix vessel_id param passing in protocols * 新增dll预载,保证部分设备可正常使用unilabos_msgs * 修复可能的web template找不到的问题 新增联网获取json启动 删除非-g传入启动json的方式 兼容传参参数名短横线与下划线 * 修复可能的web template找不到的问题 新增联网获取json启动 删除非-g传入启动json的方式 兼容传参参数名短横线与下划线 更新版本到0.10.1 修复Upload Registry镜像不匹配 * 新增用户引导 * Device visualization (#67) * 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 * 修改moveit_interface,并在mqtt上报时发送一个时间戳 * 添加机械臂和移液站 * 添加 * 添加硬件 * update * 添加 --------- 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: 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> Co-authored-by: ZiWei <131428629+ZiWei09@users.noreply.github.com>
1219 lines
46 KiB
Python
1219 lines
46 KiB
Python
from pathlib import Path
|
||
import time
|
||
import rclpy,json
|
||
from rclpy.node import Node
|
||
from std_msgs.msg import String,Header
|
||
import numpy as np
|
||
from moveit_msgs.srv import GetPlanningScene, ApplyPlanningScene
|
||
from rclpy.callback_groups import ReentrantCallbackGroup
|
||
from rclpy.qos import QoSProfile, QoSDurabilityPolicy, QoSReliabilityPolicy, QoSHistoryPolicy
|
||
from moveit_msgs.msg import CollisionObject, AttachedCollisionObject, AllowedCollisionEntry, RobotState, PlanningScene
|
||
from shape_msgs.msg import Mesh, MeshTriangle, SolidPrimitive
|
||
from geometry_msgs.msg import Pose, PoseStamped, Point, Quaternion, TransformStamped
|
||
from rclpy.callback_groups import ReentrantCallbackGroup
|
||
from rclpy.qos import QoSProfile, QoSDurabilityPolicy, QoSReliabilityPolicy, QoSHistoryPolicy
|
||
from rclpy.task import Future
|
||
import copy
|
||
from typing import Tuple, Optional, Union, Any, List
|
||
from tf_transformations import quaternion_from_euler
|
||
from tf2_ros import TransformBroadcaster, Buffer, TransformListener
|
||
from rclpy.action import ActionServer
|
||
from unilabos_msgs.action import SendCmd
|
||
from rclpy.action.server import ServerGoalHandle
|
||
from unilabos.ros.nodes.base_device_node import BaseROS2DeviceNode,DeviceNodeResourceTracker
|
||
from unilabos.resources.graphio import initialize_resources
|
||
from unilabos.registry.registry import lab_registry
|
||
|
||
class ResourceMeshManager(BaseROS2DeviceNode):
|
||
def __init__(self, resource_model: dict, resource_config: list,resource_tracker, device_id: str = "resource_mesh_manager", rate=50):
|
||
"""初始化资源网格管理器节点
|
||
|
||
Args:
|
||
resource_model (dict): 资源模型字典,包含资源的3D模型信息
|
||
resource_config (dict): 资源配置字典,包含资源的配置信息
|
||
device_id (str): 节点名称
|
||
"""
|
||
super().__init__(
|
||
driver_instance=self,
|
||
device_id=device_id,
|
||
status_types={},
|
||
action_value_mappings={},
|
||
hardware_interface={},
|
||
print_publish=False,
|
||
resource_tracker=resource_tracker,
|
||
)
|
||
|
||
self.resource_model = resource_model
|
||
self.resource_config_dict = {item['id']: item for item in resource_config}
|
||
self.move_group_ready = False
|
||
self.resource_tf_dict = {}
|
||
self.tf_broadcaster = TransformBroadcaster(self)
|
||
self.tf_buffer = Buffer()
|
||
self.tf_listener = TransformListener(self.tf_buffer, self)
|
||
self.rate = rate
|
||
self.zero_count = 0
|
||
|
||
self.old_resource_pose = {}
|
||
self.__planning_scene = PlanningScene()
|
||
self.__old_planning_scene = None
|
||
self.__old_allowed_collision_matrix = None
|
||
self.mesh_path = Path(__file__).parent.parent.parent.parent.absolute()
|
||
self.msg_type = 'resource_status'
|
||
self.resource_status_dict = {}
|
||
|
||
callback_group = ReentrantCallbackGroup()
|
||
self._get_planning_scene_service = self.create_client(
|
||
srv_type=GetPlanningScene,
|
||
srv_name="/get_planning_scene",
|
||
qos_profile=QoSProfile(
|
||
durability=QoSDurabilityPolicy.VOLATILE,
|
||
reliability=QoSReliabilityPolicy.RELIABLE,
|
||
history=QoSHistoryPolicy.KEEP_LAST,
|
||
depth=1,
|
||
),
|
||
callback_group=callback_group,
|
||
)
|
||
|
||
# Create a service for applying the planning scene
|
||
self._apply_planning_scene_service = self.create_client(
|
||
srv_type=ApplyPlanningScene,
|
||
srv_name="/apply_planning_scene",
|
||
qos_profile=QoSProfile(
|
||
durability=QoSDurabilityPolicy.VOLATILE,
|
||
reliability=QoSReliabilityPolicy.RELIABLE,
|
||
history=QoSHistoryPolicy.KEEP_LAST,
|
||
depth=1,
|
||
),
|
||
callback_group=callback_group,
|
||
)
|
||
|
||
self.resource_pose_publisher = self.create_publisher(
|
||
String, f"resource_pose", 10
|
||
)
|
||
self.__collision_object_publisher = self.create_publisher(
|
||
CollisionObject, "/collision_object", 10
|
||
)
|
||
self.__planning_scene_publisher = self.create_publisher(
|
||
PlanningScene, "/planning_scene", 10
|
||
)
|
||
self.__attached_collision_object_publisher = self.create_publisher(
|
||
AttachedCollisionObject, "/attached_collision_object", 0
|
||
)
|
||
|
||
# 创建一个Action Server用于修改resource_tf_dict
|
||
self._action_server = ActionServer(
|
||
self,
|
||
SendCmd,
|
||
f"tf_update",
|
||
self.tf_update,
|
||
callback_group=callback_group
|
||
)
|
||
|
||
# 创建一个Action Server用于添加新的资源模型与resource_tf_dict
|
||
self._add_resource_mesh_action_server = ActionServer(
|
||
self,
|
||
SendCmd,
|
||
f"add_resource_mesh",
|
||
self.add_resource_mesh_callback,
|
||
callback_group=callback_group
|
||
)
|
||
|
||
self.resource_tf_dict = self.resource_mesh_setup(self.resource_config_dict)
|
||
self.create_timer(1/self.rate, self.publish_resource_tf)
|
||
self.create_timer(1/self.rate, self.check_resource_pose_changes)
|
||
|
||
def check_move_group_ready(self):
|
||
"""检查move_group节点是否已初始化完成"""
|
||
|
||
# 获取当前可用的节点列表
|
||
if len(self.resource_tf_dict) == 0:
|
||
return
|
||
tf_ready = self.tf_buffer.can_transform("world", next(iter(self.resource_tf_dict.keys())), rclpy.time.Time(),rclpy.duration.Duration(seconds=2))
|
||
|
||
# if tf_ready:
|
||
if self._get_planning_scene_service.service_is_ready() and self._apply_planning_scene_service.service_is_ready() and tf_ready:
|
||
self.move_group_ready = True
|
||
self.publish_resource_tf()
|
||
self.add_resource_collision_meshes(self.resource_tf_dict)
|
||
|
||
|
||
def add_resource_mesh_callback(self, goal_handle : ServerGoalHandle):
|
||
tf_update_msg = goal_handle.request
|
||
try:
|
||
self.add_resource_mesh(tf_update_msg.command)
|
||
except Exception as e:
|
||
self.get_logger().error(f"添加资源失败: {e}")
|
||
goal_handle.abort()
|
||
return SendCmd.Result(success=False)
|
||
goal_handle.succeed()
|
||
return SendCmd.Result(success=True)
|
||
|
||
def add_resource_mesh(self,resource_config_str:str):
|
||
"""刷新资源配置"""
|
||
|
||
registry = lab_registry
|
||
resource_config = json.loads(resource_config_str.replace("'",'"'))
|
||
|
||
if resource_config['id'] in self.resource_config_dict:
|
||
self.get_logger().info(f'资源 {resource_config["id"]} 已存在')
|
||
return
|
||
if resource_config['class'] in registry.resource_type_registry.keys():
|
||
model_config = registry.resource_type_registry[resource_config['class']]['model']
|
||
if model_config['type'] == 'resource':
|
||
self.resource_model[resource_config['id']] = {
|
||
'mesh': f"{str(self.mesh_path)}/device_mesh/resources/{model_config['mesh']}",
|
||
'mesh_tf': model_config['mesh_tf']}
|
||
if 'children_mesh' in model_config.keys():
|
||
self.resource_model[f"{resource_config['id']}_"] = {
|
||
'mesh': f"{str(self.mesh_path)}/device_mesh/resources/{model_config['children_mesh']}",
|
||
'mesh_tf': model_config['children_mesh_tf']
|
||
}
|
||
resources = initialize_resources([resource_config])
|
||
resource_dict = {item['id']: item for item in resources}
|
||
self.resource_config_dict = {**self.resource_config_dict,**resource_dict}
|
||
tf_dict = self.resource_mesh_setup(resource_dict)
|
||
self.resource_tf_dict = {**self.resource_tf_dict,**tf_dict}
|
||
self.publish_resource_tf()
|
||
self.add_resource_collision_meshes(tf_dict)
|
||
|
||
|
||
def resource_mesh_setup(self, resource_config_dict:dict):
|
||
"""move_group初始化完成后的设置"""
|
||
self.get_logger().info('开始设置资源网格管理器')
|
||
#遍历resource_config中的资源配置,判断panent是否在resource_model中,
|
||
resource_tf_dict = {}
|
||
for resource_id, resource_config in resource_config_dict.items():
|
||
|
||
parent = resource_config['parent']
|
||
parent_link = 'world'
|
||
if parent in self.resource_model:
|
||
parent_link = parent
|
||
elif parent is None and resource_id in self.resource_model:
|
||
|
||
pass
|
||
elif parent is not None and resource_id in self.resource_model:
|
||
# parent_link = f"{self.resource_config_dict[parent]['parent']}_{parent}_device_link".replace("None_","")
|
||
parent_link = f"{parent}_device_link".replace("None_","")
|
||
|
||
else:
|
||
continue
|
||
# 提取位置信息并转换单位
|
||
position = {
|
||
"x": float(resource_config['position']['x'])/1000,
|
||
"y": float(resource_config['position']['y'])/1000,
|
||
"z": float(resource_config['position']['z'])/1000
|
||
}
|
||
|
||
rotation_dict = {
|
||
"x": 0,
|
||
"y": 0,
|
||
"z": 0
|
||
}
|
||
|
||
if 'rotation' in resource_config['config']:
|
||
rotation_dict = resource_config['config']['rotation']
|
||
|
||
# 从欧拉角转换为四元数
|
||
q = quaternion_from_euler(
|
||
float(rotation_dict['x']),
|
||
float(rotation_dict['y']),
|
||
float(rotation_dict['z'])
|
||
)
|
||
|
||
rotation = {
|
||
"x": q[0],
|
||
"y": q[1],
|
||
"z": q[2],
|
||
"w": q[3]
|
||
}
|
||
|
||
# 更新资源TF字典
|
||
resource_tf_dict[resource_id] = {
|
||
"parent": parent_link,
|
||
"position": position,
|
||
"rotation": rotation
|
||
}
|
||
|
||
return resource_tf_dict
|
||
|
||
|
||
def publish_resource_tf(self):
|
||
"""
|
||
发布资源之间的TF关系
|
||
|
||
遍历self.resource_tf_dict中的每个元素,根据key,parent,以及position和rotation,
|
||
发布key和parent之间的tf关系
|
||
"""
|
||
|
||
transforms = []
|
||
|
||
# 遍历资源TF字典
|
||
resource_tf_dict = copy.deepcopy(self.resource_tf_dict)
|
||
for resource_id, tf_info in resource_tf_dict.items():
|
||
parent = tf_info['parent']
|
||
position = tf_info['position']
|
||
rotation = tf_info['rotation']
|
||
|
||
# 创建静态变换消息
|
||
|
||
transform = TransformStamped()
|
||
transform.header.stamp = self.get_clock().now().to_msg()
|
||
transform.header.frame_id = parent
|
||
transform.child_frame_id = resource_id
|
||
|
||
# 设置位置
|
||
transform.transform.translation.x = float(position['x'])
|
||
transform.transform.translation.y = float(position['y'])
|
||
transform.transform.translation.z = float(position['z'])
|
||
|
||
# 设置旋转
|
||
transform.transform.rotation.x = rotation['x']
|
||
transform.transform.rotation.y = rotation['y']
|
||
transform.transform.rotation.z = rotation['z']
|
||
transform.transform.rotation.w = rotation['w']
|
||
|
||
transforms.append(transform)
|
||
|
||
# 一次性发布所有静态变换
|
||
if transforms:
|
||
self.tf_broadcaster.sendTransform(transforms)
|
||
# self.check_resource_pose_changes()
|
||
# self.get_logger().info(f'已发布 {len(transforms)} 个资源TF关系')
|
||
|
||
|
||
def check_resource_pose_changes(self):
|
||
"""
|
||
遍历资源TF字典,计算每个资源相对于world的变换,
|
||
与旧的位姿比较,记录发生变化的资源,并更新旧位姿记录。
|
||
|
||
Returns:
|
||
dict: 包含发生位姿变化的资源ID及其新位姿
|
||
"""
|
||
if not self.move_group_ready:
|
||
self.check_move_group_ready()
|
||
return
|
||
changed_poses = {}
|
||
resource_tf_dict = copy.deepcopy(self.resource_tf_dict)
|
||
if self.msg_type == 'resource_pose':
|
||
for resource_id in resource_tf_dict.keys():
|
||
try:
|
||
# 获取从resource_id到world的转换
|
||
|
||
transform = self.tf_buffer.lookup_transform(
|
||
"world",
|
||
resource_id,
|
||
rclpy.time.Time(seconds=0),
|
||
# rclpy.duration.Duration(seconds=5)
|
||
)
|
||
|
||
# 提取当前位姿信息
|
||
current_pose = {
|
||
"position": {
|
||
"x": transform.transform.translation.x,
|
||
"y": transform.transform.translation.y,
|
||
"z": transform.transform.translation.z
|
||
},
|
||
"rotation": {
|
||
"x": transform.transform.rotation.x,
|
||
"y": transform.transform.rotation.y,
|
||
"z": transform.transform.rotation.z,
|
||
"w": transform.transform.rotation.w
|
||
}
|
||
}
|
||
|
||
# 检查是否存在旧位姿记录
|
||
if resource_id not in self.old_resource_pose:
|
||
# 如果没有旧记录,则认为是新资源,记录变化
|
||
changed_poses[resource_id] = current_pose
|
||
self.old_resource_pose[resource_id] = current_pose
|
||
else:
|
||
# 比较当前位姿与旧位姿
|
||
old_pose = self.old_resource_pose[resource_id]
|
||
if (not self._is_pose_equal(current_pose, old_pose)):
|
||
# 如果位姿发生变化,记录新位姿
|
||
changed_poses[resource_id] = current_pose
|
||
self.old_resource_pose[resource_id] = current_pose
|
||
|
||
except Exception as e:
|
||
self.get_logger().warning(f"获取资源 {resource_id} 的世界坐标变换失败: {e}")
|
||
|
||
elif self.msg_type == 'resource_status':
|
||
for resource_id, resource_status in resource_tf_dict.items():
|
||
if resource_id not in self.old_resource_pose:
|
||
# 如果没有旧记录,则认为是新资源,记录变化
|
||
changed_poses[resource_id] = resource_status['parent']
|
||
self.old_resource_pose[resource_id] = resource_status['parent']
|
||
else:
|
||
# 比较当前位姿与旧位姿
|
||
old_pose = self.old_resource_pose[resource_id]
|
||
if resource_status['parent'] != old_pose:
|
||
# 如果位姿发生变化,记录新位姿
|
||
changed_poses[resource_id] = resource_status['parent']
|
||
self.old_resource_pose[resource_id] = resource_status['parent']
|
||
|
||
|
||
if changed_poses != {}:
|
||
self.zero_count = 0
|
||
changed_poses_msg = String()
|
||
changed_poses_msg.data = json.dumps(changed_poses)
|
||
self.resource_pose_publisher.publish(changed_poses_msg)
|
||
else:
|
||
if self.zero_count > self.rate:
|
||
self.zero_count = 0
|
||
changed_poses_msg = String()
|
||
changed_poses_msg.data = json.dumps(changed_poses)
|
||
self.resource_pose_publisher.publish(changed_poses_msg)
|
||
self.zero_count += 1
|
||
|
||
|
||
def _is_pose_equal(self, pose1, pose2, tolerance=1e-7):
|
||
"""
|
||
比较两个位姿是否相等(考虑浮点数精度)
|
||
|
||
Args:
|
||
pose1: 第一个位姿
|
||
pose2: 第二个位姿
|
||
tolerance: 浮点数比较的容差
|
||
|
||
Returns:
|
||
bool: 如果位姿相等返回True,否则返回False
|
||
"""
|
||
# 比较位置
|
||
pos1 = pose1["position"]
|
||
pos2 = pose2["position"]
|
||
if (abs(pos1["x"] - pos2["x"]) > tolerance or
|
||
abs(pos1["y"] - pos2["y"]) > tolerance or
|
||
abs(pos1["z"] - pos2["z"]) > tolerance):
|
||
return False
|
||
|
||
# 比较旋转
|
||
rot1 = pose1["rotation"]
|
||
rot2 = pose2["rotation"]
|
||
if (abs(rot1["x"] - rot2["x"]) > tolerance or
|
||
abs(rot1["y"] - rot2["y"]) > tolerance or
|
||
abs(rot1["z"] - rot2["z"]) > tolerance or
|
||
abs(rot1["w"] - rot2["w"]) > tolerance):
|
||
return False
|
||
|
||
return True
|
||
|
||
def tf_update(self, goal_handle : ServerGoalHandle):
|
||
tf_update_msg = goal_handle.request
|
||
|
||
try:
|
||
cmd_dict = json.loads(tf_update_msg.command.replace("'",'"'))
|
||
self.__planning_scene = self._get_planning_scene_service.call(
|
||
GetPlanningScene.Request()
|
||
).scene
|
||
self.__planning_scene.is_diff = True
|
||
planning_scene = PlanningScene()
|
||
planning_scene.is_diff = True
|
||
planning_scene.robot_state.is_diff = True
|
||
# time_start = self.get_clock().now()
|
||
time_start = rclpy.time.Time(seconds=0)
|
||
count = 0
|
||
|
||
for resource_id, target_parent in cmd_dict.items():
|
||
parent_id = target_parent
|
||
if target_parent == '__trash':
|
||
parent_id = 'world'
|
||
# 获取从resource_id到target_parent的转换
|
||
transform = self.tf_buffer.lookup_transform(
|
||
parent_id,
|
||
resource_id,
|
||
time_start,
|
||
timeout=rclpy.duration.Duration(seconds=10)
|
||
)
|
||
|
||
# 提取转换中的位置和旋转信息
|
||
position = {
|
||
"x": transform.transform.translation.x,
|
||
"y": transform.transform.translation.y,
|
||
"z": transform.transform.translation.z
|
||
}
|
||
|
||
rotation = {
|
||
"x": transform.transform.rotation.x,
|
||
"y": transform.transform.rotation.y,
|
||
"z": transform.transform.rotation.z,
|
||
"w": transform.transform.rotation.w
|
||
}
|
||
|
||
self.resource_tf_dict[resource_id] = {
|
||
"parent": parent_id,
|
||
"position": position,
|
||
"rotation": rotation
|
||
}
|
||
|
||
|
||
# self.attach_collision_object(id=resource_id,link_name=target_parent)
|
||
# time.sleep(0.02)
|
||
operation_attach = CollisionObject.ADD
|
||
operation_world = CollisionObject.REMOVE
|
||
if target_parent == 'world':
|
||
operation_attach = CollisionObject.REMOVE
|
||
operation_world = CollisionObject.ADD
|
||
elif target_parent == '__trash':
|
||
operation_attach = CollisionObject.REMOVE
|
||
|
||
world_object = CollisionObject(
|
||
id=resource_id,
|
||
operation=operation_world
|
||
)
|
||
if target_parent != '__trash':
|
||
planning_scene.world.collision_objects.append(world_object)
|
||
|
||
|
||
collision_object = AttachedCollisionObject(
|
||
object=CollisionObject(
|
||
id=resource_id,
|
||
operation=operation_attach
|
||
)
|
||
)
|
||
if target_parent != 'world' and target_parent != '__trash':
|
||
collision_object.link_name = target_parent
|
||
planning_scene.robot_state.attached_collision_objects.append(collision_object)
|
||
|
||
count += 1
|
||
|
||
if count > 30:
|
||
req = ApplyPlanningScene.Request()
|
||
req.scene = planning_scene
|
||
self.publish_resource_tf()
|
||
self._apply_planning_scene_service.call(req)
|
||
self.__planning_scene_publisher.publish(planning_scene)
|
||
count = 0
|
||
|
||
planning_scene = PlanningScene()
|
||
planning_scene.is_diff = True
|
||
planning_scene.robot_state.is_diff = True
|
||
|
||
req = ApplyPlanningScene.Request()
|
||
req.scene = planning_scene
|
||
self.publish_resource_tf()
|
||
self._apply_planning_scene_service.call(req)
|
||
self.__planning_scene_publisher.publish(planning_scene)
|
||
|
||
# self.__collision_object_publisher.publish(CollisionObject())
|
||
|
||
|
||
except Exception as e:
|
||
self.get_logger().error(f"更新资源TF字典失败: {e}")
|
||
goal_handle.abort()
|
||
return SendCmd.Result(success=False)
|
||
goal_handle.succeed()
|
||
return SendCmd.Result(success=True)
|
||
|
||
|
||
|
||
def add_resource_collision_meshes(self,resource_tf_dict:dict):
|
||
"""
|
||
遍历资源配置字典,为每个在resource_model中有对应模型的资源添加碰撞网格
|
||
|
||
该方法检查每个资源ID是否在self.resource_model中有对应的3D模型文件路径,
|
||
|
||
"""
|
||
self.get_logger().info('开始添加资源碰撞网格')
|
||
|
||
self.__planning_scene = self._get_planning_scene_service.call(
|
||
GetPlanningScene.Request()
|
||
).scene
|
||
planning_scene = PlanningScene()
|
||
planning_scene.is_diff = True
|
||
count = 0
|
||
for resource_id, tf_info in resource_tf_dict.items():
|
||
|
||
if resource_id in self.resource_model:
|
||
# 获取位置信息
|
||
|
||
position = [
|
||
float(self.resource_model[resource_id]['mesh_tf'][0]),
|
||
float(self.resource_model[resource_id]['mesh_tf'][1]),
|
||
float(self.resource_model[resource_id]['mesh_tf'][2])
|
||
]
|
||
|
||
# 获取旋转信息并转换为四元数
|
||
|
||
q = quaternion_from_euler(
|
||
float(self.resource_model[resource_id]['mesh_tf'][3]),
|
||
float(self.resource_model[resource_id]['mesh_tf'][4]),
|
||
float(self.resource_model[resource_id]['mesh_tf'][5])
|
||
)
|
||
|
||
# 添加碰撞网格
|
||
collision_object = self.get_collision_mesh(
|
||
filepath=self.resource_model[resource_id]['mesh'],
|
||
id=resource_id,
|
||
position=position,
|
||
quat_xyzw=q,
|
||
frame_id=resource_id
|
||
)
|
||
count += 1
|
||
planning_scene.world.collision_objects.append(collision_object)
|
||
elif f"{tf_info['parent']}_" in self.resource_model:
|
||
# 获取资源的父级框架ID
|
||
id_ = f"{tf_info['parent']}_"
|
||
|
||
# 获取位置信息
|
||
position = [
|
||
float(self.resource_model[id_]['mesh_tf'][0]),
|
||
float(self.resource_model[id_]['mesh_tf'][1]),
|
||
float(self.resource_model[id_]['mesh_tf'][2])
|
||
]
|
||
|
||
# 获取旋转信息并转换为四元数
|
||
|
||
q = quaternion_from_euler(
|
||
float(self.resource_model[id_]['mesh_tf'][3]),
|
||
float(self.resource_model[id_]['mesh_tf'][4]),
|
||
float(self.resource_model[id_]['mesh_tf'][5])
|
||
)
|
||
|
||
# 添加碰撞网格
|
||
collision_object = self.get_collision_mesh(
|
||
filepath=self.resource_model[id_]['mesh'],
|
||
id=resource_id,
|
||
position=position,
|
||
quat_xyzw=q,
|
||
frame_id=resource_id
|
||
)
|
||
count += 1
|
||
planning_scene.world.collision_objects.append(collision_object)
|
||
|
||
if count > 30:
|
||
req = ApplyPlanningScene.Request()
|
||
req.scene = planning_scene
|
||
self.publish_resource_tf()
|
||
self._apply_planning_scene_service.call(req)
|
||
self.__planning_scene_publisher.publish(planning_scene)
|
||
count = 0
|
||
|
||
planning_scene = PlanningScene()
|
||
planning_scene.is_diff = True
|
||
|
||
req = ApplyPlanningScene.Request()
|
||
req.scene = planning_scene
|
||
self.publish_resource_tf()
|
||
self._apply_planning_scene_service.call(req)
|
||
self.__planning_scene_publisher.publish(planning_scene)
|
||
|
||
self.get_logger().info('资源碰撞网格添加完成')
|
||
|
||
|
||
def add_collision_primitive(
|
||
self,
|
||
id: str,
|
||
primitive_type: int,
|
||
dimensions: Tuple[float, float, float],
|
||
pose: Optional[Union[PoseStamped, Pose]] = None,
|
||
position: Optional[Union[Point, Tuple[float, float, float]]] = None,
|
||
quat_xyzw: Optional[
|
||
Union[Quaternion, Tuple[float, float, float, float]]
|
||
] = None,
|
||
frame_id: Optional[str] = None,
|
||
operation: int = CollisionObject.ADD,
|
||
):
|
||
"""
|
||
Add collision object with a primitive geometry specified by its dimensions.
|
||
|
||
`primitive_type` can be one of the following:
|
||
- `SolidPrimitive.BOX`
|
||
- `SolidPrimitive.SPHERE`
|
||
- `SolidPrimitive.CYLINDER`
|
||
- `SolidPrimitive.CONE`
|
||
"""
|
||
|
||
if (pose is None) and (position is None or quat_xyzw is None):
|
||
raise ValueError(
|
||
"Either `pose` or `position` and `quat_xyzw` must be specified!"
|
||
)
|
||
|
||
if isinstance(pose, PoseStamped):
|
||
pose_stamped = pose
|
||
elif isinstance(pose, Pose):
|
||
pose_stamped = PoseStamped(
|
||
header=Header(
|
||
stamp=self.get_clock().now().to_msg(),
|
||
frame_id=(
|
||
frame_id if frame_id is not None else self.__base_link_name
|
||
),
|
||
),
|
||
pose=pose,
|
||
)
|
||
else:
|
||
if not isinstance(position, Point):
|
||
position = Point(
|
||
x=float(position[0]), y=float(position[1]), z=float(position[2])
|
||
)
|
||
if not isinstance(quat_xyzw, Quaternion):
|
||
quat_xyzw = Quaternion(
|
||
x=float(quat_xyzw[0]),
|
||
y=float(quat_xyzw[1]),
|
||
z=float(quat_xyzw[2]),
|
||
w=float(quat_xyzw[3]),
|
||
)
|
||
pose_stamped = PoseStamped(
|
||
header=Header(
|
||
stamp=self.get_clock().now().to_msg(),
|
||
frame_id=(
|
||
frame_id if frame_id is not None else self.__base_link_name
|
||
),
|
||
),
|
||
pose=Pose(position=position, orientation=quat_xyzw),
|
||
)
|
||
|
||
msg = CollisionObject(
|
||
header=pose_stamped.header,
|
||
id=id,
|
||
operation=operation,
|
||
pose=pose_stamped.pose,
|
||
)
|
||
|
||
msg.primitives.append(
|
||
SolidPrimitive(type=primitive_type, dimensions=dimensions)
|
||
)
|
||
|
||
self.__collision_object_publisher.publish(msg)
|
||
|
||
def add_collision_box(
|
||
self,
|
||
id: str,
|
||
size: Tuple[float, float, float],
|
||
pose: Optional[Union[PoseStamped, Pose]] = None,
|
||
position: Optional[Union[Point, Tuple[float, float, float]]] = None,
|
||
quat_xyzw: Optional[
|
||
Union[Quaternion, Tuple[float, float, float, float]]
|
||
] = None,
|
||
frame_id: Optional[str] = None,
|
||
operation: int = CollisionObject.ADD,
|
||
):
|
||
"""
|
||
Add collision object with a box geometry specified by its size.
|
||
"""
|
||
|
||
assert len(size) == 3, "Invalid size of the box!"
|
||
|
||
self.add_collision_primitive(
|
||
id=id,
|
||
primitive_type=SolidPrimitive.BOX,
|
||
dimensions=size,
|
||
pose=pose,
|
||
position=position,
|
||
quat_xyzw=quat_xyzw,
|
||
frame_id=frame_id,
|
||
operation=operation,
|
||
)
|
||
|
||
def add_collision_sphere(
|
||
self,
|
||
id: str,
|
||
radius: float,
|
||
pose: Optional[Union[PoseStamped, Pose]] = None,
|
||
position: Optional[Union[Point, Tuple[float, float, float]]] = None,
|
||
quat_xyzw: Optional[
|
||
Union[Quaternion, Tuple[float, float, float, float]]
|
||
] = None,
|
||
frame_id: Optional[str] = None,
|
||
operation: int = CollisionObject.ADD,
|
||
):
|
||
"""
|
||
Add collision object with a sphere geometry specified by its radius.
|
||
"""
|
||
|
||
if quat_xyzw is None:
|
||
quat_xyzw = Quaternion(x=0.0, y=0.0, z=0.0, w=1.0)
|
||
|
||
self.add_collision_primitive(
|
||
id=id,
|
||
primitive_type=SolidPrimitive.SPHERE,
|
||
dimensions=[
|
||
radius,
|
||
],
|
||
pose=pose,
|
||
position=position,
|
||
quat_xyzw=quat_xyzw,
|
||
frame_id=frame_id,
|
||
operation=operation,
|
||
)
|
||
|
||
def add_collision_cylinder(
|
||
self,
|
||
id: str,
|
||
height: float,
|
||
radius: float,
|
||
pose: Optional[Union[PoseStamped, Pose]] = None,
|
||
position: Optional[Union[Point, Tuple[float, float, float]]] = None,
|
||
quat_xyzw: Optional[
|
||
Union[Quaternion, Tuple[float, float, float, float]]
|
||
] = None,
|
||
frame_id: Optional[str] = None,
|
||
operation: int = CollisionObject.ADD,
|
||
):
|
||
"""
|
||
Add collision object with a cylinder geometry specified by its height and radius.
|
||
"""
|
||
|
||
self.add_collision_primitive(
|
||
id=id,
|
||
primitive_type=SolidPrimitive.CYLINDER,
|
||
dimensions=[height, radius],
|
||
pose=pose,
|
||
position=position,
|
||
quat_xyzw=quat_xyzw,
|
||
frame_id=frame_id,
|
||
operation=operation,
|
||
)
|
||
|
||
def add_collision_cone(
|
||
self,
|
||
id: str,
|
||
height: float,
|
||
radius: float,
|
||
pose: Optional[Union[PoseStamped, Pose]] = None,
|
||
position: Optional[Union[Point, Tuple[float, float, float]]] = None,
|
||
quat_xyzw: Optional[
|
||
Union[Quaternion, Tuple[float, float, float, float]]
|
||
] = None,
|
||
frame_id: Optional[str] = None,
|
||
operation: int = CollisionObject.ADD,
|
||
):
|
||
"""
|
||
Add collision object with a cone geometry specified by its height and radius.
|
||
"""
|
||
|
||
self.add_collision_primitive(
|
||
id=id,
|
||
primitive_type=SolidPrimitive.CONE,
|
||
dimensions=[height, radius],
|
||
pose=pose,
|
||
position=position,
|
||
quat_xyzw=quat_xyzw,
|
||
frame_id=frame_id,
|
||
operation=operation,
|
||
)
|
||
|
||
def get_collision_mesh(
|
||
self,
|
||
filepath: Optional[str],
|
||
id: str,
|
||
pose: Optional[Union[PoseStamped, Pose]] = None,
|
||
position: Optional[Union[Point, Tuple[float, float, float]]] = None,
|
||
quat_xyzw: Optional[
|
||
Union[Quaternion, Tuple[float, float, float, float]]
|
||
] = None,
|
||
frame_id: Optional[str] = None,
|
||
operation: int = CollisionObject.ADD,
|
||
scale: Union[float, Tuple[float, float, float]] = 1.0,
|
||
mesh: Optional[Any] = None,
|
||
):
|
||
"""
|
||
Add collision object with a mesh geometry. Either `filepath` must be
|
||
specified or `mesh` must be provided.
|
||
Note: This function required 'trimesh' Python module to be installed.
|
||
"""
|
||
|
||
# Load the mesh
|
||
try:
|
||
import trimesh
|
||
except ImportError as err:
|
||
raise ImportError(
|
||
"Python module 'trimesh' not found! Please install it manually in order "
|
||
"to add collision objects into the MoveIt 2 planning scene."
|
||
) from err
|
||
|
||
# Check the parameters
|
||
if (pose is None) and (position is None or quat_xyzw is None):
|
||
raise ValueError(
|
||
"Either `pose` or `position` and `quat_xyzw` must be specified!"
|
||
)
|
||
if (filepath is None and mesh is None) or (
|
||
filepath is not None and mesh is not None
|
||
):
|
||
raise ValueError("Exactly one of `filepath` or `mesh` must be specified!")
|
||
if mesh is not None and not isinstance(mesh, trimesh.Trimesh):
|
||
raise ValueError("`mesh` must be an instance of `trimesh.Trimesh`!")
|
||
|
||
if isinstance(pose, PoseStamped):
|
||
pose_stamped = pose
|
||
elif isinstance(pose, Pose):
|
||
pose_stamped = PoseStamped(
|
||
header=Header(
|
||
stamp=self.get_clock().now().to_msg(),
|
||
frame_id=(
|
||
frame_id if frame_id is not None else self.__base_link_name
|
||
),
|
||
),
|
||
pose=pose,
|
||
)
|
||
else:
|
||
if not isinstance(position, Point):
|
||
position = Point(
|
||
x=float(position[0]), y=float(position[1]), z=float(position[2])
|
||
)
|
||
if not isinstance(quat_xyzw, Quaternion):
|
||
quat_xyzw = Quaternion(
|
||
x=float(quat_xyzw[0]),
|
||
y=float(quat_xyzw[1]),
|
||
z=float(quat_xyzw[2]),
|
||
w=float(quat_xyzw[3]),
|
||
)
|
||
pose_stamped = PoseStamped(
|
||
header=Header(
|
||
stamp=self.get_clock().now().to_msg(),
|
||
frame_id=(
|
||
frame_id if frame_id is not None else self.__base_link_name
|
||
),
|
||
),
|
||
pose=Pose(position=position, orientation=quat_xyzw),
|
||
)
|
||
|
||
msg = CollisionObject(
|
||
header=pose_stamped.header,
|
||
id=id,
|
||
operation=operation,
|
||
pose=pose_stamped.pose,
|
||
)
|
||
|
||
if filepath is not None:
|
||
mesh = trimesh.load(filepath)
|
||
|
||
# Scale the mesh
|
||
if isinstance(scale, float):
|
||
scale = (scale, scale, scale)
|
||
if not (scale[0] == scale[1] == scale[2] == 1.0):
|
||
# If the mesh was passed in as a parameter, make a copy of it to
|
||
# avoid transforming the original.
|
||
if filepath is not None:
|
||
mesh = mesh.copy()
|
||
# Transform the mesh
|
||
transform = np.eye(4)
|
||
np.fill_diagonal(transform, scale)
|
||
mesh.apply_transform(transform)
|
||
|
||
msg.meshes.append(
|
||
Mesh(
|
||
triangles=[MeshTriangle(vertex_indices=face) for face in mesh.faces],
|
||
vertices=[
|
||
Point(x=vert[0], y=vert[1], z=vert[2]) for vert in mesh.vertices
|
||
],
|
||
)
|
||
)
|
||
|
||
# self.__collision_object_publisher.publish(msg)
|
||
return msg
|
||
|
||
def add_collision_mesh(
|
||
self,
|
||
filepath: Optional[str],
|
||
id: str,
|
||
pose: Optional[Union[PoseStamped, Pose]] = None,
|
||
position: Optional[Union[Point, Tuple[float, float, float]]] = None,
|
||
quat_xyzw: Optional[
|
||
Union[Quaternion, Tuple[float, float, float, float]]
|
||
] = None,
|
||
frame_id: Optional[str] = None,
|
||
operation: int = CollisionObject.ADD,
|
||
scale: Union[float, Tuple[float, float, float]] = 1.0,
|
||
mesh: Optional[Any] = None,
|
||
):
|
||
"""
|
||
Add collision object with a mesh geometry. Either `filepath` must be
|
||
specified or `mesh` must be provided.
|
||
Note: This function required 'trimesh' Python module to be installed.
|
||
"""
|
||
|
||
# Load the mesh
|
||
try:
|
||
import trimesh
|
||
except ImportError as err:
|
||
raise ImportError(
|
||
"Python module 'trimesh' not found! Please install it manually in order "
|
||
"to add collision objects into the MoveIt 2 planning scene."
|
||
) from err
|
||
|
||
# Check the parameters
|
||
if (pose is None) and (position is None or quat_xyzw is None):
|
||
raise ValueError(
|
||
"Either `pose` or `position` and `quat_xyzw` must be specified!"
|
||
)
|
||
if (filepath is None and mesh is None) or (
|
||
filepath is not None and mesh is not None
|
||
):
|
||
raise ValueError("Exactly one of `filepath` or `mesh` must be specified!")
|
||
if mesh is not None and not isinstance(mesh, trimesh.Trimesh):
|
||
raise ValueError("`mesh` must be an instance of `trimesh.Trimesh`!")
|
||
|
||
if isinstance(pose, PoseStamped):
|
||
pose_stamped = pose
|
||
elif isinstance(pose, Pose):
|
||
pose_stamped = PoseStamped(
|
||
header=Header(
|
||
stamp=self.get_clock().now().to_msg(),
|
||
frame_id=(
|
||
frame_id if frame_id is not None else self.__base_link_name
|
||
),
|
||
),
|
||
pose=pose,
|
||
)
|
||
else:
|
||
if not isinstance(position, Point):
|
||
position = Point(
|
||
x=float(position[0]), y=float(position[1]), z=float(position[2])
|
||
)
|
||
if not isinstance(quat_xyzw, Quaternion):
|
||
quat_xyzw = Quaternion(
|
||
x=float(quat_xyzw[0]),
|
||
y=float(quat_xyzw[1]),
|
||
z=float(quat_xyzw[2]),
|
||
w=float(quat_xyzw[3]),
|
||
)
|
||
pose_stamped = PoseStamped(
|
||
header=Header(
|
||
stamp=self.get_clock().now().to_msg(),
|
||
frame_id=(
|
||
frame_id if frame_id is not None else self.__base_link_name
|
||
),
|
||
),
|
||
pose=Pose(position=position, orientation=quat_xyzw),
|
||
)
|
||
|
||
msg = CollisionObject(
|
||
header=pose_stamped.header,
|
||
id=id,
|
||
operation=operation,
|
||
pose=pose_stamped.pose,
|
||
)
|
||
|
||
if filepath is not None:
|
||
mesh = trimesh.load(filepath)
|
||
|
||
# Scale the mesh
|
||
if isinstance(scale, float):
|
||
scale = (scale, scale, scale)
|
||
if not (scale[0] == scale[1] == scale[2] == 1.0):
|
||
# If the mesh was passed in as a parameter, make a copy of it to
|
||
# avoid transforming the original.
|
||
if filepath is not None:
|
||
mesh = mesh.copy()
|
||
# Transform the mesh
|
||
transform = np.eye(4)
|
||
np.fill_diagonal(transform, scale)
|
||
mesh.apply_transform(transform)
|
||
|
||
msg.meshes.append(
|
||
Mesh(
|
||
triangles=[MeshTriangle(vertex_indices=face) for face in mesh.faces],
|
||
vertices=[
|
||
Point(x=vert[0], y=vert[1], z=vert[2]) for vert in mesh.vertices
|
||
],
|
||
)
|
||
)
|
||
|
||
self.__collision_object_publisher.publish(msg)
|
||
|
||
def remove_collision_object(self, id: str):
|
||
"""
|
||
Remove collision object specified by its `id`.
|
||
"""
|
||
|
||
msg = CollisionObject()
|
||
msg.id = id
|
||
msg.operation = CollisionObject.REMOVE
|
||
msg.header.stamp = self.get_clock().now().to_msg()
|
||
self.__collision_object_publisher.publish(msg)
|
||
|
||
def remove_collision_mesh(self, id: str):
|
||
"""
|
||
Remove collision mesh specified by its `id`.
|
||
Identical to `remove_collision_object()`.
|
||
"""
|
||
|
||
self.remove_collision_object(id)
|
||
|
||
def attach_collision_object(
|
||
self,
|
||
id: str,
|
||
link_name: Optional[str] = None,
|
||
touch_links: List[str] = [],
|
||
weight: float = 0.0,
|
||
):
|
||
"""
|
||
Attach collision object to the robot.
|
||
"""
|
||
|
||
msg = AttachedCollisionObject(
|
||
object=CollisionObject(id=id, operation=CollisionObject.ADD)
|
||
)
|
||
msg.link_name = link_name
|
||
msg.touch_links = touch_links
|
||
msg.weight = weight
|
||
|
||
self.__attached_collision_object_publisher.publish(msg)
|
||
|
||
def detach_collision_object(self, id: int):
|
||
"""
|
||
Detach collision object from the robot.
|
||
"""
|
||
|
||
msg = AttachedCollisionObject(
|
||
object=CollisionObject(id=id, operation=CollisionObject.REMOVE)
|
||
)
|
||
self.__attached_collision_object_publisher.publish(msg)
|
||
|
||
def detach_all_collision_objects(self):
|
||
"""
|
||
Detach collision object from the robot.
|
||
"""
|
||
|
||
msg = AttachedCollisionObject(
|
||
object=CollisionObject(operation=CollisionObject.REMOVE)
|
||
)
|
||
self.__attached_collision_object_publisher.publish(msg)
|
||
|
||
def move_collision(
|
||
self,
|
||
id: str,
|
||
position: Union[Point, Tuple[float, float, float]],
|
||
quat_xyzw: Union[Quaternion, Tuple[float, float, float, float]],
|
||
frame_id: Optional[str] = None,
|
||
):
|
||
"""
|
||
Move collision object specified by its `id`.
|
||
"""
|
||
|
||
msg = CollisionObject()
|
||
|
||
if not isinstance(position, Point):
|
||
position = Point(
|
||
x=float(position[0]), y=float(position[1]), z=float(position[2])
|
||
)
|
||
if not isinstance(quat_xyzw, Quaternion):
|
||
quat_xyzw = Quaternion(
|
||
x=float(quat_xyzw[0]),
|
||
y=float(quat_xyzw[1]),
|
||
z=float(quat_xyzw[2]),
|
||
w=float(quat_xyzw[3]),
|
||
)
|
||
|
||
pose = Pose()
|
||
pose.position = position
|
||
pose.orientation = quat_xyzw
|
||
msg.pose = pose
|
||
msg.id = id
|
||
msg.operation = CollisionObject.MOVE
|
||
msg.header.frame_id = (
|
||
frame_id if frame_id is not None else self.__base_link_name
|
||
)
|
||
msg.header.stamp = self.get_clock().now().to_msg()
|
||
|
||
self.__collision_object_publisher.publish(msg)
|
||
|
||
def update_planning_scene(self) -> bool:
|
||
"""
|
||
Gets the current planning scene. Returns whether the service call was
|
||
successful.
|
||
"""
|
||
|
||
if not self._get_planning_scene_service.service_is_ready():
|
||
self.get_logger().warn(
|
||
f"Service '{self._get_planning_scene_service.srv_name}' is not yet available. Better luck next time!"
|
||
)
|
||
return False
|
||
self.__planning_scene = self._get_planning_scene_service.call(
|
||
GetPlanningScene.Request()
|
||
).scene
|
||
return True
|
||
|
||
def allow_collisions(self, id: str, allow: bool) -> Optional[Future]:
|
||
"""
|
||
Takes in the ID of an element in the planning scene. Modifies the allowed
|
||
collision matrix to (dis)allow collisions between that object and all other
|
||
object.
|
||
|
||
If `allow` is True, a plan will succeed even if the robot collides with that object.
|
||
If `allow` is False, a plan will fail if the robot collides with that object.
|
||
Returns whether it successfully updated the allowed collision matrix.
|
||
|
||
Returns the future of the service call.
|
||
"""
|
||
# Update the planning scene
|
||
if not self.update_planning_scene():
|
||
return None
|
||
allowed_collision_matrix = self.__planning_scene.allowed_collision_matrix
|
||
self.__old_allowed_collision_matrix = copy.deepcopy(allowed_collision_matrix)
|
||
|
||
# Get the location in the allowed collision matrix of the object
|
||
j = None
|
||
if id not in allowed_collision_matrix.entry_names:
|
||
allowed_collision_matrix.entry_names.append(id)
|
||
else:
|
||
j = allowed_collision_matrix.entry_names.index(id)
|
||
# For all other objects, (dis)allow collisions with the object with `id`
|
||
for i in range(len(allowed_collision_matrix.entry_values)):
|
||
if j is None:
|
||
allowed_collision_matrix.entry_values[i].enabled.append(allow)
|
||
elif i != j:
|
||
allowed_collision_matrix.entry_values[i].enabled[j] = allow
|
||
# For the object with `id`, (dis)allow collisions with all other objects
|
||
allowed_collision_entry = AllowedCollisionEntry(
|
||
enabled=[allow for _ in range(len(allowed_collision_matrix.entry_names))]
|
||
)
|
||
if j is None:
|
||
allowed_collision_matrix.entry_values.append(allowed_collision_entry)
|
||
else:
|
||
allowed_collision_matrix.entry_values[j] = allowed_collision_entry
|
||
|
||
# Apply the new planning scene
|
||
if not self._apply_planning_scene_service.service_is_ready():
|
||
self.get_logger().warn(
|
||
f"Service '{self._apply_planning_scene_service.srv_name}' is not yet available. Better luck next time!"
|
||
)
|
||
return None
|
||
return self._apply_planning_scene_service.call_async(
|
||
ApplyPlanningScene.Request(scene=self.__planning_scene)
|
||
)
|
||
|
||
def process_allow_collision_future(self, future: Future) -> bool:
|
||
"""
|
||
Return whether the allow collision service call is done and has succeeded
|
||
or not. If it failed, reset the allowed collision matrix to the old one.
|
||
"""
|
||
if not future.done():
|
||
return False
|
||
|
||
# Get response
|
||
resp = future.result()
|
||
|
||
# If it failed, restore the old planning scene
|
||
if not resp.success:
|
||
self.__planning_scene.allowed_collision_matrix = (
|
||
self.__old_allowed_collision_matrix
|
||
)
|
||
|
||
return resp.success
|
||
|
||
def clear_all_collision_objects(self) -> Optional[Future]:
|
||
"""
|
||
Removes all attached and un-attached collision objects from the planning scene.
|
||
|
||
Returns a future for the ApplyPlanningScene service call.
|
||
"""
|
||
# Update the planning scene
|
||
if not self.update_planning_scene():
|
||
return None
|
||
self.__old_planning_scene = copy.deepcopy(self.__planning_scene)
|
||
|
||
# Remove all collision objects from the planning scene
|
||
self.__planning_scene.world.collision_objects = []
|
||
self.__planning_scene.robot_state.attached_collision_objects = []
|
||
|
||
# Apply the new planning scene
|
||
if not self._apply_planning_scene_service.service_is_ready():
|
||
self.get_logger().warn(
|
||
f"Service '{self._apply_planning_scene_service.srv_name}' is not yet available. Better luck next time!"
|
||
)
|
||
return None
|
||
return self._apply_planning_scene_service.call_async(
|
||
ApplyPlanningScene.Request(scene=self.__planning_scene)
|
||
)
|