文章目录[隐藏]
前言
从今年3月份开始得知要参加光电比赛,对于一个新手小白来说,确实有些紧张与压力。但万事开头难,不会咱们就去做,大不了从头开始,总比停滞不前好多了吧。最终在我与我小组不断的努力中,获得了省赛一等奖与国赛三等奖的不错成绩。在此,我将分享我制作过程中的点点滴滴,希望阅读到我的作品的各位伙伴们能有所收获。
购买物品
此次设计的光电垃圾分拣小车,在最开始时,我们并不知道垃圾是定点放置,起初我们都以为垃圾是随机分布的,于是开始的设计是通过超声波进行寻找物体。后来到比赛时才发现别的小组用的是定点寻物,唉,就比他们慢了很多,但无所谓了。
小车底盘购买
小车我们用的是众灵科技的C6小车,电机是减速370电机,直接用总线连接用PWM控制,很方便。
摄像头购买
摄像头采用的是星瞳科技的openmv7plus。这个摄像头是开源的,可以进行串口通信。
超声波购买
超声波采用的是SR超声波模块,开始买了一个,最后比赛时用了四个。
机械臂购买
机械臂也是在众灵购买的,用的是A款大夹子,我们对夹子进行了自主的改装,使得它可以进行抓取电池等小物品,也可以抓取瓶子等大物体。
设计思路
总体设计思路如下:
先通过超声波模块进行寻找物体,直到在物体面前18厘米处停下来。通过串口发送信息到摄像头,摄像头会进行神经网络识别,识别具体是什么物体。当识别完毕后,会发送串口信息到stm32控制其进行抓取物体,抓取成功后会在此发送信息到摄像头,接收到串口信息后,摄像头会根据开始识别的物体信息,寻找对应的色块,将色块的坐标信息发送给stm32,控制stm32进行小车的运动。当小车运动到色域足够大时,会发送信息到stm32控制小车放下物体。
代码分享
此代码全部为我自己亲手所写的内容。一个人写了将近1000行的摄像头代码。从0到1。我这次是真的体会到了。
stm32串口通信
串口是核心,只要是学32,串口必须掌握!!!
串口初始化:
void tb_usart_init(void) {
tb_usart1_init(115200);
uart1_open();
tb_usart2_init(115200);
uart2_open();
tb_usart3_init(115200);
uart3_open();
tb_interrupt_open();
return;
}
串口优先级:
void tb_usart1_init(u32 rate) {
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);
USART_DeInit(USART1);
/* Configure USART Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART Rx as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_InitStructure.USART_BaudRate = rate;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_ClockInitStructure.USART_Clock = USART_Clock_Disable;
USART_ClockInitStructure.USART_CPOL = USART_CPOL_Low;
USART_ClockInitStructure.USART_CPHA = USART_CPHA_2Edge;
USART_ClockInitStructure.USART_LastBit = USART_LastBit_Disable;
USART_ClockInit(USART1, &USART_ClockInitStructure);
USART_Init(USART1, &USART_InitStructure );
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
// USART_ITConfig(USART1, USART_IT_PE, ENABLE);
// USART_ITConfig(USART1, USART_IT_ERR, ENABLE);
USART_Cmd(USART1, ENABLE);
}
串口中断函数:
int USART1_IRQHandler(void) {
u8 sbuf_bak;
static u16 buf_index = 0;
if(USART_GetFlagStatus(USART1,USART_IT_RXNE)==SET) {
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
sbuf_bak = USART_ReceiveData(USART1);
//uart1_send_byte(sbuf_bak);
if(uart1_get_ok)return 0;
if(sbuf_bak == '<') {
uart1_mode = 4;
buf_index = 0;
}else if(uart1_mode == 0) {
if(sbuf_bak == '$') { //命令模式 $XXX!
uart1_mode = 1;
} else if(sbuf_bak == '#') { //单舵机模式 #000P1500T1000! 类似这种命令
uart1_mode = 2;
} else if(sbuf_bak == '{') { //多舵机模式 {#000P1500T1000!#001P1500T1000!} 多个单舵机命令用大括号括起来
uart1_mode = 3;
} else if(sbuf_bak == '<') { //保存动作组模式 <G0000#000P1500T1000!#001P1500T1000!B000!> 用尖括号括起来 带有组序号
uart1_mode = 4;
}
buf_index = 0;
}
uart_receive_buf[buf_index++] = sbuf_bak;
if((uart1_mode == 4) && (sbuf_bak == '>')){
uart_receive_buf[buf_index] = '\0';
uart1_get_ok = 1;
} else if((uart1_mode == 1) && (sbuf_bak == '!')){
uart_receive_buf[buf_index] = '\0';
uart1_get_ok = 1;
} else if((uart1_mode == 2) && (sbuf_bak == '!')){
uart_receive_buf[buf_index] = '\0';
uart1_get_ok = 1;
} else if((uart1_mode == 3) && (sbuf_bak == '}')){
uart_receive_buf[buf_index] = '\0';
uart1_get_ok = 1;
}
if(buf_index >= UART_BUF_SIZE)buf_index = 0;
}
//发送中断 用前在初始化的时候请打开
//if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET) {
//USART_SendData(USARTy, TxBuffer1[TxCounter1++]);
//}
return 0;
}
stm32超声波模块编写
超声波有四个:
初始化:
void setup_csb() {
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOA, ENABLE);
//初始化超声波IO口 Trig PB0 Echo PA2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//初始化超声波定时器
TIM3_Int_Init(30000, 71);
}
编写条件:
void csb_Delay_Us(uint16_t time) //延时函数
{
uint16_t i,j;
for(i=0;i<time;i++)
for(j=0;j<9;j++);
}
/*************************************************************
函数名称:get_csb_value()
功能介绍:采集超声波数据
函数参数:无
返回值: 采集的数据
*************************************************************/
u16 get_csb_value(void) {
u16 csb_t;
Trig(1);
csb_Delay_Us(20);
Trig(0);
while(Echo() == 0); //等待接收口高电平输出
TIM_SetCounter(TIM3,0);//清除计数
TIM_Cmd(TIM3, ENABLE); //使能TIMx外设
while(Echo() == 1);
TIM_Cmd(TIM3, DISABLE); //使能TIMx外设
csb_t = TIM_GetCounter(TIM3);//获取时间,分辨率为1US
//340m/s = 0.017cm/us
if(csb_t < 25000) {
// sprintf((char *)cmd_return, "csb_time=%d\r\n", (int)(csb_t*0.17));
// uart1_send_str(cmd_return);
csb_t = csb_t*0.017;
return csb_t;
}
return 0;
}
进行判断:
void zhuixun(void) {
static u32 systick_ms_bak = 0;
int adc_csb;
if(group_do_ok == 0)return;
//每20ms计算一次
while(1){
// loop_sensor();
get_csb_value();
get_adc_csb_middle();
if(millis() - systick_ms_bak > 50) {
systick_ms_bak = millis();
adc_csb = get_adc_csb_middle();//获取a0的ad值,计算出距离
// sprintf((char *)uart_receive_buf, "adc_csb = %d\r\n", adc_csb);
// uart1_send_str(uart_receive_buf);
if(adc_csb >100)
{
car_set(850,-850);
}
// if(adc_csb < 20) {//距离10cm左右就夹取
// car_set(0,0);
// beep_on_times(1, 100);
// parse_cmd((u8 *)"$DGT:1-8,1!");
// break ;
// }
if((adc_csb > 19.5) && (adc_csb <95)) {
car_set (400,400);}
if(adc_csb<18){
car_set (-300,-300);
}
if((adc_csb > 18)&&(adc_csb < 19.5)) {//距离10cm左右就夹取
car_set(0,0);
// beep_on_times(1, 100);
bianliang=1;
break ;
}
}
//tb_usart1_send_str("0xaa 0x01 0xbb");
}
//parse_cmd((u8 *)"$DGT:6-8,1!");
}
openmv核心代码
神经网络采用官网教程进行操作。
串口通信
import sensor, image, time, os, tf
from pyb import UART
import json
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time=2000)
net = "trained.tflite"
labels = [line.rstrip('\n') for line in open("labels.txt")]
clock = time.clock()
uart = UART(3, 115200,timeout_char=1000)
uart.init(115200, bits=8, parity=None, stop=1)
while(True):
bool_flag_1=False
if uart.any():
buff = [range(1000)]
buff = uart.readline().decode()
进行判断并且分级操作
img = sensor.snapshot()
for obj in tf.classify(net, img, min_scale=1.0, scale_mul=0.8, x_overlap=0.5, y_overlap=0.5):
bool_flag_2=False
print("**********\nPredictions at [x=%d,y=%d,w=%d,h=%d]" % obj.rect())
img.draw_rectangle(obj.rect())
predictions_list = list(zip(labels, obj.output()))
if bool_flag_1==True:
bool_flag_1=False
break
for i in range(len(predictions_list)):
print("%s = %f" % (predictions_list[i][0], predictions_list[i][1]))
nums = [predictions_list[0][1],predictions_list[1][1],predictions_list[2][1],predictions_list[3][1],predictions_list[4][1]]
max_num = 0
for j in nums:
max_num = j if j >= max_num else max_num
if bool_flag_2==True:
bool_flag_1=True
bool_flag_2=False
break
if predictions_list[i][1]>=max_num:
data = i
if data==00:
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(10)
sensor.set_auto_whitebal(False)
clock = time.clock()
black_rhreshold =(6, 63, -64, 14, -50, 31)
red_rhreshold = (17, 47, 3, 96, -94, 69)
size_threshold = 5000
def find_max(blobs):
max_size=0
for blob in blobs:
if blob[2]*blob[3] > max_size:
max_blob=blob
max_size = blob[2]*blob[3]
return max_blob
while(True):
clock.tick()
img = sensor.snapshot()
blobs = img.find_blobs([red_rhreshold])
if blobs:
max_blob = find_max(blobs)
img.draw_cross(max_blob.cx(),max_blob.cy())
img.draw_rectangle(max_blob.rect())
W=max_blob.w()
H=max_blob.h()
S=int(W*H)
X=int(max_blob.cx()-img.width()/2)
Y=int(max_blob.cy()-img.height()/2)
print("x轴偏移坐标:",X)
print("Y轴偏移坐标:",Y)
print("S面积",S)
if 10<X and (S<10000 and S>8000):
b_output = 300
a_output = 50
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(1750)+'T0000!'
qi = '#007P'+str(1250)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if -10>X and (S<10000 and S>8000):
b_output = 300
a_output = -50
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(1750)+'T0000!'
qi = '#007P'+str(1250)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if (10>X and X>-10) and (S<10000 and S>8000):
b_output = 300
a_output = 0
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(1750)+'T0000!'
qi = '#007P'+str(1250)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if 10<X and (S<8000 and S>5000):
b_output = 300
a_output = 100
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(1800)+'T0000!'
qi = '#007P'+str(1200)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if -10>X and (S<8000 and S>5000):
b_output = 300
a_output = -100
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(1800)+'T0000!'
qi = '#007P'+str(1200)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if (10>X and X>-10) and (S<8000 and S>5000):
b_output = 300
a_output = 0
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(1800)+'T0000!'
qi = '#007P'+str(1200)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if 10<X and (S<5000 and S>3000):
b_output = 300
a_output = 200
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(1900)+'T0000!'
qi = '#007P'+str(1100)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if -10>X and (S<5000 and S>3000):
b_output = 300
a_output = -200
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(1900)+'T0000!'
qi = '#007P'+str(1100)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if (10>X and X>-10) and (S<5000 and S>3000):
b_output = 300
a_output = 0
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(1900)+'T0000!'
qi = '#007P'+str(1100)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if 10<X and (S<3000 and S>0):
b_output = 300
a_output = 300
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(2000)+'T0000!'
qi = '#007P'+str(1000)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if -10>X and (S<3000 and S>0):
b_output = 300
a_output = -300
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(2000)+'T0000!'
qi = '#007P'+str(1000)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if (10>X and X>-10) and (S<3000 and S>0):
b_output = 300
a_output = 0
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(2000)+'T0000!'
qi = '#007P'+str(1000)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if -10>X and (S>10000):
b_output = 300
a_output = 100
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(1250)+'T0000!'
qi = '#007P'+str(1750)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if 10>X and (S>10000):
b_output = 300
a_output = -100
qian = '{#002P'+str (int(1500+a_output))+'T0000!'
liu = '#006P'+str(1250)+'T0000!'
qi = '#007P'+str(1750)+'T0000!}'
data = bytearray(qian+liu+qi)
uart.write(data)
if -10<X<10 and S>10000:
data = bytearray('{#006P1500T0000!#007P1500T0000!#002P1500T0000!}')
dataxia = bytearray('$XIA!')
uart.write(data)
time.sleep_ms(500)
uart.write(dataxia)
bool_flag_2=True
break
else:
data = bytearray('{#006P2300T0000!#007P2300T0000!#002P1500T0000!}')
uart.write(data)
代码太多,核心代码我已经在此列出。总之我相信各位大佬肯定可以看懂吧。欢迎各位大佬评论留言。
源码
最后我将stm32与openmv完整代码发到这里,有需要的可以下载。谢谢
代码下载
版权声明:本文为CSDN博主「C饭王」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_45253310/article/details/119208371
暂无评论