diff --git a/README.md b/README.md index cdb7a0c..398424d 100644 --- a/README.md +++ b/README.md @@ -3,9 +3,14 @@ ``` -1.1 +v1.1 1.添加打印机逻辑 +v1.2 + 1. D值支持可配置 + 2. 校准并优化桶内消毒液的体积 + 3. 平滑消毒液体积显示 + ``` diff --git a/iflytoplinuxsdk b/iflytoplinuxsdk index 0727f2c..b517025 160000 --- a/iflytoplinuxsdk +++ b/iflytoplinuxsdk @@ -1 +1 @@ -Subproject commit 0727f2cfe0574e10d646d841faa3769e9820f1a0 +Subproject commit b517025b96b5d3b8608ac462aa41ad6eb10eada5 diff --git a/src/configs/gconfig.hpp b/src/configs/gconfig.hpp index b396929..22bce02 100644 --- a/src/configs/gconfig.hpp +++ b/src/configs/gconfig.hpp @@ -20,7 +20,10 @@ marco(int32_t /* */, iflytopSubDeviceCanBitrate, 500000) /*子设备Can设备波特率*/ \ marco(string /* */, pipettingRobotCanIFName, "can1") /*移液臂Can设备名称*/ \ marco(int32_t /* */, pipettingRobotCanBitrate, 500000) /*移液臂Can设备波特率*/ \ - marco(int32_t /* */, disinfectantBucketCapacity_g, 2500) /*消毒桶容积*/ + marco(int32_t /* */, disinfectantBucketCapacity_g, 2200) /*消毒桶容积*/ \ + marco(float /* */, dvalueCoefficient, 1) /*数值越小,相对消毒时间越长*/ \ + marco(float /* */, disinfectantWeightPa, 1) /*数值越小,相对消毒时间越长*/ \ + marco(float /* */, disinfectantWeightCorrectionFactor, 0.9) /*数值越小,相对消毒时间越长*/ configTemplateDEFILE_CONFIG_SERVICE2( // GConfig, // diff --git a/src/service/device_io_control_service.cpp b/src/service/device_io_control_service.cpp index 9979deb..8ab3242 100644 --- a/src/service/device_io_control_service.cpp +++ b/src/service/device_io_control_service.cpp @@ -1,4 +1,5 @@ #include "device_io_control_service.hpp" + #include "iflytop/components/uart_printer/uart_printer.hpp" #include "iflytoplinuxsdk/src/iflytop/components/ziconv.hpp" using namespace iflytop; @@ -14,18 +15,68 @@ using namespace std; -通断电磁阀 3 PC7 5 #endif -#define GPM_TO_SPEED(gpm) (gpm * 10) -#define SPEED_TO_GPM(speed) (speed / 10) +#define GPM_TO_SPEED(gpm) (gpm * 14.7) +#define SPEED_TO_GPM(speed) (speed / 14.7 + 0.5) DeviceIoControlService::DeviceIoControlService() {} -void DeviceIoControlService::initialize() { GET_TO_SERVICE(m_zcanHost); } +void DeviceIoControlService::initialize() { + GET_TO_SERVICE(m_zcanHost); + GET_TO_SERVICE(m_config); +} + +void DeviceIoControlService::updateDisinfectantVolumeSample(float _pa) { + float pa = _pa - 100; // 100当容器中没有液体时的压强 + if (pa < 0) pa = 0; + float g = m_volumeConvertor.pressurePa2VolumeG(_pa) * m_config->get_disinfectantWeightCorrectionFactor(); + m_disinfectantVolumeSample_g = m_DisinfectantWeightFilter.filter(g); + // logger->info("pa:{} _pa:{}", _pa, _pa,g); + logger->info("g:{} pa:{} _pa:{}", g, pa, _pa); +} void DeviceIoControlService::startScan() { - m_workThread.reset(new Thread("DeviceIoControlService", [this]() { + m_PressureSensorDataSampleThread.reset(new Thread("PressureSensorDataSampleThread", [this]() { ThisThread thisThread; - uint32_t i = 0; - int readpressuresensor_id = 1; + while (!thisThread.getExitFlag()) { + /* code */ + ZCanHost::huacheng_pressure_sensor_read_c1005_t sdata; + if (m_zcanHost->huacheng_pressure_sensor_read_c1005(1, sdata) == 0) { + lock_guard lock(lock_); + m_pressure_sensor_data[1] = sdata; + } + + thisThread.sleepForMs(100); + + if (m_zcanHost->huacheng_pressure_sensor_read_c1005(2, sdata) == 0) { + lock_guard lock(lock_); + m_pressure_sensor_data[2] = sdata; + } + + thisThread.sleepForMs(100); + + if (m_zcanHost->huacheng_pressure_sensor_read_c1005(3, sdata) == 0) { + lock_guard lock(lock_); + m_pressure_sensor_data[3] = sdata; + } + + thisThread.sleepForMs(100); + + if (m_zcanHost->huacheng_pressure_sensor_read_c1005(4, sdata) == 0) { + lock_guard lock(lock_); + m_pressure_sensor_data[4] = sdata; + } + + thisThread.sleepForMs(100); + + { updateDisinfectantVolumeSample(m_pressure_sensor_data[1].value / 1.0 /*pa*/); } + } + })); + + m_workThread.reset(new Thread("DeviceIoControlService", [this]() { + ThisThread thisThread; + uint32_t i = 0; + int error = 0; + int readpressuresensor_id = 1; while (!thisThread.getExitFlag()) { /* code */ @@ -47,56 +98,22 @@ void DeviceIoControlService::startScan() { lock_guard lock(lock_); m_adc_2 = adcv; } - // m_zcanHost->readadc(1, m_adc_1); - // m_zcanHost->readadc(2, m_adc_2); - // m_zcanHost->readadc(3, m_adc_3); - // m_zcanHost->readadc(4, m_adc_4); - // m_zcanHost->readadc(5, m_adc_5); } - if (i % 3000 == 0) { + if (i % 3000 == 0 && error < 10) { // m_hpp272_data_1 ZCanHost::hpp272_data_t m_hpp272_data_1_cache; int suc = m_zcanHost->hpp272_read_c1000(1, m_hpp272_data_1_cache); if (suc == 0) { lock_guard lock(lock_); m_hpp272_data_1 = m_hpp272_data_1_cache; + error = 0; + } else { + error++; + if (error == 10) { + logger->error("hpp272_read_c1000 error:{}", suc); + } } - // hydrogen_peroxide_volume - // water_vapor_saturation_pressure_h2o_h2o2 - // logger->info("---------hpp272_read_c1000---------"); - // logger->info("hydrogen_peroxide_volume :{}", m_hpp272_data_1.hydrogen_peroxide_volume); - // logger->info("h2o_h2o2_rs :{}", m_hpp272_data_1.h2o_h2o2_rs); - // logger->info("temperature1 :{}", m_hpp272_data_1.temperature1); - // logger->info("relative_humidity :{}", m_hpp272_data_1.relative_humidity); - // logger->info("absolute_hydrogen_peroxide :{}", m_hpp272_data_1.absolute_hydrogen_peroxide); - // logger->info("h2o_h2o2dew_point_temperature :{}", m_hpp272_data_1.h2o_h2o2dew_point_temperature); - // logger->info("reserved1 :{}", m_hpp272_data_1.reserved1); - // logger->info("water_volume :{}", m_hpp272_data_1.water_volume); - // logger->info("water_vapor_pressure :{}", m_hpp272_data_1.water_vapor_pressure); - // logger->info("absolute_humidity :{}", m_hpp272_data_1.absolute_humidity); - // logger->info("water_vapor_saturation_pressure_h2o:{}", m_hpp272_data_1.water_vapor_saturation_pressure_h2o); - // logger->info("temperature2 :{}", m_hpp272_data_1.temperature2); - // logger->info("h2o2_vapor_pressure :{}", m_hpp272_data_1.h2o2_vapor_pressure); - // logger->info("water_vapor_saturation_pressure_h2o_h2o2:{}", m_hpp272_data_1.water_vapor_saturation_pressure_h2o_h2o2); - // logger->info(""); - } - - if (i % 300 == 0) { - if (readpressuresensor_id == 5) { - readpressuresensor_id = 1; - } - ZCanHost::huacheng_pressure_sensor_read_c1005_t sdata; - if (m_zcanHost->huacheng_pressure_sensor_read_c1005(readpressuresensor_id, sdata) == 0) { - lock_guard lock(lock_); - m_pressure_sensor_data[readpressuresensor_id] = sdata; - } - readpressuresensor_id++; - } - - if (i % 100 == 0) { - // m_zcanHost->readio(1, m_waterImmersionSensor1); - // m_zcanHost->readio(2, m_waterImmersionSensor2); } } })); @@ -325,19 +342,21 @@ static int filter(int data) { } int DeviceIoControlService::getDisinfectantVolume_g() { - // kpa; lock_guard lock(lock_); + return m_disinfectantVolumeSample_g; - float kpa = m_pressure_sensor_data[1].value / 1000.0; - int g = 2.11 * kpa * 1000 * 1.3; - if (g < 450) { /*零点*/ - return 0; - } else { - g -= 450; - } - g = filter(g); - // logger->info("g {}", g); - return g; + // kpa; + // lock_guard lock(lock_); + // float kpa = m_pressure_sensor_data[1].value / 1000.0; + // int g = 2.11 * kpa * 1000 * 1.3; + // if (g < 450) { /*零点*/ + // return 0; + // } else { + // g -= 450; + // } + // g = filter(g); + // // logger->info("g {}", g); + // return g; } int DeviceIoControlService::getPressureSensorData(int index) { lock_guard lock(lock_); @@ -458,6 +477,5 @@ bool DeviceIoControlService::getAllSensorData(DeviceIoControlService::all_h2o2se return true; } - void DeviceIoControlService::printerTest() {} void DeviceIoControlService::printerPrintf(string str) { GET_SERVICE(UartPrinter)->print(ZIconv::utf8_to_gb2312(str)); } diff --git a/src/service/device_io_control_service.hpp b/src/service/device_io_control_service.hpp index 18057fa..9d798d9 100644 --- a/src/service/device_io_control_service.hpp +++ b/src/service/device_io_control_service.hpp @@ -21,6 +21,10 @@ #include // std::lock_guard lock(lock_); +// +#include "configs/gconfig.hpp" +#include "utils/moving_average_filter.hpp" +#include "utils/volume_convertor.hpp" /** * @brief @@ -62,6 +66,13 @@ class DeviceIoControlService : public enable_shared_from_this m_PressureSensorDataSampleThread; + shared_ptr m_config; + // 液体重量计算 + int32_t m_disinfectantVolumeSample_g; // 消毒液量采样 + VolumeConvertor m_volumeConvertor; + MovingAverageFilter m_DisinfectantWeightFilter = MovingAverageFilter(20); + public: int32_t m_airCompressor_channelIndex = 0; int32_t m_airCompressor_valve1State = 0; @@ -178,5 +189,8 @@ class DeviceIoControlService : public enable_shared_from_thisheartingPlate_setPower(false); m_deviceIoControlService->airBlower_setState(false); m_deviceIoControlService->airCompressor_setState(false); + + m_dvalueComputer.initialize(); } static string getTime() { @@ -96,37 +98,7 @@ static bool zfeq(float a, float b, float eps = 0.01) { } return false; } -float DisinfectionCtrlService::getDisinfectionDValue(float ppm) { - /** - * @brief - * - * D值的计算公式是根据美国竞品的数据记录计算得来的 - * - * 浓度小于150时,y=-0.5269X+97.868 - * 浓度大于150时,y=-0.1405X+40.369 - */ - - if (zfeq(ppm, 0)) { - return -1; - } - - float dvalue = 0; - - if (ppm < 150) { - dvalue = -0.5251 * ppm + 98.154; - } else if (ppm >= 150 && ppm < 240) { - dvalue = -0.125 * ppm + 38.913; - } else if (ppm >= 240) { - // 240 -> 8.913 - // 1400 -> 2 - // y = -0.00603x + 10.4472 - dvalue = -0.00596 * ppm + 10.3434; - } - if (dvalue < 2) { - dvalue = 2; - } - return dvalue; -} +float DisinfectionCtrlService::getDisinfectionDValue(float ppm) { return m_dvalueComputer.computeDValue(ppm); } float DisinfectionCtrlService::computeNowLogLevel(DisinfectionContext& context) { float dvalue = context.dvalue; if (dvalue > 0) { diff --git a/src/service/disinfection_ctl_service.hpp b/src/service/disinfection_ctl_service.hpp index a4e076d..88f406d 100644 --- a/src/service/disinfection_ctl_service.hpp +++ b/src/service/disinfection_ctl_service.hpp @@ -19,6 +19,7 @@ #include "iflytop/components/zcanreceiver/zcanhost.hpp" #include "iflytop/core/core.hpp" #include "service/device_io_control_service.hpp" +#include "utils/dvalue_computer.hpp" #include "zservice_container/zservice_container.hpp" /** * @brief @@ -55,6 +56,8 @@ class DisinfectionCtrlService : public enable_shared_from_this m_dbService; shared_ptr m_disinfectionLogsManager; + DValueComputer m_dvalueComputer; + recursive_mutex lock_; int m_disinfectionWorkState = 0; @@ -99,7 +102,6 @@ class DisinfectionCtrlService : public enable_shared_from_this csvlogger; - }; public: diff --git a/src/utils/dvalue_computer.cpp b/src/utils/dvalue_computer.cpp new file mode 100644 index 0000000..4a7564b --- /dev/null +++ b/src/utils/dvalue_computer.cpp @@ -0,0 +1,55 @@ +#include "dvalue_computer.hpp" + +#include + +#include "zservice_container/zservice_container.hpp" +using namespace iflytop; +using namespace std; + +static bool zfeq(float a, float b, float eps = 0.01) { + if (fabs(a - b) < eps) { + return true; + } + return false; +} + +void DValueComputer::initialize() { + /** + * @brief + */ + + m_config = GET_SERVICE(GConfig); +} + +float DValueComputer::computeDValue(float h2o2ppm) { + /** + * @brief + * + * D值的计算公式是根据美国竞品的数据记录计算得来的 + * + * 浓度小于150时,y=-0.5269X+97.868 + * 浓度大于150时,y=-0.1405X+40.369 + */ + + if (zfeq(h2o2ppm, 0)) { + return -1; + } + + float dvalue = 0; + + if (h2o2ppm < 150) { + // + dvalue = -0.5251 * h2o2ppm + 98.154; + } else if (h2o2ppm >= 150 && h2o2ppm < 240) { + // + dvalue = -0.125 * h2o2ppm + 38.913; + } else if (h2o2ppm >= 240) { + // + dvalue = -0.00596 * h2o2ppm + 10.3434; + } + if (dvalue < 2) { + dvalue = 2; + } + dvalue = dvalue * m_config->get_dvalueCoefficient(); + return dvalue; +} diff --git a/src/utils/dvalue_computer.hpp b/src/utils/dvalue_computer.hpp new file mode 100644 index 0000000..e2c5418 --- /dev/null +++ b/src/utils/dvalue_computer.hpp @@ -0,0 +1,16 @@ + +#pragma once +#include + +#include "configs/gconfig.hpp" +namespace iflytop { + +class DValueComputer { + ENABLE_LOGGER(DValueComputer); + shared_ptr m_config; + + public: + void initialize(); + float computeDValue(float h2o2ppm); +}; +} // namespace iflytop \ No newline at end of file diff --git a/src/utils/moving_average_filter.hpp b/src/utils/moving_average_filter.hpp new file mode 100644 index 0000000..7e7246c --- /dev/null +++ b/src/utils/moving_average_filter.hpp @@ -0,0 +1,43 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +namespace iflytop { +using namespace std; + +class MovingAverageFilter { + size_t size_; + float sum_ = 0; + std::list values_; + + public: + MovingAverageFilter(size_t size) : size_(size) { + if (size_ <= 0) { + throw std::invalid_argument("size must be greater than 0"); + } + } + + float filter(float value) { + if (values_.size() < size_) { + values_.push_back(value); + sum_ += value; + return sum_ / values_.size(); + } + + sum_ -= values_.front(); + values_.pop_front(); + values_.push_back(value); + sum_ += value; + return sum_ / size_; + } + + private: +}; +} // namespace iflytop diff --git a/src/utils/volume_convertor.cpp b/src/utils/volume_convertor.cpp new file mode 100644 index 0000000..8b0fb5c --- /dev/null +++ b/src/utils/volume_convertor.cpp @@ -0,0 +1,81 @@ +#include "volume_convertor.hpp" + +using namespace iflytop; + +float VolumeConvertor::pa2high(float pa) { + /** + * @brief kpa 转换成液面高度 + * + * p = h*density*g + * + * h = p/(density*g) + * + * p :压强, 单位 pa + * density:液体密度, 单位 kg/m^3 + * g :重力加速度, 单位 + * h :液面高度, 单位 m + * + * 过氧化氢 浓度30.5%时密度=1.11331981022045g/cm^3 = 1113.31981022045kg/m^3 + * + */ + // 计算液面高度 + float h_m = pa / (density * 9.78); // 液体密度最后会被约掉,大小不影响结果 + float h_dm = h_m * 10; + + return h_dm; +} +/** + * @brief 计算倒圆锥体积 + * + * @param rb 圆锥体底部半径 + * @param ru 圆锥体顶部半径 + * @param h 圆锥体高度 + * @param nowh 圆锥内液面高度 + * @return float + */ +float VolumeConvertor::computeConeVolume(float rb, float ru, float h, float nowh) { + if (nowh > h) nowh = h; + if (nowh < 0) nowh = 0; + + float rb_now = rb + (ru - rb) * nowh / h; + float v = PI * nowh * (rb_now * rb_now + rb_now * ru + ru * ru) / 3; + return v; +} + +float VolumeConvertor::pressurePa2VolumeG(float _pa) { + float pa = _pa - 90; + if (pa < 0) { + pa = 0; + } + + // 计算液面高度 + float h_dm = pa2high(pa); + + float h1_dm = h_dm; + float h2_dm = h_dm - container_h1; + float h3_dm = h_dm - container_h2 - container_h1; + float h4_dm = h_dm - container_h3 - container_h2 - container_h1; + + h1_dm = h1_dm < 0 ? 0 : h1_dm; + h2_dm = h2_dm < 0 ? 0 : h2_dm; + h3_dm = h3_dm < 0 ? 0 : h3_dm; + h4_dm = h4_dm < 0 ? 0 : h4_dm; + + h1_dm = h1_dm > container_h1 ? container_h1 : h1_dm; + h2_dm = h2_dm > container_h2 ? container_h2 : h2_dm; + h3_dm = h3_dm > container_h3 ? container_h3 : h3_dm; + h4_dm = h4_dm > container_h4 ? container_h4 : h4_dm; + +// printf("h_dm:%f h1_dm:%f, h2_dm:%f, h3_dm:%f, h4_dm:%f\n",h_dm, h1_dm, h2_dm, h3_dm, h4_dm); + + float v1 = computeConeVolume(container_rb1, container_ru1, container_h1, h1_dm); + float v2 = computeConeVolume(container_rb2, container_ru2, container_h2, h2_dm); + float v3 = computeConeVolume(container_rb3, container_ru3, container_h3, h3_dm); + float v4 = computeConeVolume(container_rb4, container_ru4, container_h4, h4_dm); +// printf("v1:%f, v2:%f, v3:%f, v4:%f\n", v1, v2, v3, v4); + + // h4_dm * (double)(2.1124069002737764) + float V_L = v1 + v2 + v3 + v4; // 0.001m^3 + float g = V_L * density; // 1m^3 = 1000L + return g; +} \ No newline at end of file diff --git a/src/utils/volume_convertor.hpp b/src/utils/volume_convertor.hpp new file mode 100644 index 0000000..0ff1f2a --- /dev/null +++ b/src/utils/volume_convertor.hpp @@ -0,0 +1,69 @@ + +#pragma once +#include + +namespace iflytop { + +#define PI 3.14159265358979323846 + +class VolumeConvertor { + /** + * @brief + * + * | <--r4_2 -->| + * _____________ + * | | + * | | + * | | h4 + * | | + * | r4_1 | + * \ / h3 + * | | h2 + * \ _____ / h1 + * + * + * | ru | + * ----------- + * \ / + * \ / h + * \_____/ + * |rb| + * + */ + + float container_h4 = 1.83; + float container_ru4 = 0.64; + float container_rb4 = 0.64; + + float container_h3 = 0.17; + float container_ru3 = 0.64; + float container_rb3 = 0.47; + + float container_h2 = 0.0737; + float container_ru2 = 0.47; + float container_rb2 = 0.47; + + float container_h1 = 0.0376; + float container_ru1 = 0.47; + float container_rb1 = 0.04; + + float density = 1000; // kg/m^3 + + public: + float pressurePa2VolumeG(float _pa); + + private: + float pa2high(float pa); + /** + * @brief 计算倒圆锥体积 + * + * @param rb 圆锥体底部半径 + * @param ru 圆锥体顶部半径 + * @param h 圆锥体高度 + * @param nowh 圆锥内液面高度 + * @return float + */ + float computeConeVolume(float rb, float ru, float h, float nowh); +}; + +} // namespace iflytop diff --git a/src/version.hpp b/src/version.hpp index 939163c..ad8ec44 100644 --- a/src/version.hpp +++ b/src/version.hpp @@ -1,2 +1,2 @@ #pragma once -#define VERSION "pipeline_disinfection_1.0" \ No newline at end of file +#define VERSION "1.2" \ No newline at end of file