迪文科技论坛

 找回密码
 立即注册
搜索
查看: 347|回复: 2

【2024.2.27获奖项目】全工位氢氧根离子检测站

[复制链接]

567

主题

167

回帖

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
11957
发表于 2024-3-4 11:51:31 | 显示全部楼层 |阅读模式
【开源】全工位氢氧根离子检测站

一、简介
    本开源项目一个用于检测水中离子含量的工作站,主要是氢氧根离子,根据反性原则,也可以得到大致的H+离子浓度,这里的测检水可以分为多种的,通常情况下可用于电厂污水, 纺织污水, 池塘污水等等,根据检测到的离子浓度做出及时防护措施,以往检测人员比较辛苦,都是通过人工采样后,然后再接着人工化学试剂的方式来分析离子浓度,这样的做法费时费力而且有时候精度差,不能很好的批量化检测,而全工位氢氧根离子检测站就是基于此需求而诞生的一款自动化全工位设备.简化了人力,大大的加快效率,它有如下特点:
  1.具有全工位效率,默认为1-40工位,可以搭配多阶延长板实现外扩到1-120工位;
  2.具有工位多兼容性,工位的大小可以手动调节,支持宽瓶, 窄瓶, 小试管, 长试管等等;
  3.配置三轴机械爪,实现全工位范围内的移动, 搅拌,浸泡, 测量等操作;
  4.具有6级测量精度可选择,当选为自动档时,系统自动预判;
  5.支持多点离子校准,点数是任意的,不强制,不固定;
  6.仪器运行状态,以及校准状态详细展示;
  7.起始工位,工位数量可以任意设置,但不能跳点;
硬件上有rs485, rs232双接口,配合modbus协议和私有协议实现对接各路外机。

二、GUI工程

图标素材





图片素材

DGUS tool等界面







三、C51工程
  1. <font face="宋体" size="3">机械臂核心操作代码
  2. #ifndef __BASE_H__
  3. #define __BASE_H__
  4. #include "sys.h"

  5. #define BASE_SHAKE_CNT_DEF                        12
  6. #define BASE_CLEAN_TIME_DEF                        3

  7. u8 base_shake(u16 cnt,u16 quit_code);
  8. u8 base_clean(u16 clean_time, u16 quit_code);
  9. u8 base_air_dry(u16 quit_code);
  10. u8 base_select_sample(u8 pos,u8 is_clean,u16 quit_code);


  11. #include "base.h"
  12. #include "motor.h"
  13. #include "test.h"
  14. #include "params.h"












  15. u8 base_shake_x_or_y(u8 is_x,u16 cnt,u16 quit_code)
  16. {
  17.         #define SHAKE_STEP                        300
  18.         #define SHAKE_DELAY                        400
  19.         s16 cur_step = 0;
  20.         u8 res = 0;
  21.         
  22.         if(cur_motor_pos==MOTOR_POS_CLEAN)
  23.                 return 0;
  24.         
  25.         while(cnt--)
  26.         {
  27.                 if(cur_step==0)
  28.                         cur_step = SHAKE_STEP;
  29.                 else if(cur_step>0)
  30.                         cur_step = SHAKE_STEP*-2;
  31.                 else
  32.                         cur_step = SHAKE_STEP*2;
  33.                 if(is_x)
  34.                 {
  35.                         motor_set_dir((cur_step<0?MOTOR_DIR_FORWARD:MOTOR_DIR_BACKWARD),MOTOR_DIR_SKIP,MOTOR_DIR_SKIP);
  36.                         motor_move((cur_step<0?-cur_step:cur_step),0,0);
  37.                 }else
  38.                 {
  39.                         motor_set_dir(MOTOR_DIR_SKIP,(cur_step<0?MOTOR_DIR_FORWARD:MOTOR_DIR_BACKWARD),MOTOR_DIR_SKIP);
  40.                         motor_move(0,(cur_step<0?-cur_step:cur_step),0);                        
  41.                 }
  42.                 sys_delay_ms(SHAKE_DELAY);
  43.                 if(func_code_scan()==quit_code)
  44.                 {
  45.                         res = 1;
  46.                         break;
  47.                 }        
  48.         }
  49.         
  50.         if(cur_step!=0)
  51.         {
  52.                 if(is_x)
  53.                 {
  54.                         motor_set_dir((cur_step<0?MOTOR_DIR_BACKWARD:MOTOR_DIR_FORWARD),MOTOR_DIR_SKIP,MOTOR_DIR_SKIP);
  55.                         motor_move(SHAKE_STEP,0,0);
  56.                 }else
  57.                 {
  58.                         motor_set_dir(MOTOR_DIR_SKIP,(cur_step<0?MOTOR_DIR_BACKWARD:MOTOR_DIR_FORWARD),MOTOR_DIR_SKIP);
  59.                         motor_move(0,SHAKE_STEP,0);                        
  60.                 }
  61.                 sys_delay_ms(SHAKE_DELAY);
  62.         }
  63.         
  64.         return res;
  65. }






  66. u8 base_shake(u16 cnt,u16 quit_code)
  67. {
  68.         if(base_shake_x_or_y(1,cnt,quit_code))
  69.                 return 1;
  70.         if(base_shake_x_or_y(0,cnt,quit_code))
  71.                 return 2;
  72.         
  73.         return 0;
  74. }






  75. u8 base_clean(u16 clean_time, u16 quit_code)
  76. {
  77.         #define FULL_TIME                        (sys_params.full_time)
  78.         #define EMPTY_TIME                (FULL_TIME+25)
  79.         #define BASE_UNIT                        200
  80.         u8 res = 0;
  81.         u8 time;
  82.         
  83.         


  84.         motor_select_sample(MOTOR_POS_CLEAN);
  85.         
  86.         WASTE_PUMP_OFF();
  87.         WATER_PUMP_ON();
  88.         time = FULL_TIME;
  89.         while(time--)
  90.         {
  91.                 sys_delay_ms(BASE_UNIT);
  92.                 if(func_code_scan()==quit_code)
  93.                 {
  94.                         res = 1;
  95.                         break;
  96.                 }
  97.         }
  98.         


  99.         if(clean_time)
  100.         {
  101.                 WASTE_PUMP_ON();
  102.                 while(clean_time--)
  103.                 {
  104.                         sys_delay_ms(1000);
  105.                         if(func_code_scan()==quit_code)
  106.                         {
  107.                                 res = 1;
  108.                                 break;
  109.                         }
  110.                 }               
  111.         }
  112.         


  113.         WASTE_PUMP_ON();
  114.         WATER_PUMP_OFF();
  115.         time = EMPTY_TIME;
  116.         while(time--)
  117.         {
  118.                 sys_delay_ms(BASE_UNIT);
  119.                 if(func_code_scan()==quit_code)
  120.                         res = 3;
  121.         }               
  122.         WASTE_PUMP_OFF();


  123.         if(res==0)
  124.         {
  125.                 test_update_sta(WORK_STA_AIR_DRY);
  126.                 res = base_air_dry(quit_code);
  127.         }
  128.         
  129.         return res;
  130. }






  131. u8 base_air_dry(u16 quit_code)
  132. {
  133.         #define AIR_DRY_TIME        (sys_params.air_dry_time)
  134.         u8 res = 0;
  135.         u8 sec;
  136.         
  137.         AIR_PUMP_ON();
  138.         sec = AIR_DRY_TIME;
  139.         while(sec--)
  140.         {
  141.                 sys_delay_ms(1000);
  142.                 if(func_code_scan()==quit_code)
  143.                 {
  144.                         res = 1;
  145.                         break;
  146.                 }
  147.         }        
  148.         AIR_PUMP_OFF();
  149.         
  150.         return res;
  151. }






  152. u8 base_select_sample(u8 pos,u8 is_clean,u16 quit_code)
  153. {


  154.         if(is_clean)
  155.         {
  156.                 test_update_sta(WORK_STA_CLEAN);
  157.                 if(is_testing)
  158.                 {
  159.                         work_sta = WORK_STA_TEST_STEP_1;
  160.                         if(test_upload_data())
  161.                                 return 1;
  162.                 }
  163.                 if(base_clean(BASE_CLEAN_TIME_DEF, quit_code))
  164.                         return 1;
  165.         }
  166.         if(is_testing)
  167.         {
  168.                 work_sta = WORK_STA_TEST_STEP_2;
  169.                 if(test_upload_data())
  170.                         return 1;
  171.         }        
  172.         
  173.         test_update_sta(WORK_STA_MOVE);
  174.         motor_select_sample(pos);
  175.         if(func_code_scan()==quit_code)
  176.                 return 2;


  177.         test_update_sta(WORK_STA_SHAKE);
  178.         if(base_shake(BASE_SHAKE_CNT_DEF,quit_code))
  179.                 return 3;
  180.         if(func_code_scan()==quit_code)
  181.                 return 4;        
  182.         
  183.         return 0;
  184. }


  185. 测试相关的代码

  186. bit is_complete_tip = 0;
  187. u16 complete_tip_time = 0;
  188. u8 cur_bottle_no = 0;
  189. u8 cur_completed_num = 0;
  190. u8 total_sample_num = NUM_OF_GROUP_DEF;
  191. u8 cur_work_sta = WORK_STA_IDLE;
  192. u8 last_result[LAST_RESULT_MAX_LEN] = {"--------\0\0"};
  193. u8 is_testing = 0;
  194. u8 is_normal_completed = 0;

  195. u8 test_make(u16 quit_code);

  196. //开始测试
  197. void test_start(u16 quit_code)
  198. {
  199.         u16 val;
  200.         
  201.         is_testing = 1;
  202.         is_complete_tip = 0;
  203.         cur_work_sta = WORK_STA_CLEAN;
  204.         cur_completed_num = 0;
  205.         cur_bottle_no = start_bottle_no;
  206.         score = SCORE_UNKNOW;
  207.         val = 1;
  208.         sys_write_vp(MAIN_WIN_START_BTN_VP,(u8*)&val,1);
  209.         main_win_update();
  210.         
  211.         
  212.         is_normal_completed = !test_make(quit_code);
  213.         if(is_normal_completed)
  214.         {
  215.                 test_update_sta(WORK_STA_CLEAN);
  216.                 base_clean(BASE_CLEAN_TIME_DEF, quit_code);
  217.         }
  218.         motor_select_sample(MOTOR_POS_PROTECT);
  219.         
  220.         
  221.         cur_work_sta = (is_normal_completed?WORK_STA_ALL_COMPLETED:WORK_STA_IDLE);
  222.         cur_bottle_no = 0;
  223.         val = 0;
  224.         sys_write_vp(MAIN_WIN_START_BTN_VP,(u8*)&val,1);
  225.         main_win_update();
  226.         if(is_normal_completed)
  227.         {
  228.                 is_complete_tip = 1;
  229.                 complete_tip_time = COMPLETE_TIP_MAX_TIME;
  230.                 sys_goto_win(WIN_ID_MAIN);
  231.                 sys_delay_ms(100);
  232.                 sys_click_pos(2,13);
  233.         }
  234.         is_testing = 0;
  235.         is_stable = 0;
  236.         check_stable_tick = 0;
  237.         val = 0;
  238.         sys_write_vp(BTN_VAL_ADDR,(u8*)&val,1);
  239.         work_sta = WORK_STA_TEST_STEP_COMPLETED;
  240.         test_upload_data();
  241. }


  242. //测试流程
  243. u8 test_make(u16 quit_code)
  244. {
  245.         u8 pos;
  246.         u8 offset;
  247.         float sum = 0;
  248.         float max = -999999;
  249.         float min = 999999;
  250.         u8 index = 0;
  251.         u8 end_pos;
  252.         
  253.         end_pos = total_sample_num+start_bottle_no-1;
  254.         for(pos=(start_bottle_no-1);pos<end_pos;pos++)
  255.         {
  256.                
  257.                 if(base_select_sample(pos,!(is_group&&(index%num_of_group)),quit_code))
  258.                         return 1;
  259.                
  260.                 cur_work_sta = WORK_STA_ANALYSIS;
  261.                 main_win_update();
  262.                 if(is_testing)
  263.                 {
  264.                         work_sta = WORK_STA_TEST_STEP_3;
  265.                         if(test_upload_data())
  266.                                 return 1;
  267.                 }
  268.                 check_stable_tick = 1;
  269.                 is_stable = 0;
  270.                 stable_val = 999999;
  271.                 while(1)
  272.                 {
  273.                         if(is_stable)
  274.                                 break;
  275.                         if(func_code_scan()==quit_code)
  276.                                 return 2;
  277.                 }
  278.                
  279.                 score = SCORE_UNKNOW;
  280.                 memset(last_result,0,LAST_RESULT_MAX_LEN);
  281.                 sprintf(last_result,"%.3f",cur_ph);
  282.                 if(is_group&&(invalid_num_of_group<num_of_group))
  283.                 {
  284.                         offset = index%num_of_group;
  285.                         if(offset>=invalid_num_of_group)
  286.                         {
  287.                                 sum += cur_val;//对有效点累加求和
  288.                                 if(cur_val>max)
  289.                                         max = cur_val;
  290.                                 if(cur_val<min)
  291.                                         min = cur_val;
  292.                         }
  293.                         if((offset+1)==num_of_group)
  294.                         {
  295.                                 sum /= (num_of_group-invalid_num_of_group);
  296.                                 score = ((max-min)<valid_range_of_group?SCORE_YES:SCORE_NO);
  297.                                 sum = 0;
  298.                                 max = -999999;
  299.                                 min = 999999;
  300.                         }               
  301.                 }
  302.                 cur_completed_num++;
  303.                 if(is_testing)
  304.                 {
  305.                         work_sta = WORK_STA_TEST_STEP_4;
  306.                         if(test_upload_data())
  307.                                 return 1;
  308.                 }
  309.                 cur_bottle_no++;
  310.                 if(cur_bottle_no>end_pos)
  311.                         cur_bottle_no = 0;
  312.                 main_win_update();
  313.                 index++;
  314.         }
  315.         
  316.         return 0;
  317. }</font>
复制代码


四、视频演示效果



备注说明:如需源码,请参考此链接:http://inforum.dwin.com.cn:20080/forum.php?mod=viewthread&tid=9915&_dsign=bb2eff7f






本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

发表于 2024-6-9 14:44:13 | 显示全部楼层
回复

使用道具 举报

0

主题

694

回帖

4104

积分

论坛元老

Rank: 8Rank: 8

积分
4104
发表于 2024-6-9 20:34:45 | 显示全部楼层
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|Archiver|手机版|小黑屋|迪文科技论坛 ( 京ICP备05033781号-1 )

GMT+8, 2024-11-22 05:04 , Processed in 0.108890 second(s), 22 queries .

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表