#include "Arduino.h" #include "motocontrol.h" #include "moto.h" #include #include "config.h" #define DEBUG_OUT false Motocontrol::Motocontrol() { _controlstatus.is_instore = false; _controlstatus.is_setzero = false; _controlstatus.is_overweight = false; _controlstatus.zero_cnt = 0; _controlstatus.motostatus = MotoStatus::MS_Stop; _controlstatus.speed_targe = SPEED_BTN_SLOW; _check_targetlength = false; _pullweight = 0; _curr_length = 0.0; _hooksstatus = HS_UnInit; _weightalign = false; _overweightcount = 0; _notweightcount = 0; _autogoodsdown = false; _servotatus = SS_ServoUnLocked; // 停止状态,为了防止舵机堵转,和延时关闭电机需要一个停止状态机 _unblocktimes = 0; } Motocontrol::~Motocontrol() { } bool Motocontrol::init(Servo *lockservo) // 初始化 { _lockservo = lockservo; // 不管堵转问题,马上会执行其他初始化让舵机介绍 _lockservo->write(SERVO_LOCKPOS); _servotatus = SS_ServoLocked; return _moto_dji.init(); } void Motocontrol::setspeed(float motospeed,float acctime) // 设置速度 { _controlstatus.speed_targe = motospeed; _moto_dji.settime_acc(acctime); } void Motocontrol::setweight(int pullweight) // 设置重量 { _pullweight = pullweight; checkgoods(); } void Motocontrol::checkgoods() // 检测是否超重 { // 到顶部锁定状态,有向上的压力,重量不准,不能检测 if (_controlstatus.is_toplocked) return; // 检查是否超重 if (_pullweight > HOOK_WEIHT_MAX) { // 防止毛刺 _overweightcount++; if (_overweightcount > 40) _controlstatus.is_overweight = true; } else { _controlstatus.is_overweight = false; _overweightcount = 0; } // 检查是否有货物 if (_pullweight < HOOK_WEIHT_MIN) { // 防止毛刺 _notweightcount++; if (_notweightcount > 40) { // printf("goods weightwrite(SERVO_UNLOCKPOS); _moto_dji.setspeedtarget(-1.0f);//解锁时逆向慢速转动 _servotatus = SS_WaitUnLock; _tm_servotatus = millis(); _unblocktimes = 0; } void Motocontrol::stop(float acctime) // 停止 { printf("stop \n"); _moto_dji.settime_acc(acctime); _moto_dji.setspeedtarget(0.0f); _controlstatus.motostatus = MS_Stop; _hooksstatus = HS_Stop; lockservo(); } void Motocontrol::setlocked(bool locked) { if (locked) { stop(); setzero(); _hooksstatus = HS_Locked; _autogoodsdown = false; } _controlstatus.is_toplocked = locked; } void Motocontrol::setzero() // 设置0长度位置 { // 记录0长度位置--以后需要保存到falsh里面 _controlstatus.zero_cnt = getmotoinfo().output_round_cnt; _controlstatus.is_setzero = true; } int16_t Motocontrol::getlength() // 得到长度 { return 0; } // 检测是否挂有货物 void Motocontrol::goodsstartup() { _hooksstatus = HS_WaitUnhook; _tm_waitunhook = millis(); } // 重量传感器已经校准 void Motocontrol::weightalign(bool weightalign) { _weightalign = weightalign; } void Motocontrol::checkhookstatus() // 检查挂钩状态 { // 需要在自动放货物中 if (!_autogoodsdown) return; _hook_currlen = _curr_length; switch (_hooksstatus) { // 正在下放货物 case HookStatus::HS_Down: { // 如果没有货物--开始回收 if (!_controlstatus.is_havegoods) { printf("HS_Down not havegoods wait unhook \n"); goodsstartup(); break; } break; } case HookStatus::HS_Stop: { // 如果有长度目标 if ((_hook_targetlen > 0) && (_hook_targetlen <= HOOK_SLOWDOWN_LENGTH)) { printf("_hook_targetlen>0 \n"); // 如果停了就开始慢速 { printf("begin hook slow down \n"); // 慢速一直下放,直到货物卸下--没有重量 setspeed(SPEED_HOOK_SLOW); moto_run(MS_Down); _hooksstatus = HS_DownSlow; } } else { // 没有长度目标,如果停了并且货物还在,一般是线到最大了,所有开始回收 { printf("not settargetlen arrived wait unhook \n"); goodsstartup(); } } break; } case HookStatus::HS_DownSlow: { if (!_controlstatus.is_havegoods) { printf("HS_DownSlow not havegoods wait unhook \n"); goodsstartup(); } break; } case HookStatus::HS_WaitUnhook: { if ((millis() - _tm_waitunhook) > HOOK_UNHOOK_TIME) { printf("HS_WaitUnhook ok startup \n"); moto_run(MS_Stop); setspeed(SPEED_HOOK_UP); moto_run(MS_Up); } break; } case HookStatus::HS_Up: { // 会自动设置HS_InStore状态 break; } case HookStatus::HS_InStore: { // 如果到顶部,会触发setlocked,不用在这里设置 break; } } } // 检测舵机堵转---电流大或者角度不够,需要传感器 bool Motocontrol::checkservoblock() { return false; } void Motocontrol::checkmotostatus() // 检查电机状态,比如什么时候停 { moto_measure_t mf = _moto_dji.getmotoinfo(); // 停止状态---1防止舵机堵转,2延时关闭电机供电 switch (_servotatus) { case SS_WaitUnLock: //舵机解锁 { if ((millis() - _tm_servotatus) > TM_SERVOLOCK) { _moto_dji.setspeedtarget(_runspeed); _servotatus=SS_ServoUnLocked; } break; } //等待电机停止 case SS_WaitMotoStop: { if (abs(mf.speed_rpm)<3) { _lockservo->write(SERVO_LOCKPOS); _servotatus=SS_WaitServo; _tm_servotatus = millis(); } break; } // 等待舵机执行到位---------防止堵转,功能没有使用,采用硬件防堵转舵机 case SS_WaitServo: { // 舵机执行时间 if ((millis() - _tm_servotatus) > TM_SERVOLOCK) { // 检测堵转,没堵转直接关闭电机,否则打开舵机,让电机旋转一点再锁定--最多重复3次 if (!checkservoblock() || (_unblocktimes > 2)) { printf("SS not servoblock close moto \n"); _moto_dji.close(); _servotatus = SS_ServoLocked; } else // 堵转 { printf("SS servoblock unlock servo and turn moto \n"); _tm_servotatus = millis(); _servotatus = SS_WaitUnBlock; // 写一个不会堵转的位置 _lockservo->write(SERVO_BLOCKUNLOCKPOS); // 转一点电机角度 _moto_dji.setspeedtarget(SPEED_UNBLOCK); } } break; } case SS_WaitUnBlock: { if ((millis() - _tm_servotatus) > TM_UNBLOCK) { printf("SS lock servo \n"); // 继续锁定等待舵机检测 _lockservo->write(SERVO_LOCKPOS); _servotatus = SS_WaitServo; _tm_servotatus = millis(); _unblocktimes++; } break; } } // 已设置零点 if (_controlstatus.is_setzero) { // 总放线长度 _curr_length = abs(mf.output_round_cnt - _controlstatus.zero_cnt) * WHEEL_PERIMETER; // 不能超ROPE_MAXLENGTH if ((_curr_length > ROPE_MAXLENGTH) && (_controlstatus.motostatus == MS_Down)) stop(); // 开始入仓 if ((_curr_length < (INSTORE_LENGTH_MIN+(mf.output_speed_rpm*mf.output_speed_rpm)*INSTORE_LENGTH_SPEED)) && (_controlstatus.motostatus == MotoStatus::MS_Up)) { if (!_controlstatus.is_instore) { _moto_dji.setspeedtarget(-SPEED_INSTORE); _controlstatus.is_instore = true; _hooksstatus = HS_InStore; printf("begin instore \n"); } } else _controlstatus.is_instore = false; } if (_check_targetlength) // 有目标长度 { if (_controlstatus.motostatus == MS_Down) { if (mf.output_round_cnt > _target_cnt) { printf("stop--cnt:%.2f ,tar:%.2f\n", mf.output_round_cnt, _target_cnt); stop(1000);//缓慢停止 } } else if (_controlstatus.motostatus == MS_Up) { if (mf.output_round_cnt < _target_cnt) { printf("cnt:%.2f ,tar:%.2f\n", mf.output_round_cnt, _target_cnt); stop(1000);//缓慢停止 } } } } void Motocontrol::update() // 更新 { _moto_dji.update(); checkmotostatus(); checkhookstatus(); } void Motocontrol::direct_speed(float motospeed) // 直接控制电机--测试用 { _moto_dji.setspeedtarget(motospeed); } moto_measure_t Motocontrol::getmotoinfo() { return _moto_dji.getmotoinfo(); } control_status_t Motocontrol::getcontrolstatus() // 得到控制信息 { return _controlstatus; } void Motocontrol::moto_goodsdown(float length) { if (length < 0.0) { printf("length<0 fault\n"); return; } // 没设置零点 if (!_controlstatus.is_setzero) { printf("not lengthzero fault\n"); return; } if (!_weightalign) { printf("weight not align fault\n"); return; } // 没挂东西 if (!_controlstatus.is_havegoods) { printf("goods min fault:%d \n", _pullweight); return; } // 开始自动放货物状态 _autogoodsdown = true; _hook_targetlen = length; // 长度=0,直接中慢速下降, if (length == 0.0) { setspeed(SPEED_HOOK_CHECK); moto_run(MS_Down); } else if (length > HOOK_SLOWDOWN_LENGTH) // 长度大于慢速长度 { setspeed(SPEED_HOOK_FAST,TM_ACC_HS); moto_run(MS_Down, length - HOOK_SLOWDOWN_LENGTH); _hook_targetlen = HOOK_SLOWDOWN_LENGTH; } else { setspeed(SPEED_HOOK_SLOW); // 长度小于慢速长度 moto_run(MS_Down, length); } } // 按指定速度收放线 放线为+,收线为- 单位cm void Motocontrol::moto_run(MotoStatus updown, float length) { // 传入要stop,直接停 if (updown == MS_Stop) { stop(); return; } // 运动中暂时不管 if ((_controlstatus.motostatus == MS_Down) || (_controlstatus.motostatus == MS_Up)) { printf("motostatus is MS_Down\\MS_Up \n"); return; } // 没设置速度不转 if (_controlstatus.speed_targe == 0) { printf("not set speed_targe \n"); return; } if (updown == MS_Up) { if (_controlstatus.is_toplocked) { printf("is_toplocked return\n"); return; } if (_controlstatus.is_overweight) { printf("overweight fault :%d \n", _pullweight); return; } _hooksstatus = HS_Up; } else _hooksstatus = HS_Down; unlockservo(); _controlstatus.motostatus = updown; // 有长度限制 if (length != 0) { // 收需要负 if (updown == MotoStatus::MS_Up) length = -length; // 记录开始位置 _start_cnt = _moto_dji.getmotoinfo().output_round_cnt; _target_cnt = _start_cnt + length / WHEEL_PERIMETER; _check_targetlength = true; } else _check_targetlength = false; // 记录开始位置 float runspeed; if (updown == MotoStatus::MS_Down) runspeed = _controlstatus.speed_targe; else { // 如果没有设置零点,不能快速收线 if (!_controlstatus.is_setzero) _controlstatus.speed_targe = SPEED_BTN_SLOW; runspeed = -_controlstatus.speed_targe; } // 开始转 printf("run speed:%.0f,tarcnt:%.2f\n", runspeed, _target_cnt); _runspeed=runspeed; // _moto_dji.setspeedtarget(runspeed); }