diff --git a/log/死机日志.log b/log/死机日志.log index b6cdf24..b283da9 100644 --- a/log/死机日志.log +++ b/log/死机日志.log @@ -150,7 +150,7 @@ 00243217 INFO [SMTP2 ] tx:/1u10,0R 00243247 INFO [SMTP2 ] rx:(6) (2F3040030D0A) /0@ -00243248 INFO [SMTP2 ] pump_set_tip_size 1 +00243248 INFO [SMTP2 ] pump_set_tip_type 1 00243249 INFO [SMTP2 ] tx:/1u18,1R 00243279 INFO [SMTP2 ] rx:(6) (2F3040030D0A) /0@ diff --git a/sdk/components/pipette_module/base/pipette_action_param.hpp b/sdk/components/pipette_module/base/pipette_action_param.hpp index b735b95..28e74a3 100644 --- a/sdk/components/pipette_module/base/pipette_action_param.hpp +++ b/sdk/components/pipette_module/base/pipette_action_param.hpp @@ -73,4 +73,21 @@ typedef enum { // kaspiration_paramid_mix_volume, kaspiration_paramid_mix_times, -} aspiration_paramid_t; \ No newline at end of file +} aspiration_paramid_t; + +typedef struct { + // + // 容器 + // + int32_t container_pos; // 容器位置 + int32_t container_info_index; // 容器配置索引 + // + // 液体类型 + // + int32_t liquid_cfg_index; // 液体配置索引 + // + // 混匀配置 + // + int32_t mix_volume; // 混匀体积 + int32_t mix_times; // 混匀次数 +} distribu_all_param_t; diff --git a/sdk/components/pipette_module/base/pipette_cfg.hpp b/sdk/components/pipette_module/base/pipette_cfg.hpp index 5ab8e0d..2fddaef 100644 --- a/sdk/components/pipette_module/base/pipette_cfg.hpp +++ b/sdk/components/pipette_module/base/pipette_cfg.hpp @@ -23,7 +23,7 @@ typedef struct { int32_t tip_picking_append_distance; // 取tip时z轴的附加距离 int32_t tip_deposit_pos; // 丢tip位置(绝对位置0.1mm) - int32_t _transform_pos; // 移液枪安全移动的高度(绝对位置0.1mm) + int32_t _transform_pos; // 移液枪安全移动的高度(绝对位置0.1mm) /** * @brief tip类型 * @@ -70,7 +70,7 @@ typedef struct { int32_t io_trigger_append_distance; // int32_t pos_devi_tolerance; // int32_t mres; // - int32_t mark; // 结构体最后一个数值,设置9973,用于保证单片机端和java端均正确更新了枚举 + int32_t mark; // 结构体最后一个数值,设置9973,用于保证单片机端和java端均正确更新了枚举 } zm_bcfg_t; typedef enum { @@ -166,7 +166,7 @@ typedef struct { int32_t leaving_height; // 离开液面高度,此位置ZEUS开始缓慢进入液面或离开液面,精度0.1mm int32_t jet_height; // 喷射高度(0.1mm) int32_t lld_start_search_depth; // lld开始搜索时位置冗余,精度0.1mm,abspos = container_neck_pos + lld_start_search_pos_redundancy - int32_t fix_aspiration_depth; // 固定吸液深度((0.1mm),当lld失能时,移液枪先移动到这个位置,然后开始吸液 + int32_t fix_water_level_depth; // 固定吸液深度((0.1mm),当lld失能时,移液枪先移动到这个位置,然后开始吸液 int32_t llf_vconvert_coneff; // 液面跟随转换系数 0.0001 llf_zm_vel = aspiration_pm_vel * llf_vconvert_coneff * 0.0001 int32_t pierce_depth; // 穿刺深度(0.1mm),用于刺破容器防尘膜 int32_t mark; // 结构体最后一个数值,设置9973,用于保证单片机端和java端均正确更新了枚举 @@ -182,7 +182,7 @@ typedef enum { kcontainer_info_leaving_height, kcontainer_info_jet_height, kcontainer_info_lld_start_search_depth, - kcontainer_info_fix_aspiration_depth, + kcontainer_info_fix_water_level_depth, kcontainer_info_llf_vconvert_coneff, kcontainer_info_pierce_depth, kcontainer_info_mark, diff --git a/sdk/components/pipette_module/pipette_ctrl_module.cpp b/sdk/components/pipette_module/pipette_ctrl_module.cpp index 409ab10..e59ef49 100644 --- a/sdk/components/pipette_module/pipette_ctrl_module.cpp +++ b/sdk/components/pipette_module/pipette_ctrl_module.cpp @@ -25,16 +25,22 @@ void PipetteModule::initialize(int32_t id, hardward_config_t *hardwaredcfg) { / m_zm->getGState(); // 读取状态,清空下复位标识 m_piette_gun_io1.initAsInput(hardwaredcfg->IO1, ZGPIO::kMode_pullup, ZGPIO::kIRQ_noIrq, hardwaredcfg->IO1Mirror); - // ZASSERT(hardwaredcfg->uart232); - // EXHAL_UART_BindUart("pipette-uart232", hardwaredcfg->uart232); - // EXHAL_UART_RegListener(hardwaredcfg->uart232, [this](UART_HandleTypeDef *huart, uint8_t *data, size_t len) { - // printf("!rx(%d): ", len); - // if (len > 0) { - // printf("%c", data[0]); - // } - // printf("\n"); - // }); - // EXHAL_UART_ITStartAutoRead(hardwaredcfg->uart232); + ZASSERT(hardwaredcfg->uart232); + EXHAL_UART_BindUart("pipette-uart232", hardwaredcfg->uart232); + EXHAL_UART_RegListener(hardwaredcfg->uart232, [this](UART_HandleTypeDef *huart, uint8_t *data, size_t len) { + printf("!rx(%d): ", len); + if (len > 0) { + printf("%c", data[0]); + } + printf("\n"); + }); + EXHAL_UART_ITStartAutoRead(hardwaredcfg->uart232); + + while (true) { + EXHAL_UART_TransmitStringBlock(hardwaredcfg->uart232, "/1QR\r"); + osDelay(10); + } + m_smtp2.pump_set_pressure_data_stream_port(0); // // EXHAL_UART_BindUart("pipette-uart", hardwaredcfg->uart); // EXHAL_UART_RegListener(hardwaredcfg->uart, [this](UART_HandleTypeDef *huart, uint8_t *data, size_t len) { @@ -49,11 +55,26 @@ void PipetteModule::initialize(int32_t id, hardward_config_t *hardwaredcfg) { / // HAL_Delay(1000); // EXHAL_UART_TransmitStringBlock(hardwaredcfg->uart232, "/1QR\r"); + // m_smtp2.pump_factory_reset(); + // osDelay(1000); + test_connectivity(); parameter_init(); zm_sync_base_cfg(); - get_platinfo_smart(m_state.platinfo_cpyid, &m_now_platinfo); + + int32_t maxul = 0; + // int32_t ecode = 0; + + // m_smtp2.pump_set_tip_type(smtp2::TipSize_t::TS1000UL); // 默认1000ul + // m_smtp2.pump_get_max_limit(&maxul); + // ZLOGI(TAG, "1pipette gun max limit:%d", maxul); + + m_smtp2.pump_set_tip_type(smtp2::TipSize_t::TS200UL); // + m_smtp2.pump_get_max_limit(&maxul); + ZLOGI(TAG, "2pipette gun max limit:%d", maxul); + + ZLOGI(TAG, "pipette gun version:%s", m_smtp2.pump_read_version()); } void PipetteModule::test_connectivity() { @@ -339,7 +360,7 @@ int32_t PipetteModule::pipette_set_container_info(int32_t cpyid, container_info_ SET_CFG(kcontainer_info_leaving_height, cfg->leaving_height, val); SET_CFG(kcontainer_info_jet_height, cfg->jet_height, val); SET_CFG(kcontainer_info_lld_start_search_depth, cfg->lld_start_search_depth, val); - SET_CFG(kcontainer_info_fix_aspiration_depth, cfg->fix_aspiration_depth, val); + SET_CFG(kcontainer_info_fix_water_level_depth, cfg->fix_water_level_depth, val); SET_CFG(kcontainer_info_llf_vconvert_coneff, cfg->llf_vconvert_coneff, val); SET_CFG(kcontainer_info_pierce_depth, cfg->pierce_depth, val); SET_CFG(kcontainer_info_mark, cfg->mark, val); @@ -368,7 +389,7 @@ int32_t PipetteModule::pipette_get_container_info(int32_t cpyid, container_info_ GET_CFG(kcontainer_info_leaving_height, cfg->leaving_height, val); GET_CFG(kcontainer_info_jet_height, cfg->jet_height, val); GET_CFG(kcontainer_info_lld_start_search_depth, cfg->lld_start_search_depth, val); - GET_CFG(kcontainer_info_fix_aspiration_depth, cfg->fix_aspiration_depth, val); + GET_CFG(kcontainer_info_fix_water_level_depth, cfg->fix_water_level_depth, val); GET_CFG(kcontainer_info_llf_vconvert_coneff, cfg->llf_vconvert_coneff, val); GET_CFG(kcontainer_info_pierce_depth, cfg->pierce_depth, val); GET_CFG(kcontainer_info_mark, cfg->mark, val); @@ -591,8 +612,9 @@ void PipetteModule::memset_int32_t(int32_t *table, int32_t val, int32_t num) { int32_t PipetteModule::compute_zm_llf_vel(int32_t pm_vindex, container_info_t *container_info) { pm_vcfg_t pmv = {0}; get_cfg_smart(pm_vindex, &pmv); - int32_t zmval = pmv.vmax * container_info->llf_vconvert_coneff * 0.0001; - return zmval * 80 / zmbcfg.one_circle_pulse; + int32_t zmval = pmv.vmax * container_info->llf_vconvert_coneff * 0.001; + if (zmval == 0) zmval = 1; + return zmval; } /*********************************************************************************************************************** @@ -708,9 +730,9 @@ int32_t PipetteModule::pipette_pump_take_tip() { platinfo_t *platform_info = get_platinfo_smart(m_state.platinfo_cpyid, &m_now_platinfo); zm_move_to_block(platform_info->tip_picking_pos, kzm_v_default, 0); zm_move_by(platform_info->tip_picking_search_range, kzm_v_picking_tip, 0); - bool takeTip = false; + bool takeTip = false; + int32_t tipstate = 0; while (true) { - int32_t tipstate = 0; DO_IN_THREAD(m_smtp2.pump_get_tip_state(&tipstate)); if (tipstate == 1) { takeTip = true; @@ -723,6 +745,19 @@ int32_t PipetteModule::pipette_pump_take_tip() { if (takeTip && platform_info->tip_picking_append_distance > 0) // zm_move_by_block(platform_info->tip_picking_append_distance, kzm_v_picking_tip, 0); + // 移动到tip搜索位置,检查tip是否存在,如果不存在,则强制退tip一次 + if (takeTip) { + zm_move_to_block(platform_info->tip_picking_pos, kzm_v_default, 0); + for (int i = 0; i < 3; i++) { + DO_IN_THREAD(m_smtp2.pump_get_tip_state(&tipstate)); + if (tipstate == 0) { + DO_IN_THREAD(m_smtp2.pump_init()); // 强制退tip + takeTip = false; + break; + } + } + } + zm_move_to_zero_quick_block(); ZLOGI(TAG, "pipette_pump_take_tip takeTip %s", takeTip ? "suc" : "fail"); }); @@ -866,8 +901,8 @@ int32_t PipetteModule::pipette_pump_aspirate() { // DO_IN_THREAD(m_smtp2.pump_set_io2_mode(0)); // 通用输入 platinfo_t *platform_info = get_platinfo_smart(m_state.platinfo_cpyid, &m_now_platinfo); - liquid_info_t *liquidinfo = get_liquid_info_smart(acfg->liquid_cfg_index, &aspirate_run_cxt.liquid_info); - container_info_t *container_cfg = get_container_info_smart(acfg->container_info_index, &aspirate_run_cxt.container_info); + liquid_info_t *liquidinfo = get_liquid_info_smart(acfg->liquid_cfg_index, &m_now_aspirate_liquid_info); + container_info_t *container_cfg = get_container_info_smart(acfg->container_info_index, &m_now_container_info); ZLOGI(TAG, "-------------------------- aspiration param --------------------------"); ZLOGI(TAG, "- x100nl :%d", acfg->volumeX100nl); @@ -920,7 +955,7 @@ int32_t PipetteModule::pipette_pump_aspirate() { ZLOGI(TAG, "- leaving_height :%d", container_cfg->leaving_height); ZLOGI(TAG, "- jet_height :%d", container_cfg->jet_height); ZLOGI(TAG, "- lld_start_search_depth :%d", container_cfg->lld_start_search_depth); - ZLOGI(TAG, "- fix_aspiration_depth :%d", container_cfg->fix_aspiration_depth); + ZLOGI(TAG, "- fix_water_level_depth :%d", container_cfg->fix_water_level_depth); ZLOGI(TAG, "- llf_vconvert_coneff :%d", container_cfg->llf_vconvert_coneff); ZLOGI(TAG, "- pierce_depth :%d", container_cfg->pierce_depth); ZLOGI(TAG, "- mark :%d", container_cfg->mark); @@ -929,29 +964,14 @@ int32_t PipetteModule::pipette_pump_aspirate() { /*********************************************************************************************************************** * LLD * ***********************************************************************************************************************/ - DO_IN_THREAD(m_smtp2.pump_set_tip_size((smtp2::TipSize_t)platform_info->tip_type)); // 250ul, - if (acfg->lld_enable) { - // 液面探测 - _do_lld(platform_info, container_cfg, liquidinfo, acfg); - // 这里需要低速离开液面,防止携带液滴 - ZLOGI(TAG, "move to swap position in v_swap"); - zm_move_to_block(m_state.water_level - container_cfg->leaving_height, kzm_v_swap, 0); // - // 清空tip - ZLOGI(TAG, "clean tip."); - pump_move_to_x100nl_block(0, liquidinfo->empty_tip_pm_vcpyid); + _do_lld(acfg->container_pos, platform_info, container_cfg, liquidinfo); // 液面探测 } else { - // 没有使用lld,使用固定深度 - m_state.water_level = acfg->container_pos + container_cfg->fix_aspiration_depth; - ZLOGI(TAG, "lld isn't enable,use fix depth %d", m_state.water_level); - // 由于tip原本在液面之上,这里快速移动到swap位置, - ZLOGI(TAG, "move to swap position in v_default"); - zm_move_to_block(m_state.water_level - container_cfg->leaving_height, kzm_v_default, 0); // - ZLOGI(TAG, "clean tip."); - pump_move_to_x100nl_block(0, liquidinfo->empty_tip_pm_vcpyid); // + m_state.water_level = acfg->container_pos + container_cfg->fix_water_level_depth; // 没有使用lld,使用固定深度 } if (acfg->volumeX100nl != 0) { + DO_IN_THREAD(m_smtp2.pump_set_tip_type((smtp2::TipSize_t)platform_info->tip_type)); _do_sapirate(platform_info, container_cfg, liquidinfo, acfg); } else { ZLOGI(TAG, "aspiration volume == 0,skip aspirate", acfg->volumeX100nl); @@ -963,32 +983,34 @@ int32_t PipetteModule::pipette_pump_aspirate() { return 0; } -void PipetteModule::_do_lld(platinfo_t *platform_info, container_info_t *container_cfg, liquid_info_t *liquidinfo, aspiration_param_t *acfg) { +void PipetteModule::_do_lld(int32_t container_pos, platinfo_t *platform_info, container_info_t *container_cfg, liquid_info_t *liquidinfo) { int32_t ecode = 0; - ZLOGI(TAG, "start lld, lld_type %d lld_pm_vindex %d plld_threshold %d", acfg->lld_type, liquidinfo->plld_pm_vcpyid, liquidinfo->plld_threshold); - // 移动到转移位置 + ZLOGI(TAG, "-->zm move to transform pos"); zm_move_to_block(0, kzm_v_default, 0); // 清空tip + ZLOGI(TAG, "-->empty tip before lld"); pump_move_to_x100nl_block(0, liquidinfo->empty_tip_pm_vcpyid); + pump_move_to_x100nl_block(10, kpm_v_default); // 回转一下,消除齿轮间隙 // 移动到瓶口 - zm_move_to_block(acfg->container_pos + 50 /*5mm*/, // - kzm_v_default, 0); - pump_move_to_x100nl_block(0, kpm_v_default); // 回转一下,消除齿轮间隙 + ZLOGI(TAG, "-->zm move to container neck pos"); + zm_move_to_block(container_pos - 50 /*5mm*/, kzm_v_default, 0); // 启动lld - pump_apply_vcfg(liquidinfo->plld_pm_vcpyid); // 设备lld时,泵的速率 - DO_IN_THREAD(m_smtp2.pump_set_tip_size(smtp2::TS200UL)); // 250ul,保护lld不超限 - DO_IN_THREAD(m_smtp2.pump_set_io1_mode(1)); // lld输入高 - DO_IN_THREAD(m_smtp2.pump_aspirate_plld(liquidinfo->plld_threshold)); + ZLOGI(TAG, "-->start lld, lld_pm_vindex %d plld_threshold %d", liquidinfo->plld_pm_vcpyid, liquidinfo->plld_threshold); + DO_IN_THREAD(m_smtp2.pump_set_io1_mode(1)); // lld输入高 + DO_IN_THREAD(m_smtp2.pump_set_tip_type((smtp2::TipSize_t)platform_info->tip_type)); // 设置tip大小 + pump_do_lld(liquidinfo->plld_threshold, 200, liquidinfo->plld_pm_vcpyid); // lld延时200ms,速度为plld_zm_vel // 快速移动到瓶口 - zm_move_to_block(acfg->container_pos + container_cfg->lld_start_search_depth, // + ZLOGI(TAG, "-->zm move quick to lld search start pos"); + zm_move_to_block(container_pos + container_cfg->lld_start_search_depth, // kzm_v_default, 0); // lld,zm移动到瓶底 - zm_move_to(acfg->container_pos + container_cfg->container_depth, kzm_v_lld, liquidinfo->plld_zm_vel); + ZLOGI(TAG, "-->zm move slow to container bottom pos"); + zm_move_to(container_pos + container_cfg->container_depth, kzm_v_lld, liquidinfo->plld_zm_vel); /** * @brief 等待压力大于阈值 @@ -998,7 +1020,7 @@ void PipetteModule::_do_lld(platinfo_t *platform_info, container_info_t *contain while (true) { if (m_zm->isStoped()) { detect_liquid = false; - ZLOGI(TAG, "zm is stoped"); + ZLOGI(TAG, "-->zm is stoped"); break; } @@ -1006,14 +1028,19 @@ void PipetteModule::_do_lld(platinfo_t *platform_info, container_info_t *contain if (m_piette_gun_io1.getState()) { int32_t water_level = zm_get_now_pos(); detect_liquid = true; - ZLOGI(TAG, "detect liquid, water_level %d", water_level); + m_zm->stop(); + ZLOGI(TAG, "-->detect liquid, water_level %d", water_level); break; } + ZLOGI(TAG, "...wait for lld trigger, now zm pos %d", zm_get_now_pos()); thread_delay(1); } + ecode = m_smtp2.pump_get_state(nullptr); // 获取泵状态,在此之前不能执行任何泵机指令,否则会丢失错误状态 + + int32_t now_pm_pos = pump_read_pos_nl(); + ZLOGI(TAG, "pump now pos %d nl", now_pm_pos); // 检查是否是LLD错误 - ecode = m_smtp2.pump_get_state(nullptr); if (ecode != 0) { if (ecode == err::kpipette_error_LLDError) { // LLD错误。在cLLD、pLLD、hLLD模式下均未检测到液体。在超过指定的压力阈值之前,泵已达到行程终点。 @@ -1039,6 +1066,21 @@ void PipetteModule::_do_lld(platinfo_t *platform_info, container_info_t *contain } void PipetteModule::_do_sapirate(platinfo_t *platform_info, container_info_t *container_cfg, liquid_info_t *liquidinfo, aspiration_param_t *acfg) { + // 移动到液面之上 + ZLOGI(TAG, "--> move to swap pos"); + int32_t nowzpos = zm_get_now_pos(); + if (nowzpos < m_state.water_level) { + ZLOGI(TAG, "move to swap position in v_swap"); + zm_move_to_block(m_state.water_level - container_cfg->leaving_height, kzm_v_swap, 0); // + } else { + ZLOGI(TAG, "move to swap position in v_default"); + zm_move_to_block(m_state.water_level - container_cfg->leaving_height, kzm_v_default, 0); // + } + + // 清空tip + ZLOGI(TAG, "clean tip."); + pump_move_to_x100nl_block(0, liquidinfo->empty_tip_pm_vcpyid); + // 吸入过量的空气 if (liquidinfo->blowout_air_volume > 0) { ZLOGI(TAG, "--> aspirate blowout_air_volume volume=%d, pm_vcpyid=%d", liquidinfo->blowout_air_volume); @@ -1118,7 +1160,60 @@ void PipetteModule::_do_sapirate(platinfo_t *platform_info, container_info_t *co } } -int32_t PipetteModule::pipette_pump_distribu() { return 0; } +int32_t PipetteModule::pipette_pump_distribu_all() { + thread_start_work(__FUNCTION__, [this]() { + ZLOGI(TAG, "pipette_pump_aspirate"); + if (pump_read_tip_state() == 0) { + throw zapp_exception(err::kpipette_error_TipDrop); + } + + + + + + }); + + return 0; +} + +int32_t PipetteModule::pipette_test_pump_move_to_x100nl(int32_t x100nl, int32_t vcfgcpyid) { + thread_start_work(__FUNCTION__, [this, x100nl, vcfgcpyid]() { + ZLOGI(TAG, "pipette_pump_aspirate"); + if (pump_read_tip_state() == 0) { + throw zapp_exception(err::kpipette_error_TipDrop); + } + + // 移液枪部分参数初始化 + DO_IN_THREAD(m_smtp2.pump_enable_temp_compensation(0)); // 关闭温度补偿 + DO_IN_THREAD(m_smtp2.pump_set_back_clearance(0)); // 设置背隙为0 + DO_IN_THREAD(m_smtp2.pump_set_io1_mode(0)); // lld输入高 + + int32_t diff = 0; + pump_move_to_x100nl_block(x100nl, vcfgcpyid, &diff); // + m_state.asynchronous_result0 = diff; + }); + return 0; +} +int32_t PipetteModule::pipette_test_lld(int32_t container_pos, int32_t container_cpyid, int32_t liquid_cpyid) { + thread_start_work(__FUNCTION__, [this, container_pos, container_cpyid, liquid_cpyid]() { + ZLOGI(TAG, "pipette_pump_aspirate"); + if (pump_read_tip_state() == 0) { + throw zapp_exception(err::kpipette_error_TipDrop); + } + + // 移液枪部分参数初始化 + DO_IN_THREAD(m_smtp2.pump_enable_temp_compensation(0)); // 关闭温度补偿 + DO_IN_THREAD(m_smtp2.pump_set_back_clearance(0)); // 设置背隙为0 + DO_IN_THREAD(m_smtp2.pump_set_io1_mode(0)); // lld输入高 + + platinfo_t *platform_info = get_platinfo_smart(m_state.platinfo_cpyid, &m_now_platinfo); + liquid_info_t *liquidinfo = get_liquid_info_smart(container_cpyid, &m_now_aspirate_liquid_info); + container_info_t *container_cfg = get_container_info_smart(liquid_cpyid, &m_now_container_info); + + _do_lld(container_pos, platform_info, container_cfg, liquidinfo); + }); + return 0; +} /*********************************************************************************************************************** * EXT_API_UTILS * @@ -1262,32 +1357,22 @@ void PipetteModule::zm_apply_vcfg(int32_t vbasecfgindex, int32_t vel) { */ zm_vcfg_t cfg = {0}; - get_cfg_smart(vbasecfgindex, &cfg); if (vel > 0) { cfg.vmax = vel; } + TMC51X0::VCfg_t tcmvcfg; + tcmvcfg.vstart = cfg.vstart; + tcmvcfg.a1 = cfg.a1; + tcmvcfg.amax = cfg.amax; + tcmvcfg.v1 = cfg.v1; + tcmvcfg.dmax = cfg.dmax; + tcmvcfg.d1 = cfg.d1; + tcmvcfg.vstop = cfg.vstop; + tcmvcfg.vmax = cfg.vmax; + m_zm->set_vcfg(&tcmvcfg); - if (cfg.vstop > cfg.vmax) { - cfg.vstop = cfg.vmax; - } - if (cfg.vstart > cfg.vmax) { - cfg.vstart = cfg.vmax; - } - if (cfg.v1 > cfg.vmax) { - cfg.v1 = cfg.vmax; - } - - m_zm->set_vstart(cfg.vstart); - m_zm->set_a1(cfg.a1); - m_zm->set_amax(cfg.amax); - m_zm->set_v1(cfg.v1); - m_zm->set_dmax(cfg.dmax); - m_zm->set_d1(cfg.d1); - m_zm->set_vstop(cfg.vstop); - m_zm->set_vmax(cfg.vmax); - - ZLOGI(TAG, "zm set vstart %d,a1 %d,amax %d,v1 %d,dmax %d,d1 %d,vstop %d,vmax %d", cfg.vstart, cfg.a1, cfg.amax, cfg.v1, cfg.dmax, cfg.d1, cfg.vstop, cfg.vmax); + ZLOGI(TAG, "zm set vstart %d,a1 %d,amax %d,v1 %d,dmax %d,d1 %d,vstop %d,vmax %d", tcmvcfg.vstart, tcmvcfg.a1, tcmvcfg.amax, tcmvcfg.v1, tcmvcfg.dmax, tcmvcfg.d1, tcmvcfg.vstop, tcmvcfg.vmax); } void PipetteModule::zm_sync_base_cfg() { @@ -1301,6 +1386,7 @@ void PipetteModule::zm_sync_base_cfg() { m_zm->set_tzerowait(zmbcfg.tzerowait); m_zm->set_enc_resolution(zmbcfg.enc_resolution); zm_apply_vcfg(kzm_v_default, 0); + m_zm->stop(); if (m_state.enable) { m_zm->enable(true); } @@ -1366,9 +1452,9 @@ void PipetteModule::pump_waitfor_lld_is_ready(int32_t *zpos) { } } -void PipetteModule::pump_get_vcfg(int32_t vcfgindex, smtp2::VelCfg *cfg) { +void PipetteModule::pump_get_vcfg(int32_t vcfgcpyid, smtp2::VelCfg *cfg) { pm_vcfg_t cfg2 = {0}; - get_cfg_smart(vcfgindex, &cfg2); + get_cfg_smart(vcfgcpyid, &cfg2); cfg->acc = cfg2.acc; cfg->dec = cfg2.dec; cfg->vstart = cfg2.vstart; @@ -1376,41 +1462,69 @@ void PipetteModule::pump_get_vcfg(int32_t vcfgindex, smtp2::VelCfg *cfg) { cfg->vmax = cfg2.vmax; } -void PipetteModule::pump_apply_vcfg(int32_t vcfgindex, bool force) { - ZLOGI(TAG, "pump_apply_vcfg %s", get_pm_vcpyid_name((pm_vcpyid_t)vcfgindex)); - if (!force && m_state.pm_now_vcfg_index == vcfgindex) { +void PipetteModule::pump_apply_vcfg(int32_t vcfgcpyid, bool force) { + ZLOGI(TAG, "pump_apply_vcfg %s", get_pm_vcpyid_name((pm_vcpyid_t)vcfgcpyid)); + if (!force && m_state.pm_now_vcfg_index == vcfgcpyid) { // 如果当前配置和目标配置相同,则不需要重新设置 return; } smtp2::VelCfg vcfg; - pump_get_vcfg(vcfgindex, &vcfg); + pump_get_vcfg(vcfgcpyid, &vcfg); DO_IN_THREAD(m_smtp2.pump_set_vcfg(&vcfg)); - m_state.pm_now_vcfg_index = vcfgindex; + m_state.pm_now_vcfg_index = vcfgcpyid; } -void PipetteModule::pump_move_to_x100nl(int32_t x100nl, int32_t vcfgindex) { +void PipetteModule::_pump_move_to_x100nl(int32_t x100nl, int32_t vcfgcpyid) { + ZLOGI(TAG, "pump_move_to_x100nl %d, in %s", x100nl, get_pm_vcpyid_name((pm_vcpyid_t)vcfgcpyid)); smtp2::VelCfg vcfg; - pump_get_vcfg(vcfgindex, &vcfg); + pump_get_vcfg(vcfgcpyid, &vcfg); + m_state.pm_now_vcfg_index = vcfgcpyid; // 更新当前配置索引 DO_IN_THREAD(m_smtp2.pump_move_to_nl(&vcfg, x100nl * 100)); } - -void PipetteModule::pump_move_by_x100nl(int32_t x100nl, int32_t vcfgindex) { - ZLOGI(TAG, "pump_move_by_x100nl %d, in %s", x100nl, get_pm_vcpyid_name((pm_vcpyid_t)vcfgindex)); +void PipetteModule::pump_do_lld(int32_t pressure_threshold, int32_t ___, int32_t vcfgidx) { + ZLOGI(TAG, "pump_do_lld pressure_threshold %d, vcfgidx %d", pressure_threshold, vcfgidx); smtp2::VelCfg vcfg; - pump_get_vcfg(vcfgindex, &vcfg); - DO_IN_THREAD(m_smtp2.pump_move_by_nl(&vcfg, x100nl * 100)); + pump_get_vcfg(vcfgidx, &vcfg); + m_state.pm_now_vcfg_index = vcfgidx; // 更新当前配置索引 + DO_IN_THREAD(m_smtp2.pump_aspirate_plld(pressure_threshold, &vcfg)); } -void PipetteModule::pump_move_to_x100nl_block(int32_t x100nl, int32_t vcfgindex) { - pump_move_to_x100nl(x100nl, vcfgindex); - pump_waitfor_stop(); - ZLOGI(TAG, "pump now pos %d nl", pump_read_pos_nl()); +void PipetteModule::pump_move_to_x100nl_block(double x100nl, int32_t vcfgcpyid, int32_t *diff) { + int32_t diff_pos = 0; + for (size_t i = 0; i < 3; i++) { + int32_t vcpyid = vcfgcpyid; + if (i != 0) { + vcpyid = kpm_v_slow_lv1; + } + + _pump_move_to_x100nl(x100nl, vcpyid); + pump_waitfor_stop(); + int32_t targetpos = x100nl * 100; + int32_t after_pos = pump_read_pos_nl(); + diff_pos = targetpos - after_pos; + if (diff) *diff = diff_pos; + ZLOGI(TAG, "pump target %d nl, now pos %d nl diff %d", targetpos, after_pos, diff_pos); + if (abs(diff_pos) > 20) { + ZLOGW(TAG, "pump move to x100nl %d failed, diff is too large retrying...", x100nl); + continue; + } + break; + } + if (abs(diff_pos) > 30) { + module_detail_errorcode = diff_pos; + throw zapp_exception(err::kpipette_pm_positioning_abnormality); + } } -void PipetteModule::pump_move_by_x100nl_block(int32_t x100nl, int32_t vcfgindex) { - pump_move_by_x100nl(x100nl, vcfgindex); - pump_waitfor_stop(); - ZLOGI(TAG, "pump now pos %d nl", pump_read_pos_nl()); +void PipetteModule::pump_move_by_x100nl_block(double x100nl, int32_t vcfgcpyid) { + int32_t startpos = pump_read_pos_nl(); + if (startpos > 1500000) { + // 参考 https://iflytop1.feishu.cn/wiki/IWn1waKCXiUvzfkOru5c0F3HnJf + ZLOGW(TAG, "pump position is too large maybe overflow, startpos=%d", startpos); + startpos = 0; + } + double targetpos = startpos + x100nl * 100; + pump_move_to_x100nl_block(targetpos / 100, vcfgcpyid); } void PipetteModule::pump_read_pos_nl(int32_t *val) { @@ -1579,13 +1693,21 @@ void PipetteModule::thread_delay(int32_t delayms) { // } void PipetteModule::thread_start_work(const char *fnname, function fn) { m_thread.stop(); - module_status = 1; - module_errorcode = 0; + module_status = 1; + module_errorcode = 0; + module_detail_errorcode = 0; - m_state.detected_liquid = 0; m_state.asynchronous_result0 = 0; m_state.asynchronous_result1 = 0; + m_state.aspiration_ok = 0; + m_state.pump_lld_reach_limit = 0; + m_state.detected_liquid = 0; + m_state.water_level = 0; + m_state.tipblock = 0; + m_state.airsuction = 0; + m_state.bubble = 0; + m_thread.start([this, fnname, fn]() { osDelay(1); ZLOGI(TAG, "start work -> %s", fnname); diff --git a/sdk/components/pipette_module/pipette_ctrl_module.hpp b/sdk/components/pipette_module/pipette_ctrl_module.hpp index 6de20c6..51b9b1e 100644 --- a/sdk/components/pipette_module/pipette_ctrl_module.hpp +++ b/sdk/components/pipette_module/pipette_ctrl_module.hpp @@ -56,17 +56,8 @@ class PipetteModule : public ZIModule { } hardward_config_t; typedef struct { - container_info_t container_info; - liquid_info_t liquid_info; } aspirate_run_cxt_t; - typedef struct { - platinfo_t platinfo; - container_info_t container_info; - liquid_info_t transform_liquid_info; - liquid_info_t destination_liquid_info; - } distribu_run_cxt_t; - private: /*********************************************************************************************************************** * Hardware * @@ -84,9 +75,8 @@ class PipetteModule : public ZIModule { pipette_state_t m_state = {0}; platinfo_t m_now_platinfo; container_info_t m_now_container_info; + liquid_info_t m_now_aspirate_liquid_info; - aspirate_run_cxt_t aspirate_run_cxt; - distribu_run_cxt_t distribu_run_cxt; /*********************************************************************************************************************** * Config * ***********************************************************************************************************************/ @@ -182,10 +172,10 @@ class PipetteModule : public ZIModule { virtual int32_t pipette_pump_aspirate_set_param(aspiration_paramid_t param, int32_t val); virtual int32_t pipette_pump_aspirate(); - void _do_lld(platinfo_t *platform_info, container_info_t *container_cfg, liquid_info_t *liquidinfo, aspiration_param_t *acfg); + void _do_lld(int32_t container_pos, platinfo_t *platform_info, container_info_t *container_cfg, liquid_info_t *liquidinfo); void _do_sapirate(platinfo_t *platform_info, container_info_t *container_cfg, liquid_info_t *liquidinfo, aspiration_param_t *acfg); - virtual int32_t pipette_pump_distribu(); + virtual int32_t pipette_pump_distribu_all(); virtual int32_t pipette_get_sensor_sample_data(int32_t index, int32_t *motor_pos, int32_t *pval); // virtual int32_t pipette_get_sensor_sample_data_num(int32_t *num); @@ -194,6 +184,10 @@ class PipetteModule : public ZIModule { virtual int32_t pipette_read_pressure(int32_t *pressure); virtual int32_t pipette_read_capacitance(int32_t *capacitance); + // TEST CMD + virtual int32_t pipette_test_pump_move_to_x100nl(int32_t x100nl, int32_t vcfgindex); + virtual int32_t pipette_test_lld(int32_t container_pos, int32_t container_cpyid, int32_t liquid_cpyid); + private: /*********************************************************************************************************************** * MOTOR * @@ -242,10 +236,10 @@ class PipetteModule : public ZIModule { int32_t pump_read_tip_state(); void pump_waitfor_stop(); void pump_waitfor_lld_is_ready(int32_t *zpos); - void pump_move_to_x100nl(int32_t x100nl, int32_t vcfgindex); - void pump_move_by_x100nl(int32_t x100nl, int32_t vcfgindex); - void pump_move_to_x100nl_block(int32_t x100nl, int32_t vcfgindex); - void pump_move_by_x100nl_block(int32_t x100nl, int32_t vcfgindex); + void _pump_move_to_x100nl(int32_t x100nl, int32_t vcfgindex); + void pump_do_lld(int32_t pressure_threshold, int32_t ___, int32_t vcfgidx); + void pump_move_to_x100nl_block(double x100nl, int32_t vcfgindex, int32_t *diff = nullptr); + void pump_move_by_x100nl_block(double x100nl, int32_t vcfgindex); private: void push_pressure_sample_data(int32_t motor_pos, int32_t pressure_val); diff --git a/sdk/components/sensors/smtp2_v2/smtp2_v2.cpp b/sdk/components/sensors/smtp2_v2/smtp2_v2.cpp index 21c7d50..2bda0fe 100644 --- a/sdk/components/sensors/smtp2_v2/smtp2_v2.cpp +++ b/sdk/components/sensors/smtp2_v2/smtp2_v2.cpp @@ -11,7 +11,7 @@ using namespace smtp2; #define TAG "SMTP2" #define OVERTIME 100 -#define DUMP_HEX 1 +#define DUMP_HEX 0 #define RE_SEND_TIMES 5 #define RE_SEND_DELAY 400 @@ -74,10 +74,22 @@ int32_t SMTP2V2::pump_set_pressure_data_stream_port(int32_t val /*0:无 1:232 3: return setstate(true, "/1u%d,%dR\r", kcfg_pressure_data_port_channel, val); } -int32_t SMTP2V2::pump_set_tip_size(TipSize_t size) { - ZLOGI(TAG, "pump_set_tip_size %d", size); +int32_t SMTP2V2::pump_set_tip_type(TipSize_t size) { + ZLOGI(TAG, "pump_set_tip_type %d", size); return setstate(true, "/1u%d,%dR\r", kcfg_tip_size, size); } + +// 该方法调用会报参数错误,原因未知 +// int32_t SMTP2V2::pump_set_max_limit(int32_t nl) { +// ZLOGI(TAG, "pump_set_max_limit %d", nl); +// if (nl < 0) { +// ZLOGE(TAG, "pump_set_max_limit nl < 0"); +// return -1; +// } +// return setstate(true, "/1u%d,%dR\r", kcfg_total_range, nl); +// } +int32_t SMTP2V2::pump_get_max_limit(int32_t* nl) { return pump_get_state_as_int(kstate_total_range, nl); } + int32_t SMTP2V2::pump_enable_temp_compensation(int32_t enable) { ZLOGI(TAG, "pump_enable_temp_compensation %d", enable); return setstate(true, "/1u%d,%dR\r", kcfg_auto_temp_compensation, enable); @@ -93,6 +105,7 @@ int32_t SMTP2V2::pump_set_plld_start_delay(int32_t delay_ms) { int32_t SMTP2V2::pump_set_vcfg(VelCfg* vcfg) { ZLOGI(TAG, "pump_set_vcfg %d,%d,%d,%d,%d", vcfg->acc, vcfg->dec, vcfg->vstart, vcfg->vstop, vcfg->vmax); // L,设置加速度,和减速度 (1..20) V%d 设置最大速度 v%d 设置起始速度 c%d 设置停止速度 + fix_vcfg(vcfg); return setstate(true, "/1N2L%d,%dv%dc%dV%dR\r", // vcfg->acc, vcfg->dec, vcfg->vstart * 1000, vcfg->vstop * 1000, vcfg->vmax * 1000); } @@ -105,10 +118,11 @@ int32_t SMTP2V2::pump_put_tip() { ZLOGI(TAG, "pump_put_tip"); return runaction(true, "/1E0R\r"); } -int32_t SMTP2V2::pump_reset() { - ZLOGI(TAG, "pump_reset"); - _sendcmd(true, "/1!0R\r"); // 复位指令没有回执,所以这里只能使用方法_sendcmd - _sendcmd(true, "/1!0R\r"); // 复位指令没有回执,所以这里只能使用方法_sendcmd +int32_t SMTP2V2::pump_factory_reset() { + ZLOGI(TAG, "pump_factory_reset"); + _sendcmd(true, "/1!22R\r"); // + _sendcmd(true, "/1!0R\r"); // 复位指令没有回执,所以这里只能使用方法_sendcmd + _sendcmd(true, "/1!0R\r"); // 复位指令没有回执,所以这里只能使用方法_sendcmd return 0; } @@ -116,12 +130,18 @@ int32_t SMTP2V2::pump_reset() { * ACTION * ***********************************************************************************************************************/ -int32_t SMTP2V2::pump_move_to_nl(VelCfg* vcfg, int32_t nl) { - ZLOGI(TAG, "pump_move_to_nl %d", nl); - ZLOGI(TAG, "vcfg acc %d dec %d vstart %d vstop %d vmax %d", vcfg->acc, vcfg->dec, vcfg->vstart, vcfg->vstop, vcfg->vmax); +int32_t SMTP2V2::_pump_move_to_nl(VelCfg* vcfg, int32_t nl) { + ZLOGI(TAG, " _pump_move_to_nl %d", nl); + ZLOGI(TAG, " vcfg acc %d dec %d vstart %d vstop %d vmax %d", vcfg->acc, vcfg->dec, vcfg->vstart, vcfg->vstop, vcfg->vmax); + fix_vcfg(vcfg); + return runaction(true, "/1N2L%d,%dv%dc%dV%dA%dR\r", // vcfg->acc, vcfg->dec, vcfg->vstart * 1000, vcfg->vstop * 1000, vcfg->vmax * 1000, nl); } +int32_t SMTP2V2::pump_move_to_nl(VelCfg* vcfg, int32_t nl) { + ZLOGI(TAG, " pump_move_to_nl %d", nl); + return _pump_move_to_nl(vcfg, nl); +} int32_t SMTP2V2::pump_move_by_nl(VelCfg* vcfg, int32_t nl) { ZLOGI(TAG, "pump_move_by_nl %d", nl); int32_t nownl; @@ -226,9 +246,13 @@ int32_t SMTP2V2::pump_aspirate_infer_eigen_time(int32_t v, int32_t ul) { int32_t SMTP2V2::pump_get_infer_eigen_time(int32_t* eigen_time) { return pump_get_state_as_int(kstate_q_time, eigen_time); } -int32_t SMTP2V2::pump_aspirate_plld(int32_t pressure_threshold) { +int32_t SMTP2V2::pump_aspirate_plld(int32_t pressure_threshold, VelCfg* vcfg) { ZLOGI(TAG, "pump_aspirate_plld %d", pressure_threshold); - return runaction(true, "/1t%d,1R\r", pressure_threshold); + fix_vcfg(vcfg); + + return runaction(true, "/1N2L%d,%dv%dc%dV%dt%d,1R\r", // + vcfg->acc, vcfg->dec, vcfg->vstart * 1000, vcfg->vstop * 1000, vcfg->vmax * 1000, // + pressure_threshold); } int32_t SMTP2V2::pump_aspirate_plld_get_state(int32_t* detected) { int32_t isbusy = 0; @@ -297,6 +321,11 @@ int32_t SMTP2V2::pump_get_state_as_int(int32_t state_index, int32_t* val) { *val = getAck0AsInt(); return err::ksucc; } +const char* SMTP2V2::pump_read_version() { + int ret = readstate(true, "/1?%d\r", kstate_firmware); + if (ret != 0) return "fail"; + return getAckStr(); +} int32_t SMTP2V2::getAckEcode() { if (m_rxNum < 3) { @@ -331,6 +360,21 @@ int32_t SMTP2V2::getAck0AsInt() { int intval = atoi(&m_rxprocessbuf[3]); return intval; } +const char* SMTP2V2::getAckStr() { + if (m_rxNum < 3) { + return nullptr; + } + memset(m_rxprocessbuf, 0, sizeof(m_rxprocessbuf)); + memcpy(m_rxprocessbuf, m_rxbuf, m_rxNum); + for (size_t i = 0; i < m_rxNum; i++) { + if (m_rxprocessbuf[i] == '\r' || m_rxprocessbuf[i] == '\n' || m_rxprocessbuf[i] == 0x03) { + m_rxprocessbuf[i] = 0; + break; + } + } + return &m_rxprocessbuf[3]; +} + int32_t SMTP2V2::runaction(bool dump, const char* format, ...) { static char cmdbuf[256]; va_list args; @@ -453,3 +497,33 @@ bool SMTP2V2::_sendcmd_dma(const char* cmd) { osDelay(10); return true; } + +void SMTP2V2::fix_vcfg(VelCfg* vcfg) { +#if 1 + // 启动速度[v] ≤ 停止速度[c] ≤ 最高速度[V] + bool fixed = false; + if (vcfg->vstop > vcfg->vmax) { + vcfg->vstop = vcfg->vmax; + fixed = true; + } + + if (vcfg->vstart > vcfg->vstop) { + vcfg->vstart = vcfg->vstop; + fixed = true; + } + if (vcfg->acc < 1) { + vcfg->acc = 1; + fixed = true; + } + + if (vcfg->dec < 1) { + vcfg->dec = 1; + fixed = true; + } + + if (fixed) { + ZLOGI(TAG, " fixed vcfg %d,%d,%d,%d,%d", vcfg->acc, vcfg->dec, vcfg->vstart, vcfg->vstop, vcfg->vmax); + } +#endif + return; +} diff --git a/sdk/components/sensors/smtp2_v2/smtp2_v2.hpp b/sdk/components/sensors/smtp2_v2/smtp2_v2.hpp index 529bdd6..8f2727e 100644 --- a/sdk/components/sensors/smtp2_v2/smtp2_v2.hpp +++ b/sdk/components/sensors/smtp2_v2/smtp2_v2.hpp @@ -61,9 +61,9 @@ typedef enum { kcfg_motor_hold_current = 13, // 电机保持电流(单位:0.01A)0...200 default:10 kcfg_motor_run_current = 14, // 电机运行电流(单位:0.01A)0...200 default:25 kcfg_pLLD_start_delay = 15, // pLLD启动延迟(毫秒)0...2000 default:100 - kcfg_nL_increment = 16, // 纳升/增量。此值用于将[N2]模式的nL 输入和输出转换为增量。 (当前系统中不使用) + kcfg_nL_increment = 16, // 纳升/增量。此值用于将[N2]模式的nL 输入和输出转换为增量。 kcfg_total_range = 17, // 用nL表示的总量程。当这个值被改变时,u1所设定的值也会按照这个公式自动变更:u1=u17/u16 同时,u1改变时,此值也会自动变更:u17=u1*u16 (当前系统中不使用) - kcfg_tip_size = 18, // Tip大小。对此值进行设置之后,u1和u17的值将会自动进行变更。 (当前系统中不使用) + kcfg_tip_size = 18, // Tip大小。对此值进行设置之后,u1和u17的值将会自动进行变更。 kcfg_default_tolerance = 21, // [q] 命令默认容差 kcfg_pressure_data_stream_time = 22, // 泵运动完成后保持压力数据流输出的时间(毫秒)。请参见[+]命令。 kcfg_auto_temp_compensation = 24, // 自动使用温度补偿。 @@ -195,7 +195,9 @@ class SMTP2V2 { int32_t pump_set_io1_mode(int32_t mode); // 0LLD输出高 1LLD输出低 2通用输出 int32_t pump_set_io1_state(int32_t state); // int32_t pump_set_io2_mode(int32_t mode); // 0通用输入 1紧急制动 2Tip脱落输出高 3Tip脱落输出低 - int32_t pump_set_tip_size(TipSize_t size); // Tip大小 0:1ml 1:200ul(max:250ul) 2:50ul(max:62ul) 3=20ul(max:40ul) + int32_t pump_set_tip_type(TipSize_t size); // Tip大小 0:1ml 1:200ul(max:250ul) 2:50ul(max:62ul) 3=20ul(max:40ul) + // int32_t pump_set_max_limit(int32_t nl); // + int32_t pump_get_max_limit(int32_t* nl); // 获取最大行程 int32_t pump_enable_temp_compensation(int32_t enable); // 0:关闭 1:开启 int32_t pump_set_back_clearance(int32_t val); int32_t pump_set_pressure_data_stream_port(int32_t val /*0:无 1:232 3:CAN*/); @@ -203,23 +205,25 @@ class SMTP2V2 { /*********************************************************************************************************************** * STATE * ***********************************************************************************************************************/ - int32_t pump_get_state(int32_t* isbusy); - int32_t pump_get_capacitance(int32_t* capacitance); - int32_t pump_get_pressure(int32_t* pressure); - int32_t pump_get_tip_state(int32_t* tipison); - int32_t pump_get_nl(int32_t* nl); - int32_t pump_get_state_as_int(int32_t state_index, int32_t* val); + int32_t pump_get_state(int32_t* isbusy); + int32_t pump_get_capacitance(int32_t* capacitance); + int32_t pump_get_pressure(int32_t* pressure); + int32_t pump_get_tip_state(int32_t* tipison); + int32_t pump_get_nl(int32_t* nl); + int32_t pump_get_state_as_int(int32_t state_index, int32_t* val); + const char* pump_read_version(); /*********************************************************************************************************************** * ACTION * ***********************************************************************************************************************/ - int32_t pump_init(); // 泵机初始化(归零) - int32_t pump_put_tip(); // 丢弃TIP - int32_t pump_reset(); // 泵机复位 - int32_t pump_stop(); // 停止 - int32_t pump_move_to_nl(VelCfg* vcfg, int32_t nl); // - int32_t pump_move_by_nl(VelCfg* vcfg, int32_t nl); // - int32_t pump_aspirate_plld(int32_t pressure_threshold); // plld,分配探测 + int32_t pump_init(); // 泵机初始化(归零) + int32_t pump_put_tip(); // 丢弃TIP + int32_t pump_factory_reset(); // 泵机复位 + int32_t pump_stop(); // 停止 + int32_t _pump_move_to_nl(VelCfg* vcfg, int32_t nl); + int32_t pump_move_to_nl(VelCfg* vcfg, int32_t nl); // + int32_t pump_move_by_nl(VelCfg* vcfg, int32_t nl); // + int32_t pump_aspirate_plld(int32_t pressure_threshold, VelCfg* vcfg); // plld,分配探测 int32_t pump_aspirate_plld_get_state(int32_t* detected); int32_t pump_clld(int32_t c_threshold); // clld 0...130 @@ -244,6 +248,7 @@ class SMTP2V2 { void dumpparam(); + private: int32_t runaction(bool dump, const char* format, ...); int32_t _runaction(bool dump, const char* cmd); @@ -253,8 +258,11 @@ class SMTP2V2 { bool _sendcmd(bool dump, const char* cmd); bool _sendcmd_dma(const char* cmd); - int32_t getAckEcode(); - int32_t getAck0AsInt(); + int32_t getAckEcode(); + int32_t getAck0AsInt(); + const char* getAckStr(); + + void fix_vcfg(VelCfg* vcfg); }; } // namespace smtp2 diff --git a/sdk/components/tmc/ic/ztmc5130.cpp b/sdk/components/tmc/ic/ztmc5130.cpp index 708604f..679815b 100644 --- a/sdk/components/tmc/ic/ztmc5130.cpp +++ b/sdk/components/tmc/ic/ztmc5130.cpp @@ -105,6 +105,26 @@ void TMC51X0::set_vstop(int32_t vel) { } void TMC51X0::set_tzerowait(int32_t val) { writeInt(TMC5130_TZEROWAIT, val); } void TMC51X0::set_vmax(int32_t vmax) { writeInt(TMC5130_VMAX, to_motor_vel(vmax)); } +void TMC51X0::set_vcfg(VCfg_t *vcfg) { + // VMAX>V1>VSTOP>VSTART + if (vcfg->v1 > vcfg->vmax) { + vcfg->v1 = vcfg->vmax; + } + if (vcfg->vstop > vcfg->v1) { + vcfg->vstop = vcfg->v1; + } + if (vcfg->vstart > vcfg->vstop) { + vcfg->vstart = vcfg->vstop; + } + set_a1(vcfg->a1); + set_amax(vcfg->amax); + set_v1(vcfg->v1); + set_dmax(vcfg->dmax); + set_d1(vcfg->d1); + set_vstart(vcfg->vstart); + set_vstop(vcfg->vstop); + set_vmax(vcfg->vmax); +} void TMC51X0::enable(bool enable) { // m_port->TMC5130Port_setENNPinState(m_channel, !enable); diff --git a/sdk/components/tmc/ic/ztmc5130.hpp b/sdk/components/tmc/ic/ztmc5130.hpp index 3618940..a30dd5c 100644 --- a/sdk/components/tmc/ic/ztmc5130.hpp +++ b/sdk/components/tmc/ic/ztmc5130.hpp @@ -87,6 +87,17 @@ class TMC51X0 : public IStepperMotor { } GState_t; typedef struct { + int32_t vstart; + int32_t a1; + int32_t amax; + int32_t v1; + int32_t dmax; + int32_t d1; + int32_t vstop; + int32_t vmax; + } VCfg_t; + + typedef struct { SPI_HandleTypeDef *spi; Pin_t csgpio = PinNull; // Pin_t ennPin = PinNull; // @@ -172,6 +183,8 @@ class TMC51X0 : public IStepperMotor { virtual void set_tzerowait(int32_t val); virtual void set_vmax(int32_t vmax); + virtual void set_vcfg(VCfg_t *vcfg); + public: DevStatusReg_t getDevStatus() { // R 读后不清 static_assert(sizeof(DevStatusReg_t) == 4); diff --git a/sdk/components/zcan_protocol_parser/zcan_protocol_parser.cpp b/sdk/components/zcan_protocol_parser/zcan_protocol_parser.cpp index cfae2a8..a5f13b7 100644 --- a/sdk/components/zcan_protocol_parser/zcan_protocol_parser.cpp +++ b/sdk/components/zcan_protocol_parser/zcan_protocol_parser.cpp @@ -196,6 +196,9 @@ void ZCanProtocolParser::initialize(ZCanReceiver* cancmder) { REGFN(pipette_read_tip_state); REGFN(pipette_read_pressure); REGFN(pipette_read_capacitance); + + REGFN(pipette_test_pump_move_to_x100nl); + REGFN(pipette_test_lld); } void ZCanProtocolParser::_registerModule(uint16_t id, ZIModule* module) { m_modulers[id] = module; } void ZCanProtocolParser::registerModule(ZIModule* module) { _registerModule(module->getid(), module); } @@ -1103,7 +1106,7 @@ int32_t ZCanProtocolParser::pipette_pump_aspirate(cmdcontxt_t* cxt) { int32_t ZCanProtocolParser::pipette_pump_distribu(cmdcontxt_t* cxt) { CHECK_AND_GET_MODULE(0); - return module->pipette_pump_distribu(); + return module->pipette_pump_distribu_all(); } int32_t ZCanProtocolParser::pipette_get_sensor_sample_data(cmdcontxt_t* cxt) { @@ -1166,4 +1169,17 @@ int32_t ZCanProtocolParser::pipette_read_capacitance(cmdcontxt_t* cxt) { return module->pipette_read_capacitance(&ack[0]); } +// kpipette_test_pump_move_to_x100nl = 0x7600, // int32_t x100nl, int32_t vcfgindex +// kpipette_test_lld = 0x7601, // int32_t container_pos, int32_t container_cpyid, int32_t liquid_cpyid + +int32_t ZCanProtocolParser::pipette_test_pump_move_to_x100nl(cmdcontxt_t* cxt) { + CHECK_AND_GET_MODULE(2); + return module->pipette_test_pump_move_to_x100nl(cxt->params[0], cxt->params[1]); +} + +int32_t ZCanProtocolParser::pipette_test_lld(cmdcontxt_t* cxt) { + CHECK_AND_GET_MODULE(3); + return module->pipette_test_lld(cxt->params[0], cxt->params[1], cxt->params[2]); +} + #undef MODULE_CLASS \ No newline at end of file diff --git a/sdk/components/zcan_protocol_parser/zcan_protocol_parser.hpp b/sdk/components/zcan_protocol_parser/zcan_protocol_parser.hpp index fdc1790..906bfab 100644 --- a/sdk/components/zcan_protocol_parser/zcan_protocol_parser.hpp +++ b/sdk/components/zcan_protocol_parser/zcan_protocol_parser.hpp @@ -217,6 +217,9 @@ class ZCanProtocolParser : public IZCanRxProcesser { CMDFN(pipette_read_tip_state); CMDFN(pipette_read_pressure); CMDFN(pipette_read_capacitance); + + CMDFN(pipette_test_pump_move_to_x100nl); + CMDFN(pipette_test_lld); }; } // namespace iflytop \ No newline at end of file diff --git a/usrc/a8000_protocol/protocol/cmdid.cpp b/usrc/a8000_protocol/protocol/cmdid.cpp index 8afe097..95b04f1 100644 --- a/usrc/a8000_protocol/protocol/cmdid.cpp +++ b/usrc/a8000_protocol/protocol/cmdid.cpp @@ -163,6 +163,9 @@ static cmdinfo_t table[] = { CMD_ITERM(kpipette_read_tip_state), CMD_ITERM(kpipette_read_pressure), CMD_ITERM(kpipette_read_capacitance), + + CMD_ITERM(kpipette_test_pump_move_to_x100nl), + CMD_ITERM(kpipette_test_lld), }; const char* cmdid2str(int32_t code) { diff --git a/usrc/a8000_protocol/protocol/cmdid.hpp b/usrc/a8000_protocol/protocol/cmdid.hpp index c3d3027..15e018d 100644 --- a/usrc/a8000_protocol/protocol/cmdid.hpp +++ b/usrc/a8000_protocol/protocol/cmdid.hpp @@ -158,8 +158,8 @@ typedef enum { kpipette_zmotor_move_to = 0x7506, kpipette_zmotor_read_zero_point_state = 0x7507, kpipette_zmotor_read_dev_status_cache = 0x7508, - kpipette_zmotor_read_pos = 0x7509, - kpipette_zmotor_read_enc_pos = 0x750A, + kpipette_zmotor_read_pos = 0x7509, + kpipette_zmotor_read_enc_pos = 0x750A, kpipette_pump_init_device = 0x7580, kpipette_pump_take_tip = 0x7581, @@ -176,6 +176,9 @@ typedef enum { kpipette_read_pressure = 0x758C, // ack:{state} kpipette_read_capacitance = 0x758D, // ack:{state} + kpipette_test_pump_move_to_x100nl = 0x7600, // int32_t x100nl, int32_t vcfgindex + kpipette_test_lld = 0x7601, // int32_t container_pos, int32_t container_cpyid, int32_t liquid_cpyid + } cmdid_t; typedef struct { diff --git a/usrc/a8000_protocol/protocol/errorcode.cpp b/usrc/a8000_protocol/protocol/errorcode.cpp index 4a03cc6..397e919 100644 --- a/usrc/a8000_protocol/protocol/errorcode.cpp +++ b/usrc/a8000_protocol/protocol/errorcode.cpp @@ -92,8 +92,7 @@ static ecode_table_item_t table[] = { ERR_ITERM(kwater_cooling_pelter_is_error), ERR_ITERM(kstep_motor_subic_init_fail), ERR_ITERM(kstep_motor_subic_offline), - - + ERR_ITERM(kpipette_pm_positioning_abnormality), }; diff --git a/usrc/a8000_protocol/protocol/errorcode.hpp b/usrc/a8000_protocol/protocol/errorcode.hpp index 58d2696..81ff19e 100644 --- a/usrc/a8000_protocol/protocol/errorcode.hpp +++ b/usrc/a8000_protocol/protocol/errorcode.hpp @@ -70,6 +70,7 @@ typedef enum { kpipette_error_pump_load_val_is_not_empty = 1503, kpipette_lld_error_no_liquid_detected = 1504, kpipette_lld_error_pump_reach_max_pos = 1505, + kpipette_pm_positioning_abnormality = 1506, // 电机定位异常 kstep_motor_not_found_zero_point = 1600, kstep_motor_not_go_zero = 1601,