2022暑期学校——简单实现2021年电子设计竞赛国赛题目

目录

设计目标:

设计思路:

设计方案:

电机驱动

1)时钟配置

2)SYS配置

3)PWM信号输出

4)电机控制思路

5)电机驱动代码

电脑通讯

 1)CubeMx配置

 2)电脑通讯代码

HC05蓝牙通讯

1)HC05原理讲解

2)HC05蓝牙通讯代码

OpenMv处理

1)OpenMv道路识别

2)OpenMv的串口通讯

设计问题及解决:

1、STM32F429只引出了USART1引脚。

2、蓝牙模块连接的时候有效距离很短。


设计目标:

项目在2021年电子设计竞赛的国赛题目上进行了一些改动、

基本功能:其需要运输物品到指定位置(6个虚线位置),运输完成后将回到起始点。

新加功能:通过从另一片MCU远程提供目标点位置,在车上放物品后可以自动前往目标位置,同时远程MCU可以显示小车运动轨迹。

设计思路:

设计分为两块,分别为:

1、STM32F103:图形界面显示地图信息、触摸屏提供目标位置、HC05蓝牙通讯向小车传输目标点位置。

2、STM32F429:控制两类电机驱动L298N、AT8236、HC05蓝牙通讯接收目标点位置、OpenMv H7用于识别道路中的特殊位置如:十字路口、丁字路口等。

设计方案:

  • 电机驱动

为了保证小车速度,四轮均单独使用一对PWM信号,故采用两个驱动,驱动应尽量一致,但由于实验中有一驱动烧毁故采用不同的驱动实现。

小车电机型号为:

虽然AT8236拥有编码器控制模块,但电机并非编码电机,估值采用四路信号输出PWM信号控制电机转动。

从IN1、IN2、IN3、IN4分别与STM32F429的四个GPIO口相连,输出PWM信号,从而控制电机正反转及转动速度。使用STM32CubeMx配置GPIO口输出PWM信号,具体操作如下:

1)时钟配置

  1. 配置RCC中高速时钟HSE使用Crystal/Ceramic Resonator

        b)时钟树配置

2)SYS配置

其中Debug必须选用Serial Wire,否则会有板子下载后将无法找到板子从而无法再次下载的问题。

从OUT1、OUT2、OUT3、OUT4分别与小车电机的红黑线相连,从而保证小车可以正转,也可以反转。

3)PWM信号输出

采用TIM4和TIM5输出八路PWM信号,其中频率为:

96MHz/(95+1)/(254+1)=3.9KHZ,初始化占空比设置为0。

4)电机控制思路

 电机控制的总体流程如下

电机控制的具体流程为:

 在电机控制存在一个死循环,在死循环中不断地接收OpenMv的道路信息,更新车轮转速,进而达到寻线的目的,其中采用PID算法控制电机转速,由于题目中的路段基本都为直线和一些特殊交叉道路,故项目使用固定转弯时间来控制器转弯,转弯后继续寻线。 

5)电机驱动代码

此时根据CubeMx生成代码加入motor.c和motor.h文件,用于控制小车电机。部分代码如下:

//motor.h
void control_motor(int pwm_left, int pwm_right);
void stop_car();
void track_and_run();
void trun_left();
void trun_right();
void go();
void turn_180();
void go_home(int state);
void control_motor_all(int pwm_leftf, int pwm_leftr,int pwm_rightf,int pwm_rightr);
void run_way1(int state);
void run_way2(int state);
void run_way3(int state);
void run_way4(int state);
void run_way5(int state);
void run_way6(int state);
//motor.c
//定义输出的PWM输出通道
#define MOTOR_L &htim5
#define MOTOR_LF_F TIM_CHANNEL_4
#define MOTOR_LF_B TIM_CHANNEL_3
#define MOTOR_LR_F TIM_CHANNEL_2
#define MOTOR_LR_B TIM_CHANNEL_1
#define MOTOR_R &htim4
#define MOTOR_RF_F TIM_CHANNEL_4
#define MOTOR_RF_B TIM_CHANNEL_3
#define MOTOR_RR_F TIM_CHANNEL_2
#define MOTOR_RR_B TIM_CHANNEL_1

//定义PWM信号的最大最小值
#define pwm_max 255
#define pwm_min -255
#include "motor.h"
#include "tim.h"

int value=0;//表示从Openmv得到的路况信息
int turn_now=0;//无用
int stop_car_flag=0;//1表示停车
int stop_state=0;//停止线的数目
int T_num[4] = {0,0,0,0};//十字、T型、左上、右上
uint8_t PIC_buffer=1;//缓冲区,无用
extern int Move_modle;
extern int YL_start;
//int a=0;

//电机四轮驱动函数
void control_motor_all(int pwm_leftf, int pwm_leftr,int pwm_rightf,int pwm_rightr)
{
  if (pwm_leftf > 0) {
      __HAL_TIM_SetCompare(MOTOR_L,MOTOR_LF_F, pwm_leftf);
      __HAL_TIM_SetCompare(MOTOR_L,MOTOR_LR_F, pwm_leftr);
      __HAL_TIM_SetCompare(MOTOR_L,MOTOR_LF_B, 0);
      __HAL_TIM_SetCompare(MOTOR_L,MOTOR_LR_B, 0);
    }
    else {
      __HAL_TIM_SetCompare(MOTOR_L,MOTOR_LF_F, 0);
      __HAL_TIM_SetCompare(MOTOR_L,MOTOR_LR_F, 0);
      __HAL_TIM_SetCompare(MOTOR_L,MOTOR_LF_B, -pwm_leftf);
      __HAL_TIM_SetCompare(MOTOR_L,MOTOR_LR_B, -pwm_leftr);
    }
    if (pwm_rightf > 0) {
      __HAL_TIM_SetCompare(MOTOR_R,MOTOR_RF_F, pwm_rightf);
      __HAL_TIM_SetCompare(MOTOR_R,MOTOR_RR_F, pwm_rightr);
      __HAL_TIM_SetCompare(MOTOR_R,MOTOR_RF_B, 0);
      __HAL_TIM_SetCompare(MOTOR_R,MOTOR_RR_B, 0);
    }
    else {
      __HAL_TIM_SetCompare(MOTOR_R,MOTOR_RF_F, 0);
      __HAL_TIM_SetCompare(MOTOR_R,MOTOR_RR_F, 0);
      __HAL_TIM_SetCompare(MOTOR_R,MOTOR_RF_B, -pwm_rightf);
      __HAL_TIM_SetCompare(MOTOR_R,MOTOR_RR_B, -pwm_rightr);
    }
  
}
//停车
void stop_car()
{
  __HAL_TIM_SetCompare(MOTOR_L,MOTOR_LF_F, 0);
  __HAL_TIM_SetCompare(MOTOR_L,MOTOR_LR_F, 0);
  __HAL_TIM_SetCompare(MOTOR_L,MOTOR_LF_B, 0);
  __HAL_TIM_SetCompare(MOTOR_L,MOTOR_LR_B, 0);
  __HAL_TIM_SetCompare(MOTOR_R,MOTOR_RF_F, 0);
  __HAL_TIM_SetCompare(MOTOR_R,MOTOR_RR_F, 0);
  __HAL_TIM_SetCompare(MOTOR_R,MOTOR_RF_B, 0);
  __HAL_TIM_SetCompare(MOTOR_R,MOTOR_RR_B, 0);
}
//检测PWM信号是否在给定范围之内
int check_pwm(int value)
{
	if(value>pwm_max)return pwm_max;
	if(value<pwm_min)return pwm_min;
	return value;
}

//主控函数
void track_and_run(int state) {
	if(Move_modle==1)
	{
		run_way1(state);
	}
	else if(Move_modle==2)
	{
		run_way2(state);
	}
	else if(Move_modle==3)
	{
		run_way3(state);
	}
	else if(Move_modle==4)
	{
		run_way4(state);
	}
	else if(Move_modle==5)
	{
		run_way5(state);
	}
	else if(Move_modle==6)
	{
		run_way6(state);
	}
	
}


void trun_right()
{
	HAL_Delay(160);
	turn_now=1;
	control_motor_all(235,200,-215 ,-200);
	HAL_Delay(240);
}


void go()
{
	//int tracker_offset=-340;
			float tracker_KP;
			int tracker_val;
			float left_mult,right_mult;
			int pwm_base = 80;
			int pwm_left, pwm_right;
			//tracker_val = track_degrees;
			tracker_val = value;
			left_mult=1.0;
			right_mult=0.7;
			tracker_KP=4;

			
			pwm_left = (int)(pwm_base - tracker_val * tracker_KP*left_mult);
			pwm_left = check_pwm(pwm_left);
			pwm_right = (int)(pwm_base + tracker_val * tracker_KP*right_mult );
			pwm_right = check_pwm(pwm_right);

			control_motor(pwm_left,pwm_right);
}



void run_way1(int state)
{
	
	if (stop_car_flag==0 &&YL_start==1)//去的走法
	{
		if (state==0)
		{
			go();
		}
		else if(state==1)
		{
			//printf("%d\n%d\n%d\n",0xf1,1,0xf3);
			trun_left();
		}
		else if(state==2 )
		{
			stop_car();
		}
		else if(state==3 )//左边上边
		{
			stop_car();
		}
		else if(state==4 )//右边上边
		{
			stop_car();
		}
	}
	else if (stop_car_flag==1 &&YL_start==2)//回的走法
	{
		if (state==0)
		{
			go();
		}
		else if(state==1)
		{
			//printf("%d\n%d\n%d\n",0xf1,1,0xf3);
			trun_right();
		}
		else if(state==2 )
		{
			stop_car();
		}
		else if(state==3 )//左边上边
		{
			stop_car();
		}
		else if(state==4 )//右边上边
		{
			stop_car();
		}
	}
	else //回来后停车
	{
		stop_car();
	}
}

  • 电脑通讯

 1)CubeMx配置

STM32F429中使用USART3实现,原理图如下:

只需要在CubeMx中打开串口模式为Asynchronous即可完成串口调用

 2)电脑通讯代码

 USART的代码由CubeMx自动生成,其中需要自己添加重定向函数,并将Keil中魔术棒中Target一栏下Use MicroLIB勾选,即可通过printf()函数从串口输出数据。

 由于使用的STM32F429只引出了USART1的RX和TX,故对之后的串口通讯也从USART1的RX和TX输入输出数据,故在此声明了回调函数收集OpenMv的数据。printf可以将数据从TX输出,USART1_RXbuff接受了RX传输的数据。

/* USER CODE BEGIN 0 */
int fputc(int ch ,FILE *f)//重定向
{
	
	HAL_UART_Transmit (&huart1 ,(uint8_t *)&ch , 1,HAL_MAX_DELAY );
	return ch ;
}

//UART
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  uint16_t tempt;
  if(huart->Instance==USART1)
  {
    tempt=USART1_RXbuff;
    Openmv_Receive_Data(tempt);
	HAL_UART_Receive_IT(&huart1,(void *)&USART1_RXbuff,1);
  }	

}

/* USER CODE END 0 */
  • HC05蓝牙通讯

1)HC05原理讲解

HC05是一种比较集成的蓝牙模块,我们只需要调用串口就可以完成其传输功能,但必须将HC05进入AT模式调节对应参数。

  1. 长按按钮后接通VCC、GND、RXD、TXD即可进入AT模式,此时通过串口助手发送“AT+回车“,收到ok返回即进入AT模式。
  2. 在AT模式中主要设置连接密码,主从机地址等。具体参考文章:https://blog.csdn.net/seek97/article/details/81333701
  3. 拔掉电源后重新插入即可进入正常工作模式,此时会和设置好的蓝牙地址自动进行连接。
  4. 真正实现通讯还需要打开单片机的USART,通过RXD和TXD收发数据,此过程即简单的串口通讯过程,与电脑通讯类似,不再赘述。

2)HC05蓝牙通讯代码

 此部分代码和电脑端通讯代码是一样的,printf可以将数据从TX输出,USART1_RXbuff接受了RX传输的数据。

/* USER CODE BEGIN 0 */
int fputc(int ch ,FILE *f)//重定向
{
	
	HAL_UART_Transmit (&huart1 ,(uint8_t *)&ch , 1,HAL_MAX_DELAY );
	return ch ;
}

//UART
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
  uint16_t tempt;
  if(huart->Instance==USART1)
  {
    tempt=USART1_RXbuff;
    Openmv_Receive_Data(tempt);
	HAL_UART_Receive_IT(&huart1,(void *)&USART1_RXbuff,1);
  }	

}
  • OpenMv处理

1)OpenMv道路识别

以往小车识别道路需要识别黑色路线,而2021年国赛题目中需要识别红色道路,这要求OpenMv的图片格式必须为RGB565格式,同时在识别道路的时候采用阈值排除黑色边框的干扰。

2)OpenMv的串口通讯

 OpenMv的串口通讯拥有现成的函数,项目将其封装处理后可以通过帧头+内容+帧尾的形式收发数据。

#串口输出函数
def sending_data(Data1):
    global uart;
    #frame=[0x2C,18,cx%0xff,int(cx/0xff),cy%0xff,int(cy/0xff),0x5B];
    #data = bytearray(frame)
    data = ustruct.pack("<bbbb",      #格式为俩个字符俩个短整型(2字节)
                   0xF0,
                   0xF2,
                   Data1,
                   0xFF
                   )
    uart.write(data);   #必须要传入一个字节数组

#串口输入函数
def receive_data(Data):
    global LYstate
    global Move_model
    global Move_model_
    if Data !=' ':#可能有一些异常数据
        if LYstate==0 and Data=='241':#帧头
           LYstate=1
        elif LYstate==1:
            if Data=='243':#帧尾
                LYstate=0
            else:
                Move_model_=Data
                LYstate=2
        elif LYstate==2 and Data=='243':
                Move_model=Move_model_
                LYstate=0
        else:
            LYstate=0

OpenMv和单片机的通讯仍然只需要采用RXD和TXD传输数据即可。

设计问题及解决:

1、STM32F429只引出了USART1引脚。

从OpenMv的TXD给STM32F429的RXD传输数据,这部分用于识别道路并控制电机转动。

从STM32F429的TXD通过蓝牙模块给STM32F103的RXD传输数据,这部分将小车目前状况放回到操纵者手中。

从STM32F103的TXD通过蓝牙模块给OpenMv的RXD传输数据,这部分用于远程遥控小车系统。

2、蓝牙模块连接的时候有效距离很短。

        发现是VCC输入3.3V导致,输入5V的VCC可以正常工作。

  • 4
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

岂止是狼子野心

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值