目录
之前买了一批5路灰度传感器,想用这传感器进行循迹,无奈网上和官方的资料提供的还是比较少,这里还是做一下当初的学习记录。
STM32RCT6主控,5路灰度寻迹,超声波HC_SR04中断式测距,蓝牙模块HC_08通信,AS4950电机驱动芯片,减缓了MPU6050零漂问题,PID丝滑_哔哩哔哩_bilibili
这是某宝上买的5路灰度传感器,价格稍微有点贵,50多块一个。当然,一分钱一分货,这个模块可以用小螺丝刀来调节传感器上面的旋钮,通过这个旋钮来调节灵敏度,这个灵敏度调节好了的话可以识别黑白循迹、红白循迹。所以还是比较值得的。
对于这款5路数字灰度传感器来说。识别到黑线,传回来的数字量就是0,识别到白色,传回来的数字量就是1。
博主想着用这5路的中间三路来巡线,用最左和最右端的传感器用来识别十字或者丁字路口,巡线时,加入PID算法,遇到十字或者丁字路口就用最左和最右的传感器来识别,识别到了之后,我们就可以搭配MPU6050进行转90°弯了。
其中 sensor_bias 是根据中间三路传感器和黑线的相对位置来估计出的误差(如果你要问我怎么得来的,其实这个数据大差不差就行,它只是为PID服务的一个变量罢了,甚至你可以把62.5改成50,最后只要调好PID三个参数,达到的效果是一样的),这里的decide类似于状态机的信号,我令decide为6的时候,也就是小车跑出了黑线,小车停止。
#include "sensor.h"
#include "stm32f10x.h"
#include "move.h"
#include "motor.h"
#include "FSM.h"
//STEER4 --> PA11 --> R2 红线
//STEER3 --> PC9 --> R1 橘线
// --> PB4 --> M0 黄线
//STEER1 --> PA6 --> L1 绿线
//ENCODE1_A --> PB5 --> L2 棕线
float Kp_sensor = 8.134, Ki_sensor = 0.021, Kd_sensor = 2.36;//pid弯道参数参数
float sensor_bias = 0;
float sensor_bias_last = 0;
float P = 0, I = 0, D = 0, PID_value = 0; //pid直道参数
int decide;
unsigned char move_flag;
extern unsigned char FSM_state;
void sensor_Init()
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//开启C时钟 PC9
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//这句话其实可以不用,在使用输入功能时,不需要配置频率
GPIO_Init(GPIOC, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//开启A时钟 PA11 PA6
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11|GPIO_Pin_6;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_PinRemapConfig(GPIO_Remap_SWJ_NoJTRST, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//开启B时钟 PB4 PB5
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5;
GPIO_Init(GPIOB, &GPIO_InitStructure);
}
unsigned char times;
extern unsigned char FSM_hc08;
unsigned char back_flag;
unsigned char one_time;
unsigned char one_flag;
unsigned char channel_num;//channel的存在导致发送2号通道的时候只会进入一次
void sensor_read()
{
if((L2 == 1)&&(L1 == 1)&&(M0 == 1)&&(R1 == 0))// 1 1 1 0
{
if(one_time == 0)
{
if(FSM_hc08 == Channel_1)
{
FSM_state = Turn_lift_state;//跳出循环,将PID分别清零。
one_time++;
P = 0;I = 0; D = 0;
}
else if(FSM_hc08 == Channel_2)
{
if(one_flag == 0)
{
channel_num++;
one_flag = 1;
}
if(channel_num == 2)
{
FSM_state = stay2_state;//跳出循环,将PID分别清零。
one_time++;
P = 0;I = 0; D = 0;
}
}
}
}
else if((L1 == 0)&&(M0 == 1)&&(R1 == 0))// 0 1 0
{
sensor_bias = 0;decide = 3;one_flag = 0;//积分项清零
}
else if((L1 == 1)&&(M0 == 1)&&(R1 == 0))// 1 1 0
{
sensor_bias = -62.5;decide = 2;
}
else if((L1 == 0)&&(M0 == 1)&&(R1 == 1))// 0 1 1
{
sensor_bias = 62.5;decide = 2;
}
else if((L1 == 1)&&(M0 == 0)&&(R1 == 0))// 1 0 0
{
sensor_bias = -125;decide = 4;
}
else if((L1 == 0)&&(M0 == 0)&&(R1 == 1))// 0 0 1
{
sensor_bias = 62.5;decide = 4;
}
else if((L1 == 0)&&(M0 == 0)&&(R1 == 0))// 0 0 0
{
decide = 6;
}
else if((L1 == 1)&&(M0 == 1)&&(R1 == 1))// 1 1 1
{
decide = 6;FSM_state = Judge_state; //如果读取到了整条黑线,那么就进入下一状态
if(back_flag == 1)
{
FSM_state = Back_state;
back_flag = 0;
} //第一次识别到全黑线为小车停止线。第二次识别到,代表小车即将回归循迹
}
}
void Sensor_pid()
{
if(decide<=5)
{
P = sensor_bias;
I = I + sensor_bias;
D = sensor_bias-sensor_bias_last;
PID_value = Kp_sensor*P + Ki_sensor*I + Kd_sensor*D;
sensor_bias_last = sensor_bias;
//对积分值设置一个限制,防止积分值超标
if(I >=3500)I = 3500;
if(I <= -3500)I = -3500;
PWM_value_R = 2099 - (int)PID_value;
PWM_value_L = 2099 + (int)PID_value;//当线在左,左轮要慢,右轮要快,左轮要加,右轮要减,但这里的偏差是负值
Motor3_forward(PWM_value_R);
Motor4_forward(PWM_value_L);
//4 --> 右电机
//3 --> 左电机
}
else{
Move_stop();
}
}
对应的头文件部分
#ifndef __SENSOR_H
#define __SENSOR_H
//STEER4 --> PA11 --> R2 绿线
//STEER3 --> PC9 --> R1 黄线
// B --> PB6 --> M0 橘线
//STEER1 --> PA6 --> L1 红线
// A --> PB7 --> L2 白线
// 灰度传感器,当传感器识别到黑线的时候,输出为1,其余时刻输出为0
// 所以在这里我们要使用下拉输入
#define L2 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_5)
#define L1 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_6)
#define M0 GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4)
#define R1 GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_9)
#define R2 GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_11)
void sensor_Init(void);
void sensor_read(void);
void Sensor_pid(void);
#endif
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。问题1)我想知道rubyonrails是否有功能类似于primefaces的gem。我问的原因是如果您使用primefaces(http://www.primefaces.org/showcase-labs/ui/home.jsf),开发人员无需担心javascript或jquery的东西。据我所知,JSF是一个规范,基于规范的各种可用实现,prim
本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01 客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02 数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L
我使用的是最新版本的Chrome(32.0.1700.107)和Chrome驱动程序(V2.8)。但是当我在Ruby中使用以下代码运行示例测试时:require'selenium-webdriver'WAIT=Selenium::WebDriver::Wait.new(timeout:100)$driver=Selenium::WebDriver.for:chrome$driver.manage.window.maximize$driver.navigate.to'https://www.google.co.in'defapps_hoverele_hover=$driver.find_
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭9年前。多年来,我一直在使用多种语言进行编程,并且认为自己总体上相当擅长。但是,我从未编写过任何自动化测试:没有单元测试,没有TDD,没有BDD,什么都没有。我已经尝试开始为我的项目编写适当的测试套件。我可以看到在进行任何更改后能够自动测试项目中所有代码的理论值(value)。我可以看到像RSpec和Mocha这样的测试框架应该如何使设置和运行所述测试变得相当容易
如果我在功能规范中调用url_for,它会返回一个以http://www.example.com/开头的绝对URL.Capybara会很乐意尝试加载该站点上的页面,但这与我的应用程序无关。以下是重现该问题的最少步骤:从这个Gemfile开始:source'https://rubygems.org'gem"sqlite3"gem"jquery-rails"gem"draper"gem"rails",'4.1.0'gem"therubyracer"gem"uglifier"gem"rspec-rails"gem"capybara"gem"poltergeist"gem"launchy"运行
在笔者前面有一篇文章《驱动开发:断链隐藏驱动程序自身》通过摘除驱动的链表实现了断链隐藏自身的目的,但此方法恢复时会触发PG会蓝屏,偶然间在网上找到了一个作者介绍的一种方法,觉得有必要详细分析一下他是如何实现的进程隐藏的,总体来说作者的思路是最终寻找到MiProcessLoaderEntry的入口地址,该函数的作用是将驱动信息加入链表和移除链表,运用这个函数即可动态处理驱动的添加和移除问题。MiProcessLoaderEntry(pDriverObject->DriverSection,1)添加MiProcessLoaderEntry(pDriverObject->DriverSection,
目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方
有道无术,术尚可求,有术无道,止于术。本系列SpringBoot版本3.0.4本系列SpringSecurity版本6.0.2本系列SpringAuthorizationServer版本1.0.2源码地址:https://gitee.com/pearl-organization/study-spring-security-demo文章目录前言1.OAuth2AuthorizationServerMetadataEndpointFilter2.OAuth2AuthorizationEndpointFilter3.OidcProviderConfigurationEndpointFilter4.N