|
|
@ -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<void()> 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); |
|
|
|