PullupDev/src/motocontrol.cpp
pxzleo 96df77d785 1.合并小田新的文件,加入相机云台控制
2.修改钩子控制部分
3.反馈给服务器钩子文字状态
2023-06-19 15:26:16 +08:00

543 lines
14 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "Arduino.h"
#include "motocontrol.h"
#include "moto.h"
#include <ESP32Servo.h>
#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();
}
String Motocontrol::gethooktatus_str()
{
String hookstatusstr="未知";
switch (_hooksstatus)
{
case HS_UnInit:
hookstatusstr="未初始化";
break;
case HS_Down:
hookstatusstr="放钩";
break;
case HS_DownSlow:
hookstatusstr="慢速放钩";
break;
case HS_WaitUnhook:
hookstatusstr="等待脱钩";
break;
case HS_Up:
hookstatusstr="回收";
break;
case HS_InStore:
hookstatusstr="入仓中";
break;
case HS_Locked:
hookstatusstr="已锁定";
break;
case HS_Stop:
hookstatusstr="停止";
break;
default:
hookstatusstr="未知";
break;
}
return hookstatusstr;
}
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 weight<min 40 times :%d \n", _pullweight);
_controlstatus.is_havegoods = false;
}
}
else
{
_controlstatus.is_havegoods = true;
_notweightcount = 0;
}
}
void Motocontrol::lockservo() // 锁定舵机
{
printf("start_lockservo\n");
_servotatus = SS_WaitMotoStop;
_tm_servotatus = millis();
}
void Motocontrol::unlockservo() // 解锁舵机
{
printf("unlockservo\n");
// 解锁操作
_lockservo->write(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;
if ((_hooksstatus != HS_UnInit) || (_hooksstatus != HS_Stop))
{
_hooksstatus_prv = _hooksstatus;
_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;
moto_measure_t mf = _moto_dji.getmotoinfo();
_hook_currlen = _curr_length;
switch (_hooksstatus)
{
// 正在下放货物
case HookStatus::HS_Down:
{
// 如果没有货物--开始回收
if (!_controlstatus.is_havegoods)
{
printf("HS_Down not havegoods wait unhook \n");
goodsstartup();
break;
}
if ((_goods_down_target_cnt != 0) && (mf.output_round_cnt > _goods_down_target_cnt))
{
_hooksstatus = HS_DownSlow;
_moto_dji.settime_acc(500);
set_hook_speed(SPEED_HOOK_SLOW);
}
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_dji.settime_acc(1000);
set_hook_speed(-SPEED_HOOK_UP);
_hooksstatus = HS_Up;
_controlstatus.motostatus = MS_Up;
}
break;
}
// 开始收回
case HookStatus::HS_Up:
{
// 会自动设置HS_Up状态
break;
}
case HookStatus::HS_InStore:
{
// 会自动设置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)
{
// 入仓时会自动设置速度,原速度不可用
if (!_controlstatus.is_instore)
_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))
float instlen;
if (_controlstatus.is_havegoods)
instlen = INSTORE_LENGTH_MIN_GOODS + abs(mf.output_speed_rpm) * INSTORE_LENGTH_SPEED;
else
instlen = INSTORE_LENGTH_MIN_NONE + abs(mf.output_speed_rpm) * INSTORE_LENGTH_SPEED;
if ((_curr_length < instlen) && (_controlstatus.motostatus == MotoStatus::MS_Up))
{
if (!_controlstatus.is_instore)
{
_moto_dji.settime_acc(500);
set_hook_speed(-SPEED_INSTORE);
_controlstatus.is_instore = true;
_hooksstatus = HS_InStore;
printf("begin instore currlen:%.2f,instorelen:%.2f,speed:%.2f \n", _curr_length, instlen, mf.output_speed_rpm);
}
}
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::set_hook_speed(float hooksspeed)
{
_goods_speed = hooksspeed;
_runspeed = hooksspeed;
_moto_dji.setspeedtarget(hooksspeed);
}
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_goodsdownresume()
{
if (!_autogoodsdown) return;
if (_hooksstatus == HS_Stop)
{
_runspeed = _goods_speed;
if (_hooksstatus_prv == HS_Up)
_controlstatus.motostatus = MS_Up;
if (_hooksstatus_prv == HS_InStore)
{
_controlstatus.motostatus = MS_Up;
_runspeed = -SPEED_INSTORE;
}
_hooksstatus = _hooksstatus_prv;
_moto_dji.settime_acc(1000);
unlockservo(); // 打开舵机
// _moto_dji.setspeedtarget(_goods_speed);
}
}
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;
// 长度=0直接中慢速下降
if (length == 0.0)
{
_goods_down_target_cnt = 0;
setspeed(SPEED_HOOK_CHECK);
_goods_speed = SPEED_HOOK_CHECK;
}
else
{
_goods_down_start_cnt = _moto_dji.getmotoinfo().output_round_cnt;
_goods_down_target_cnt = _goods_down_start_cnt + length / WHEEL_PERIMETER;
setspeed(SPEED_HOOK_FAST, TM_ACC_HS);
_goods_speed = SPEED_HOOK_FAST;
}
moto_run(MS_Down);
}
// 按指定速度收放线 放线为+,收线为- 单位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);
}