2023电赛G题

CM Lv3

2023年电赛G题(代码以及感受)

今天是2023年的8月7日,电赛已经结束俩天了。距离去福大的省测还有俩天。

本次电赛有很多和无人机没关系的小模块。我主要负责用stm32f103c8t6完成这些小模块。当然还有一些七七八八的杂活什么的。

1.自制模拟火源

题目要求是用激光笔照射2s左右可以让这个火源熄灭或者关闭。我的思路就是要在一段时间内一直判断是否被激光笔照射。怎么检测到激光笔的照射呢?利用光敏传感器,值得一提的是我当时调节光敏传感器的灵敏度的时候才发现光敏传感器的指示灯并不灵敏,所以想要真正确保光敏传感器输出电平的跳变,不要依赖指示灯,利用串口调试助手将光敏传感器的输出电平打印出来,才更加保险。

测试光敏传感器输出的高低电平程序:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include "stm32f10x.h"                  // Device header
#include "OLED.h"
#include "Serial.h"
uint8_t flag =0;
int main(void)
{
OLED_Init();

Serial_Init();

LightSensor_Init();

while (1)
{
flag = LightSensor_Get();
Serial_SendByte(flag);
}
}

想要照射2s左右熄灭或者点亮LED,需要做到俩点:

  1. 在这2s内一直判断光敏传感器输出的电平是否满足条件。
  2. 记住上一次的状态是熄灭还是点亮才能知道照射俩秒以后是点亮还是熄灭。

模拟火源代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include "stm32f10x.h"                  // Device header
#include "LED.h"
#include "LightSensor.h"
int main(void)
{
LightSensor_Init();
LED_Init();
LED2_OFF();
uint32_t count = 0;
uint8_t flag = 0;

while (1)
{
if (LightSensor_Get() == 0) // 光敏传感器检测到红外线。
{
count++;
if (count >= 200 ) // 等待2秒钟
{
if (LightSensor_Get() == 0)
{
if (flag == 0)
{
LED2_ON(); // LED 灯长亮
flag = 1;
count = 0;
}
else
{
LED2_OFF(); // LED 灯长灭
flag = 0;
count = 0;
}
}
}
}
else
{
count = 0;
}
}
}

2.消防车上按键按下启动无人机

我这里主要负责编写按键发送部分,也就是按键按下,小车上的stm32通过蓝牙向飞控发送一串约定好的信息。飞控接收到这串特定的信息就起飞。

主函数就是简单的几句代码:

1
2
3
4
5
6
Key_Init();
KeyNum = Key_GetNum();
if(KeyNum == 1) //小车上的stm32上面的按键,按下让无人机一键起飞
{
Serial_SendPacket(); //将一个数组发送出去,这个数组里面存的就是我们约定的信息。
}
1
2
3
4
5
6
void Serial_SendPacket(void)
{
Serial_SendByte(0xFF);
Serial_SendArray(Serial_TxPacket, 5);
Serial_SendByte(0xFE);
}
1
2
3
4
5
6
7
8
9
void Key_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitTypeDef GPIOInitStructure;
GPIOInitStructure.GPIO_Mode=GPIO_Mode_IPU;
GPIOInitStructure.GPIO_Pin=GPIO_Pin_1|GPIO_Pin_11;
GPIOInitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOB,&GPIOInitStructure);
}
  • 注意的是,需要先用AT指令将两个hc-05蓝牙配置好。
  • 小bug:这个key的初始化函数一定别忘了。我当时忘了,按键没按下去,轻轻晃一晃就会发出信息,我一直以为是误触还是消抖有问题。浪费了一些时间,然后还被海奇嘲笑!现在想想,可能是因为没有初始化,引脚是浮空输入,引脚的高低电平是不确定的,所以外界的一点点扰动就会让引脚高低电平变化。

3.OLED 屏幕显示无人机实时坐标、火源坐标、累计航程、航线图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
OLED1_Init();
OLED1_BMP(0); //第二块OLED屏幕显示航线图
if (Serial_GetRxFlag() == 1 && Serial_RxPacket[0] == 0xF0 && Serial_RxPacket[1] == 0x04)
{
if ((Serial_RxPacket[0] + Serial_RxPacket[1] + Serial_RxPacket[2] + Serial_RxPacket[3] + Serial_RxPacket[4] + Serial_RxPacket[5] + Serial_RxPacket[6]) %0x100 == Serial_RxPacket[7])
{
if(Serial_RxPacket[2] == 0x01)
{
data = ((Serial_RxPacket[3] << 8) | Serial_RxPacket[4]);

OLED_ShowNum(1,3,(data / 10),2);
OLED_ShowChar(1,5,'.');
OLED_ShowNum(1,6,(data % 10),1);

data = ((Serial_RxPacket[5] << 8) | Serial_RxPacket[6]);

OLED_ShowNum(1,10,(data / 10),2);
OLED_ShowChar(1,12,'.');
OLED_ShowNum(1,13,(data % 10),1);

OLED_ShowString(1,15,"dm");
}
if(Serial_RxPacket[2] == 0x02 && flag2 == 1)
{
data = ((Serial_RxPacket[3] << 8) | Serial_RxPacket[4]);

OLED_ShowNum(2,3,(data / 10),2);
OLED_ShowChar(2,5,'.');
OLED_ShowNum(2,6,(data % 10),1);

data = ((Serial_RxPacket[5] << 8) | Serial_RxPacket[6]);

OLED_ShowNum(2,10,(data / 10),2);
OLED_ShowChar(2,12,'.');
OLED_ShowNum(2,13,(data % 10),1);

OLED_ShowString(2,15,"dm");

flag2 = 0;

flag3 = 0;//stm32给树莓派发消息的标志位
}
if(Serial_RxPacket[2] == 0x03)
{
data = ((Serial_RxPacket[3] << 8) | Serial_RxPacket[4]);

OLED_ShowNum(3,5,(data / 10),3);
OLED_ShowChar(3,8,'.');
OLED_ShowNum(3,9,(data % 10),1);
OLED_ShowString(3,10,"dm");
}
}
}

我选择分两块OLED 屏幕显示。一块显示航线图,一块显示无人机实时坐标、火源坐标、累计航程。

在此感谢晓锋哥帮助我解决显示航线图的问题!!!非常感谢!

4.小车上stm32和树莓派通信

因为我们的小车是用树莓派做的,所以在发挥部分想要完成无人机发消息给小车,让小车前往火源的话,需要飞控给树莓派通信。既然我们小车上已经装了一个stm32了,所以我干脆再配置好usart2,通过ch340接到小车上。最后飞控先和stm32通信,stm32再和树莓派通信。然后小车前进。

1
2
3
4
5
6
7
8
9
10
11
12
13
if(flag == 1 && flag3 == 0)//小车上的stm32给树莓派发消息,flag只是让他只发一次,     
{

USART2_SendByte(0x0f);
USART2_SendByte(0xf0);
USART2_SendByte(0x20);
USART2_SendByte(0x01);
USART2_SendByte(0x01);
USART2_SendByte((0x0f + 0xf0 + 0x20 + 0x01 + 0x01) % 0x100);
flag = 0;
flag3 = 1;
}

为了只发一次信息给树莓派,我又增加了flag3,这部分还得配合上面第三部分一起看。整体的意思就是说,飞控发消息给stm32要灭火的信息以后,stm32接收信息以后,把flag3置0,然后stm32就可以发消息给树莓派了,发完信息立马又把flag3置1,这样子就不会再发了。

5. 丢灭火包。

因为飞控上的pwm不好调节占空比,所以我们在无人机上再装一个stm32,无人机和这块stm32通信,然后让这块stm32去驱动舵机去丢灭火包。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
int main(void)
{
Serial_Init();
PWM_Init();
while(1)
{
if (Serial_GetRxFlag() == 1 && Serial_RxPacket[0] == 0x0f && Serial_RxPacket[1] == 0xf0)
{
if ((Serial_RxPacket[0] + Serial_RxPacket[1] + Serial_RxPacket[2]) %0x100 == Serial_RxPacket[3])
{
if(Serial_RxPacket[2] == 0x10)
{
PWM_SetCompare2(500);
Delay_s(4);
PWM_SetCompare2(0);
Serial_RxPacket[0] = 0;
Serial_RxPacket[1] = 0;
Serial_RxPacket[2] = 0;
Serial_RxPacket[3] = 0;//为了保险舵机只转一次,说到底是为了省电。
}
}
}
}
}
  • Title: 2023电赛G题
  • Author: CM
  • Created at: 2023-08-07 16:55:04
  • Updated at: 2023-08-07 21:16:11
  • Link: https://redefine.ohevan.com/2023/08/07/2023电赛G题/
  • License: This work is licensed under CC BY-NC-SA 4.0.
 Comments