目录
问题1:摄像仪雨刮除尘间隔周期以两次除尘触发时的间隔时间的修复
问题1:摄像仪雨刮除尘间隔周期以两次除尘触发时的间隔时间的修复
案例:原先雨刮前后两次的间隔周期定义为第一次开始执行到第二次开始执行的时间,如下图:
设置web界面:
但这样的弊端是随着设置雨刮执行时长和次数的增加,会导致间隔周期越来越短,不符合大众常识。因此,在重新定义雨刮的间隔时长为前一次执行后的结束时间到该次的执行开始时间,但在按照数学公式修改相应代码如下时,会随着设置雨刮的执行时长和次数增加而出现较大的误差,为此作出的实验统计如下:
如设置执行时长为4s,执行次数3次,间隔时间1分钟时,误差为0.5s可忽略不计,当设置执行时长为10s,执行次数3次,间隔时间10分钟时,误差会达到10s,
原因分析:
1、新老固件不能通用,旧雨刮刷的一个来回时间为2s,新雨刮的一个来回时间为4s,同样的参数,它们运行的时间跟设置的参数出入很大,新雨刮克服摩擦力耗时多些,新固件需重新计算步距角,减速比来适配来减少误差,这里通过查询相关电机资料来明确了相应的步距角与转速比:
解决方案的相关代码1:
//由于 *一个脉冲* *输出轴* 转0.08789度(电机实转0.08789*64=5.625度),即步进角为5.625度。
//则转完A-B-C-D为 *8个脉冲* ,即0.08789*8=0.70312度。若称A-B-C-D为一个周期,则j为需要的转完angle角度所需的周期数。
//除数计算公式:1.先把步距角转化为输出轴度数(除以电机参数里的转速比)
//2.在乘以8
void Motorcw_angle(int angle,int speed)//电机1逆时针
{
int i,j;
j=(int)(angle/0.70312);
for(i=0;i<j;i++)
{
Motorcw(speed);
}
}
电机需要校准零点的逻辑是因为在实际应用中,电机可能会因为各种原因产生偏移,导致其输出的转矩和位置不准确。通过校准零点,可以使电机的输出更加稳定,提高控制精度。
2、一次除尘时间实际为3.76秒,而我们在web界面看到的是4s,多出来的累计误差本身就会随着设置执行时间和间隔时间的增加而增加。
3、第1次除尘结束时间与第2次除尘开始的间隔时间并不是设置的1分钟,而是50s。原因是旧雨刮的voip.voip_info.keep_time每次一来一回的执行时间是2s,3次就是6s,但是新雨刮实际运行所需要的时间是16s,也就是说系统计数时会认为这10s我等了,但是你认为少的10实际上是被雨刮拿来用掉了,所以我们看到的是50s,而不是1分钟。印次我们只需根据实际现象把误差加上即可。
解决方法:
在设置雨刮除尘间隔时间为1分钟时,整机除尘间隔周期应为第一个周期的结束到第二个周期的开始的间隔时间,而不是两次除尘触发时的间隔时间,定位到关键代码如下:
uint16_t Interval_minute = 2 ;
uint32_t motor_time = 360*(uint32_t)Interval_minute;
//将电机的运行时间乘以360,假设每分钟转360度
else if(voip.voip_info.mode == 1)
{
if(!run_flag) //运行模式是否为假(既未运行)
{
//判断是否到了需要控制电机运行的时间 先判断当前的RTC计数器值,在减去电机运行的时间
if((RTC_GetCounter() - motor_time) >= (60 *voip.voip_info.Interval_time + voip.voip_info.count *voip.voip_info.keep_time + 10)) //检查当前时间与motor_time的差值是否大于等于60 * voip.voip_info.Interval_time
motor_control(RunOneCycle);
motor_time = RTC_GetCounter(); //更新电机运行时间,作为判断是否需要控制电机运行时间的依据
}
}
if(voip.voip_info.Interval_time == 0) run_flag = 1;
else run_flag = 0;
}
rt_thread_mdelay(100);
}
解决思路:
if((RTC_GetCounter() - motor_time) >= (60 *voip.voip_info.Interval_time + voip.voip_info.count *voip.voip_info.keep_time + 10))
//检查当前时间与motor_time的差值是否大于等于60
1.原先是没有红色字体,两次间隔除尘周期为m,为第1次开始除尘到第2次开始除尘的时间,实际上想要的除尘周期为第1次除尘结束时间与第2次除尘开始的间隔时间,第2次除尘结束时间与第3次除尘开始的间隔时间,第3次除尘结束时间与第4次除尘开始的间隔时间
2.于是在原先代码上增加:+ voip.voip_info.count *voip.voip_info.keep_time
发现第1次除尘结束时间与第2次除尘开始的间隔时间并不是1分钟,而是50s
根据代码和图形分析原因:
是雨刮的voip.voip_info.keep_time每次一来一回的执行时间是2s,3次就是6s,但是实际运行所需要的时间是16s,也就是说系统计数时会认为这10s我等了,但是你认为少的10实际上是被雨刮拿来用掉了,所以我们看到的是50s,而不是1分钟。只需要在+ 10即可。
{
motor_control(RunOneCycle);
motor_time = RTC_GetCounter();
//更新电机运行时间,作为判断是否需要控制电机运行时间的依据
}
问题2:点击除尘保存配置时,雨刷应该先进行一次除尘操作
static void motor_thread_entry(void *parameter)
{
static bool RunFlag=0;//?????????
unsigned char ii=0;//???????????
static voip_t voip = {0};
static uint8_t run_flag = 0;
uint32_t motor_time = 360*(uint32_t)Interval_minute; //将电机的运行时间乘以360,假设每分钟转360度
Flag=0;
// IWDG_Configuration();
rt_kprintf("\r\n -------MotorControl-----\r\n");
motor_time = RTC_GetCounter(); //得到实时时钟计数器的值
while (1)
{
/*
* StopFlag=0x00; ????
* StopFlag=0x55; ??
*/
// IWDG_ReloadCounter(); /*ι?????????????*/
if(update_voip(&voip) == RT_EOK)//????voip_info
{
run_flag = 0;
start_run = 1;
}
if(voip.voip_info.mode == 0)//DO????
{
// rt_kprintf("%d \n",CameraDo);
if(!run_flag)
{
if(GetCameraInfo())
{
motor_control(RunOneCycle);
}
if(!GetCameraInfo())
{
SystemFlag=0x01;
if(RunFlag==1)
{
RunFlag=0;
MotorStop();
rt_thread_mdelay(5000);
Motor_ZeroCalibration();
}
}
}
if(voip.voip_info.Interval_time == 0) run_flag = 1;
else run_flag = 0;
motor_time = RTC_GetCounter();
}
else if(voip.voip_info.mode == 1)
{
if(!run_flag) //运行模式是否为假(既未运行)
{
static int start_run = 1;
//485??????ò??? 判断是否到了需要控制电机运行的时间 先判断当前的RTC计数器值,在减去电机运行的时间
if((RTC_GetCounter() - motor_time) >= (60 *voip.voip_info.Interval_time + voip.voip_info.count *voip.voip_info.keep_time + 10) || start_run) //检查当前时间与motor_time的差值是否大于等于60 * voip.voip_info.Interval_time
motor_control(RunOneCycle);
motor_time = RTC_GetCounter(); //更新电机运行时间,作为判断是否需要控制电机运行时间的依据
start_run = 0;
}
}
if(voip.voip_info.Interval_time == 0)
{
run_flag = 1;
}
else run_flag = 0;
}
rt_thread_mdelay(100);
}
修改代码思路
思路:
if(!run_flag) //运行模式是否为假(既未运行)
{
static int start_run = 1; //先定义一个start_run开始运行的静态变量置为1,当运行模式为485时,条件状态加一个或的条件,当start_run = 1时,电机开始按照命令转3圈,转完以后立马start_run = 0;
if((RTC_GetCounter() - motor_time) >= (60 *voip.voip_info.Interval_time + voip.voip_info.count *voip.voip_info.keep_time + 10) || start_run) //检查当前时间与motor_time的差值是否大于等于60 * voip.voip_info.Interval_time
motor_control(RunOneCycle);
motor_time = RTC_GetCounter(); //更新电机运行时间,作为判断是否需要控制电机运行时间的依据
start_run = 0;
}
}
什么时候置为0?
if(update_voip(&voip) == RT_EOK)//在下一次更新保存参数时,start_run = 1;
{
run_flag = 0;
start_run = 1;
}
问题3:点击除尘保存配置时,雨刷不会进行复位操作
if(update_voip(&voip) == RT_EOK)//在下一次更新保存参数时,start_run = 1;
{
run_flag = 0;
motor_control(RunOneCycle); //相当于一个复位操作
//start_run = 1;
}
程序运行思路:当间隔时间设置为0,标志位run_flag置于1,这个时候不会执行任何485还是D0模式的逻辑,只会在更新参数时,走一圈,这个时候run_flag = 0;就会走间隔时间的逻辑,不停的转转转
if(voip.voip_info.Interval_time == 0) run_flag = 1;
else run_flag = 0;
其实我觉得标志位run_flag可以去掉,简化下代码
摄像仪项目总结
在优化摄像仪雨刮运行状态时,应注意观察实际现象,考虑累计误差的影响,并及时对误差较大时作出相应的纠正。
ps:怎么看测试的时间对不对
1. 执行时长2秒看每次一个来回是不是4s,3个来回刮不等待
2. 执行时长设置10s,看每次一个来回是不是4s,然后在等6s,在进行刮
3.第一次结束到第二次开始的间隔周期是不是为设置的1分钟,2分钟
4.主要看下2s和10s
ps:在做摄像仪项目时参考的一些比较好的文章,分享如下
参考文章
HuskyLens人工智能摄像头_huskylens摄像头-CSDN博客
使用RT-Thread 小记:如何使用日志LOG函数_#define dbg_log 0-CSDN博客
【STM32】STM32之电量采集_stm32获取电池电量-CSDN博客
【工具推荐】代码编辑器 vscode 使用篇(技巧 一些好用的用法)
zwdfk-prog/canopen-switches-modbus-gateway: STM32F429 ,rtt操作系统搭载canopen转modbus程序 (github.com)
TortoiseSVN安装和使用_tortoisesvn安装教程-CSDN博客
rt-thread 使用libmodbus-rtu库_rtt1.2.2是否支持libmodbus-CSDN博客【stm32f103-IWDG-独立看门狗】_stm32f103看门狗-CSDN博客
modbus的使用说明——个人使用心得_modbus数据类型16位和32位-CSDN博客
STM32+RS485+Modbus-RTU(主机模式+从机模式)-标准库/HAL库开发_stm32modbus主机-CSDN博客
移植RT-thread Nano完成一个 modbus接口的温湿度Slave设备,让上位机PC通过modbus协议获取温湿度_计算机modbus rtu控制温度-CSDN博客