2023.12.10汇报

比赛内容

伊戈尔杯

器件选型

1.红外循迹模块
受光线影响很大,需要反复调试
2.灰度循迹模块
受光线影响较大。
3.openmv
识别赛道黑点

通讯方式

检测高低电平

电控原理

速度控制

PWM

位置调整

一共4个灰度循迹模块,每边各两个。最内部的两个检测到黑线让两侧轮子以一个较小的差速前进。外侧的两个检测到黑线则让两侧轮子以相反方向转。

void run_2(void)
{
stop=HAL_GPIO_ReadPin(stop_GPIO_Port, stop_Pin);
track4 = HAL_GPIO_ReadPin(right_out_GPIO_Port, right_out_Pin);//获取传感器值
track3 = HAL_GPIO_ReadPin(right_in_GPIO_Port, right_in_Pin);
track2 = HAL_GPIO_ReadPin(left_in_GPIO_Port, left_in_Pin);
track1 = HAL_GPIO_ReadPin(left_out_GPIO_Port, left_out_Pin);

if ((track1 == 1 && track2 == 0 && track3 == 0 && track4 == 0)||(track1 == 1 && track2 == 1 && track3 == 0 && track4 == 0))//左左
turn_left_high();
else if (track1 == 0 && track2 == 1 && track3 == 0 && track4 == 0)//左
turn_left_low();
else if (track1 == 0 && track2 == 0 && track3 == 1 && track4 == 0)//右
turn_right_low();
else if ((track1 == 0 && track2 == 0 && track3 == 0 && track4 == 1)||(track1 == 0 && track2 == 0 && track3 == 1 && track4 == 1))//右右
turn_right_high();
else if(stop==1)
{
stopMotors();
HAL_Delay(10000);
}
else if ((track1==1&&track4==1&&track3==1)||(track1==1&&track4==1&&track2==1)||(track2==1&&track3==1&&track4==1)||(track2==1&&track3==1&&track1==1))
{
HAL_Delay(1);
track4 = HAL_GPIO_ReadPin(right_out_GPIO_Port, right_out_Pin);//获取传感器值
track3 = HAL_GPIO_ReadPin(right_in_GPIO_Port, right_in_Pin);
track2 = HAL_GPIO_ReadPin(left_in_GPIO_Port, left_in_Pin);
track1 = HAL_GPIO_ReadPin(left_out_GPIO_Port, left_out_Pin);
if ((track1==1&&track4==1&&track3==1)||(track1==1&&track4==1&&track2==1)||(track2==1&&track3==1&&track4==1)||(track2==1&&track3==1&&track1==1))
{
stopMotors();
HAL_Delay(10000);
}
}
else
ahead();
}

2.位置式PID
参考:https://blog.csdn.net/lqj11/article/details/116165991
3.停车黑线识别
问题:行驶中误触发
解决办法1:任意三个传感器同时检测到黑线,则延迟1ms再次检测,若仍检测到,则停车
办法2:移动平均滤波器(问ChatGPT得到的答案)
移动平均滤波器是一种常用的信号处理技术,用于平滑噪声信号或减少信号中的高频成分。它的基本原理是通过对一系列连续输入信号进行平均来计算输出信号。
移动平均滤波器的操作步骤如下:

  1. 定义一个固定大小的窗口或缓冲区,用于存储输入信号的历史数据。
  2. 每当有新的输入信号到达,将其添加到窗口的末尾,并将最早的输入信号从窗口的开头移除,以保持窗口的大小不变。
  3. 对窗口中的所有输入信号进行求和,并将求和结果除以窗口的大小,得到平均值。
  4. 平均值作为输出信号。
#include <stdio.h>

#define WINDOW_SIZE 3

float movingAverageFilter(float input) {
static float window[WINDOW_SIZE] = {0};
static int currentIndex = 0;
float sum = 0;

// 将新的输入信号添加到窗口
window[currentIndex] = input;

// 计算窗口中所有输入信号的和
for (int i = 0; i < WINDOW_SIZE; i++) {
sum += window[i];
}

// 更新当前索引
currentIndex = (currentIndex + 1) % WINDOW_SIZE;

// 计算平均值并返回
return sum / WINDOW_SIZE;
}

int main() {
float inputSignal[] = {1.2, 2.5, 3.1, 2.8, 4.0}; // 输入信号
int inputSignalSize = sizeof(inputSignal) / sizeof(float);

printf("Input Signal: ");
for (int i = 0; i < inputSignalSize; i++) {
float filteredSignal = movingAverageFilter(inputSignal[i]);
printf("%.2f ", filteredSignal);
}
printf("\n");

return 0;
}

极客赛

器件选型

FPM10A指纹识别模块
舵机
ASRPRO语音识别模块
PCF8591模数转换

通讯方式

IO口电平

UART串口通讯
串口发送数据:
HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)

UART_HandleTypeDef *huart UATR的别名 如 : UART_HandleTypeDef huart1; 别名就是huart1
*pData 需要发送的数据
Size 发送的字节数
Timeout 最大发送时间,发送数据超过该时间退出发送

发送字符a。

char ZZX='a';
HAL_UART_Transmit(&huart1,(uint8_t *)&ZZX,1, 0xffff);
接收字符并且返回接收到的字符:

基本流程:main函数中使能串口接收中断HAL_UART_Receive_IT()接收数据>接收到数据进入串口接收中断回调函数HAL_UART_RxCpltCallback()
####### 声明变量用来接收数据

#define RXBUFFERSIZE  256     //最大接收字节数

char TxBuffer[RXBUFFERSIZE]; //发送缓冲
uint8_t RxBuffer=0; //接收中断缓冲
uint8_t Uart1_Rx_Cnt = 0; //接收缓冲计数

变量RxBuffer是在接收中断函数HAL_UART_Receive_IT()中用来存储接收到的数据,数组TxBuffer是在串口接收中断回调函数HAL_UART_RxCpltCallback()存储中断函数HAL_UART_Receive_IT()中接收到的数据。
####### 启用接收中断(放置在main函数中)

HAL_UART_Receive_IT(&huart1, (uint8_t *)&RxBuffer, 1);

只触发一次中断,每次接收完数据要重复调用。
####### 设置串口接收中断回调函数HAL_UART_RxCpltCallback()

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(huart);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_UART_TxCpltCallback could be implemented in the user file
*/

if(Uart1_Rx_Cnt >= 255) //溢出判断
{
Uart1_Rx_Cnt = 0;
memset(TxBuffer,0x00,sizeof(TxBuffer));
HAL_UART_Transmit(&huart1, (uint8_t *)"数据溢出", 10,0xFFFF);

}
else
{
TxBuffer[Uart1_Rx_Cnt++] = RxBuffer; //接收数据转存

if((TxBuffer[Uart1_Rx_Cnt-1] == 0x0A)&&(TxBuffer[Uart1_Rx_Cnt-2] == 0x0D)) //判断结束位
{
HAL_UART_Transmit(&huart1, (uint8_t *)&TxBuffer, Uart1_Rx_Cnt,0xFFFF); //将收到的信息发送出去
while(HAL_UART_GetState(&huart1) == HAL_UART_STATE_BUSY_TX);//检测UART发送结束
Uart1_Rx_Cnt = 0;
memset(TxBuffer,0x00,sizeof(TxBuffer)); //清空数组
}
}

HAL_UART_Receive_IT(&huart1, (uint8_t *)&RxBuffer, 1); //开启接收中断
}
根据接收到的字符点亮LED灯:

方法同上,但无需配置串口接收中断回调函数HAL_UART_RxCpltCallback()

while (1)
{
if(RxBuffer=='a')
{
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_SET);
HAL_UART_Receive_IT(&huart1, (uint8_t *)&RxBuffer, 1);
}
if(RxBuffer=='b')
{
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, GPIO_PIN_RESET);
HAL_UART_Receive_IT(&huart1, (uint8_t *)&RxBuffer, 1);
}
}

IIC通讯