Project 07 of 11: 项目 07 / 11:NUEDC 2025 Simple Self-Aiming Device2025 电赛简易自行瞄准装置
Problem E of the 2025 National Undergraduate Electronic Design Contest: an MSPM0 line-tracking car carrying a K230 gimbal that aims a laser at a target. I captained a team of three that had to knock on seven or eight doors for a supervisor and nearly missed registration. In 84 hours we burned a core board and threw away a gimbal, and came out with a Jiangsu second prize, XJTLU's first NUEDC award.2025 年全国大学生电子设计竞赛 E 题:一辆 MSPM0 循迹小车,车上架着 K230 云台,用激光去打靶心。我当队长的三人队,找指导老师敲了七八扇门,报名差点没赶上;84 小时里烧了一块核心板、扔了一个云台,最后拿了江苏省二等奖,也是西浦在电赛上的第一个奖。


Finding a Supervisor and Registering找老师与报名
The Jiangsu division kept the submitted entries in a big room with a wooden floor, marked out in white tape, one square per school with the school's name on a sheet of A4. The other schools' squares were piled with box after box. The square for Xi'an Jiaotong-Liverpool University sat against the far wall, holding one box. Inside it was the car the three of us had built in four days and three nights. Getting that one box onto that floor took about as much effort as building the car.
江苏赛区收作品的地方是一间铺木地板的大屋子,地上用白胶带隔出一格一格,每格贴一张 A4 纸写着学校名字。别的学校那几格,纸箱一摞挨一摞;西交利物浦大学那一格在最里头靠墙,地上就摆着一个箱子,里面是我们三个人四天三夜做出来的车。能让这一个箱子摆到这块地板上,前面费的劲不比做车少。

The team was three third-year students from XJTLU's School of Advanced Technology (SAT) who put themselves together. NUEDC needs a supervising teacher, so we went floor by floor through the SAT building knocking on doors. Seven or eight teachers in all, and not one wanted to take on a team for a contest none of us had ever entered. One meeting I won't forget: the moment we started explaining, the teacher launched into a pitch for the optoelectronics contest they supervised and told us NUEDC was useless. The three of us stood there and could not get a single word in. It felt exactly like being cornered by a pyramid-scheme recruiter. The one who finally said yes was my supervisor from SURF, XJTLU's summer programme where undergraduates do research with academic staff. Only then did the team actually exist.
队伍是我们三个大三学生自己凑起来的,都在西浦的智能工程学院(SAT)。电赛要有指导老师,我们就在 SAT 办公楼里一层一层敲门,前后敲了七八个老师的门,没有一个愿意带一支从没打过电赛的队伍。有一位老师让我印象最深:我们刚开口讲,对方就开始推销自己带的光电大赛,顺带告诉我们电赛没什么用。我们三个大活人站在那,一句嘴都插不上,那个架势跟传销现场一模一样,真的服了。最后点头的是我做 SURF 时的导师,SURF 是西浦的暑期本科生科研项目,本科生跟着学院老师做一段研究。有老师肯带,这支队伍才算立住。
With a supervisor sorted, we couldn't find where to register. Every Jiangsu notice went out in a QQ group, and nobody from XJTLU was in it. Whoever maintained the official site that year never posted the 2025 registration notice, and the newest files there were from 2024. We hunted everywhere and finally found a QQ group number in the small print at the bottom of a 2023 notice. I joined, asked around, and someone pushed me the 2025 provincial group. By then the fee deadline had already passed, and there wasn't a single XJTLU name in the group. Absolutely ridiculous. We explained our situation to the organisers, and they let us register late. Notices live only in a chat group, nobody looks after the website, and a new school gets no attention at all. The whole process was held together with tape. Any later, and this car would never have been built.
老师有了,报名入口又找不到。江苏赛区的通知全发在一个 QQ 群里,西浦没有一个人在群里;那年负责更新官网的人也偷了懒,没发 2025 年的报名通知,官网上最新的文件还停在 2024 年。我们到处找入口,最后是在一篇 2023 年公告最底下的小字里翻到一个 QQ 群号,加进去问了一圈,才有人把 2025 年的省赛群推给我。进群的时候,缴费截止日已经过了,群里一个西浦的人都没有,闹麻了。跟组委会说明了情况,才让我们补报上。通知全靠群,官网没人管,新学校没人搭理,草台班子得明明白白。再晚一点,这辆车根本就没有机会造出来。
Preparation备赛
From June we were in the lab every day. None of us had done the contest before, and the school had no inherited code or training system to lean on, so everything started from scratch. My embedded knowledge came from Jiangxie Technology's STM32 course on Bilibili, and FreeRTOS from Wei Dongshan's videos. In those two months I drew my own schematic and built a two-wheeled STM32 balance car, and worked through 2024's problem H, an autonomous driving car, on TI's MSPM0.
从 6 月起,我们每天泡在实验室。三个人谁都没打过电赛,学校里也没有传下来的代码和备赛体系,一切从零开始。我的嵌入式是跟着 B 站江协科技的 STM32 课入的门,FreeRTOS 看的是韦东山。备赛那两个月,我自己画原理图做了一台 STM32 双轮平衡车,又拿 TI 的 MSPM0 把 2024 年的 H 题自动行驶小车练了一遍。


Problem E and the CarE 题与整车方案
The contest opened at 8:00 on 30 July. As soon as the problems came out we picked problem E, a control problem: the simple self-aiming device. A car follows a black-line track, a square one metre on a side, counterclockwise. On the car sits a two-axis gimbal steering a blue-violet laser pointer, which has to put its spot on the bullseye of an A4 target standing 50 cm outside the track. The car must be controlled by an MSPM0, and the MSPM0 and the aiming module each need their own power switch. From the start to sealing at 20:00 on 2 August we had four days and three nights, 84 hours.
7 月 30 日早上 8 点开赛,题目一公布,我们挑了控制类的 E 题,简易自行瞄准装置。一辆小车沿着 1 m 见方的黑线跑道逆时针循迹,车上架一个二维云台,控制一支蓝紫激光笔,把光斑打到跑道外 50 cm 那张 A4 靶纸的靶心上。小车必须用 MSPM0 控制,MSPM0 和瞄准模块要用两个独立的开关分别上电。从开赛到 8 月 2 日晚 8 点封箱,一共四天三夜,84 小时。
I was the captain, responsible for the system architecture, the hardware plan, the wiring and the power, plus all the car's code on the MSPM0. One teammate took the K230 vision and gimbal code, and by the first morning had already trained a single-class detection model whose only label is yuan, Chinese for circle. The other teammate took the mechanical structure, assembly, integration and the design report. Every module on the car was bought ready-made: an MSPM0G3507 core board, a TB6612 motor driver, geared motors with encoders, an eight-channel grey-scale sensor bar, an MPU6050, an OLED, a CanMV K230, the gimbal servos, a relay and the laser pointer. Three days left no time to draw boards. The plan, the wiring and the code were ours.
我是队长,负责整车的系统架构、硬件方案、接线和供电,以及 MSPM0 上小车的全部代码。一位队友负责 K230 的视觉识别和云台代码,开赛第一天上午就训出了一个单类检测模型,只认一个类别 yuan,也就是圆;另一位队友负责机械结构、装配、联调和设计报告。车上的模块全是买来的成品:MSPM0G3507 核心板、TB6612 电机驱动、带编码器的减速电机、八路灰度传感器、MPU6050、OLED、CanMV K230、云台舵机、继电器和激光笔。三天时间画不了板子,方案、接线和代码都是我们自己定、自己接、自己写的。


Line Tracking循迹
The first two days went almost entirely into line tracking, and the car only ran steadily on the evening of day two. The idea is plain enough. Six channels on the grey-scale bar each report a signed score when they sit on the line, and the sum says which way to turn and how hard. Corners are counted off the track: one count per right-angle corner, a key sets N laps, and the car stops after 4N corners. Plain as it is, getting the car to lap a one-metre square steadily, lap after lap, took the whole two days; the lapping video shows where it ended up. How those few lines turn six readings into steering is in Weighted Six-Channel Line Tracking and Lap Counting, and where the car's control clock comes from is in MPU6050 Interrupts as the Control Clock.
前两天几乎全花在循迹上,车到第二天晚上才跑稳。思路很朴素:灰度条上接了六路,压在线上的那几路各报一个带正负号的分,加起来就是车该往哪拐、拐多急;过弯靠数线,每过一个直角数一次,按键选好 N 圈,数够 4N 个弯就停。思路是朴素,真要它在 1 m 见方的跑道上一圈一圈稳稳地转起来,整整磨了两天,跑圈的视频里是它最后的样子。这几行代码怎么把六个读数变成转向,写在六路灰度循迹的加权与计圈;车上的控制节拍是从哪来的,写在用 MPU6050 中断给控制环打拍子。
The Burned Core Board烧掉的核心板
On day two the main controller burned. The grey-scale sensors were running from 5 V, their outputs went straight into IO pins that only tolerate 3.3 V, and we had put nothing in between, so the C07A core board was simply gone. The spare we had was barely usable; I ran flying wires on it so we could keep debugging, and a new chip sent by SF Express rush delivery only arrived early on day four. The last twelve hours were swapping the chip, soldering and flying wires, all of which I did, and the sensors moved to 3.3 V. One mismatched logic level cost a core board and a rush courier bill. How it burned, and what the car's two power systems each feed, are in Two Power Systems and the Relay-Switched Laser.
第二天,主控板烧了。灰度传感器那时接的是 5 V,输出直接怼进只扛得住 3.3 V 的 IO 口,我们又没在中间加任何保护,C07A 核心板就这么没了。手上的备用板几乎不能用,我在上面飞线,凑合着接着调;顺丰加急寄来的新芯片第四天清晨才到。最后十二个小时,一直在换芯片、焊接、飞线,这些都是我做的,传感器也改到了 3.3 V 上。一个电平没对上,代价是一块核心板和一单加急快递。板子是怎么烧的、车上两套电源各管什么,写在两套电源与继电器控制的激光。



Gimbal and Target Tracking云台与追靶
The gimbal went through three designs. The first was a 3D-printed stepper-motor gimbal drawn by our mechanics teammate. Our chassis was already tall, and with that gimbal on top the car broke the problem's 25 cm height limit. There was no time for a redesign, so it went in the bin. Next came serial bus servos. Their communication was reliable enough, but the servos we bought were so imprecise that the laser wandered all over the target, even with the PID tuned.
云台前前后后换了三套。最早是负责机械的队友画的 3D 打印步进电机云台,我们的底盘本来就高,云台装上去,整车就超过了题目 25 cm 的限高,一时半会又改不出新版,只好扔掉。接着换成串口总线舵机,通信倒是稳,可买来的舵机精度太差,激光笔在靶纸上抖来抖去,PID 调好了照样抖。
By the afternoon of day three the gimbal still couldn't hold the target, and all of us were close to writing off the aiming part. I dug into my teammate's K230 code and found three problems. The servo limits weren't set properly, so the servos kept turning out of range. The output direction was reversed, so every correction made the error bigger. And once the direction was right, the gimbal would track halfway and then slide off without picking the target up again. That one took ages: an if/else was missing a branch, and once the program went in, it never came back out. With all three fixed, the gimbal came alive in one go. That moment felt like the top of a roller coaster.
到第三天下午,云台还是追不住靶,大家几乎认定瞄准这块交不了差。我扎进队友的 K230 代码里查,查出三处问题。舵机的限位没设好,老是转出界;输出方向反了,误差越修越大;方向改对以后,追目标追到一半会滑开,不再接着追,这一处研究了半天,原来是一组 if/else 少写了一层分支,程序进去以后就再没跳出来。三处改完,云台一下子活了,那一刻的心情跟坐过山车冲上顶差不多。
The laser still shook on the serial servos, so in the end we switched to PWM servos, paired with the model my teammate had trained on day one, and the K230 found the target, worked out the angles and switched the laser on its own. One desk test has the gimbal chasing a target on a laptop screen, and a run on the track ends with the spot on the bullseye. How the loop gets from pixels to servo angles, and which link each of the three faults sat in, is in The K230 Gimbal Tracking Loop.
串口舵机上的激光还是抖,最后换成了 PWM 舵机,配上队友第一天就训好的模型,K230 自己找靶、自己算角度、自己开关激光。桌上的一段测试里,云台追着笔记本屏幕上的靶子转;跑道上的一段最后,光斑落在了靶心上。这条回路怎么从像素算到舵机角度,那三处毛病各卡在哪一环,写在 K230 云台追靶回路。
Judging in Nanjing南京测评
We sealed the box at 8 pm on 2 August. The next day we carried it to Nanjing for the Jiangsu judging at Nanjing Vocational College of Information Technology, worried the whole way that the trip had shaken loose some of those flying wires. At the venue, the other schools arrived as organised delegations, coach after coach, teams carrying banners, with code and training passed down over the years. We were three people with one box, like gatecrashers at someone else's party. There were teams from Jiangsu University of Science and Technology there too. Everything I knew about embedded systems came from Jiangxie Technology's videos, which everyone calls the "Jiangkeda" course, after that very university's nickname. Meeting the actual Jiangkeda in person made the gap very concrete.
8 月 2 日晚上 8 点封箱。第二天我们抱着箱子去南京,在南京信息职业技术学院参加江苏赛区测评,一路上都在担心那些飞线经不经得住颠。到了现场,别的学校是学校统一组织,大巴一辆接一辆,队伍举着队旗,带着一届届传下来的代码和成熟的备赛体系;我们三个人自己来,抱着一个箱子,活像误闯天家。场上还看到了江苏科技大学的队伍。我的嵌入式全是跟着江协科技的视频学的,那套课大家都管它叫江科大,这回真撞见了江科大本校的人,差距一下子就具体了。



Before opening the box we silently prayed to the machine spirit. The car behaved itself and ran just as it had in the lab. All three basic requirements passed. The extensions were another story: not one of them. The first two ask the car to drive one lap and then two with the laser held on the target the whole way, and both came apart at the right-angle corners. The car body swung round, the target was flung out of frame, and the gimbal could not win it back. We never attempted the third, drawing a circle in sync with the lap. When the judge picked up the score sheet and walked away, the string that had been pulled tight for four days finally went slack.
开箱前,三个人对着车默默祈祷机魂大悦。车很争气,跟在实验室里一个样:基本要求三项全部完成。发挥部分就没那么争气了,一项都没拿下:前两项要车跑一圈、跑两圈,全程让激光一直打在靶上,结果都栽在直角弯上,车身一转,靶就被甩出画面,云台追不回来;第三项同步画圆,我们没做。评委拿着测评表转身走开的那一刻,三个人绷了四天的那根弦才终于松下来。
Result结果
A few days later the Jiangsu results came out: a provincial second prize. We stopped at the provincial round and did not go on to the national one. It was also the first NUEDC award in XJTLU's history. When we signed up, the goal we set ourselves was simply to finish.
几天后江苏赛区的结果出来,江苏省二等奖,止步省赛,没进国赛。这也是西浦建校以来在电赛上拿到的第一个奖。报名那会儿,我们给自己定的目标只有一个:完赛就是胜利。



A team that knocked on seven or eight doors to find a supervisor and only scraped through registration on an organiser's goodwill. In four days it burned a core board, threw away a gimbal and failed every extension, and the basic requirements alone still carried it to a provincial second prize, putting XJTLU's name on Jiangsu's NUEDC award list for the first time. I'm genuinely proud of this, and I have no intention of being modest about it.
一支敲了七八扇门才找到老师、靠组委会通融才补上报名的队伍,四天里烧了一块核心板、扔了一个云台,发挥题一项都没拿下,光靠基本要求也拼到了省二等奖,把西浦的名字第一次写进了江苏赛区电赛的获奖名单。这件事我是真的骄傲,也不打算谦虚。
Development notes开发笔记
Debugging records and technical notes tied to the decisions and artifacts on this project page.与这个项目页面中的设计决策和工程材料直接关联的调试记录与技术笔记。
- 01The K230 Gimbal Tracking LoopK230 云台追靶回路On the afternoon of day three the NUEDC car's gimbal still could not hold the target, and three faults turned up in the K230 code: servo limits, a reversed loop sign and a missing branch. Following the loop from pixel error to servo duty cycle shows where each one sat, and why the extensions were still lost at the right-angle corners.电赛第三天下午,云台还是追不住靶,K230 代码里揪出三处毛病:舵机限位、回路方向、少了一层分支。顺着回路从像素误差走到舵机占空比,能看清这三处各卡在哪一环,也能看清发挥题为什么还是栽在了直角弯上。
- 02MPU6050 Interrupts as the Control Clock用 MPU6050 中断给控制环打拍子The NUEDC car's project configures a 5 ms timer and never starts it; the control loop actually runs inside the MPU6050's DMP data-ready interrupt, 200 Hz from the sensor's own clock, halved to 100 Hz, and shared with two encoders decoded at 2x. What that inherited structure buys, what it costs, and what the motors do if the sensor ever goes quiet.电赛小车的工程里配了一个 5 ms 的定时器,却从来没启动;控制环实际跑在 MPU6050 的 DMP 数据就绪中断里,传感器自己的时钟给出 200 Hz,控制减半到 100 Hz,还和两路二倍频解码的编码器挤在同一个中断里。这套从例程继承来的结构换来了什么、付出了什么,传感器一旦不再发中断,电机又会怎样。
- 03Two Power Systems and the Relay-Switched Laser两套电源与继电器控制的激光On day two of the NUEDC contest the grey-scale sensors' 5 V outputs killed the MSPM0 core board. Working back from that board through the datasheet and the car's two power systems, a buck plus LDO chain for the MSPM0 and three separately switched LM2596 bucks for the aiming side, ends at the relay that lights the laser when its K230 GPIO goes low.电赛第二天,灰度传感器的 5 V 输出烧掉了 MSPM0 核心板。从这块板子出发,翻数据手册,再顺着车上的两套电源往下走:MSPM0 这边是降压加 LDO,瞄准那边是单独开关的三颗 LM2596,最后走到那个让激光在 K230 的 GPIO 拉低时才亮的继电器。
- 04Weighted Six-Channel Line Tracking and Lap Counting六路灰度循迹的加权与计圈The NUEDC car's line tracking took the first two days and ran steadily only on the evening of day two. Read again, its handful of lines turn six grey-scale channels into a target wheel-speed difference, let a sum and a difference decide between a gentle arc and a pivot, and count laps off the same outer sensor that pulls hardest.电赛小车的循迹占掉了前两天,到第二天晚上才跑稳。把那几行代码重新读一遍:六路灰度加成一个轮速差目标,一个和、一个差决定车是缓缓画弧还是原地打转,计圈用的又恰好是拽得最狠的那一路传感器。
Public Project Files公开项目资料
Uploaded evidence served from the public asset folder. Use the file index to preview documents, source code, media, PDFs, and downloadable artifacts without leaving the page.这里列出已经上传到公开目录的项目证据。可以在左侧索引里选择文件,在右侧直接预览文档、源码、媒体、PDF 和可下载附件。
balance.c
C / 9.9 KB
#include "balance.h"
#include "bsp_siic.h"
#include "bsp_debugtimer.h"
#include "bsp_key.h"
#include "bsp_debugtimer.h"
#include "MPU6050.h"
//编码器值
extern volatile short g_EncoderACount;
extern volatile short g_EncoderBCount;
int Turn1=0;
int Velocity1=0;
//小车标志位,1停止,0启动
uint8_t Flag_Stop = 1;
//车轮速度,仅用于OLED显示
float Velocity_Left,Velocity_Right;
//左右电机PWM值
int Motor_Left,Motor_Right;
//蓝牙遥控相关的标志位
uint8_t Flag_front,Flag_back,Flag_Left,Flag_Right,Flag_velocity=2;
//小车PID参数
//float Balance_Kp=28305,Balance_Kd=150,Velocity_Kp=25215,Velocity_Ki=125,Turn_Kp=4662,Turn_Kd=66;
float Balance_Kp=0,Balance_Kd=0,Velocity_Kp=-20,Velocity_Ki=1,Turn_Kp=15,Turn_Kd=2;
//机械中值
short MiddleAngle = 3;
//小车电池电压
float robotVol=0;
uint8_t getVolFlag = 0;
//控制任务,此函数放置于外部中断内执行,5ms控制1次
int Encoder_Left,Encoder_Right;
int controlFlag = 0;
int flag=0;
void BalanceControlTask(void)
{
static int Balance_Pwm=0,Velocity_Pwm_R=0,Velocity_Pwm_L=0,Turn_Pwm=0;
//控制频率,降低为100hz
//按键检测
pKeyInterface_t key = &UserKey;
UserKeyState_t keystate = key->getKeyState(200);
//通过单击按键启动/关闭平衡小车
if( keystate == USEKEY_single_click ) Flag_Stop = !Flag_Stop;
//计算电池电压
robotVol = (float)Get_Vol()*3.3f*11.0f/4096.0f;
flag+=1;
controlFlag=!controlFlag;
if(controlFlag==0 )
{
flag=0;
//读取编码器数值
Encoder_Left = g_EncoderACount;
Encoder_Right = g_EncoderBCount;
g_EncoderACount=0,g_EncoderBCount=0;
//通过编码器值计算车轮速度
Get_Velocity_Form_Encoder(Encoder_Left,Encoder_Right);
Velocity_Pwm_L+=Velocity2(Velocity1,Encoder_Left+Encoder_Right);
Velocity_Pwm_R+=Velocity2(Velocity1,Encoder_Right);
Turn_Pwm=+Turn2(Turn1,Encoder_Left-Encoder_Right);
Motor_Left= Velocity_Pwm_L+ Turn_Pwm;
Motor_Right= Velocity_Pwm_L-Turn_Pwm ;
Motor_Left=PWM_Limit(Motor_Left,7666,-7666);
Motor_Right=PWM_Limit(Motor_Right,7666,-7666);
if( Flag_Stop == 0 )set_pwm(Motor_Left,Motor_Right);
else
{
Motor_Left=0;
Motor_Right=0;
Velocity_Pwm_L=0;
set_pwm(0,0);
}
// if( fabs(mpu6050.roll) > 50 || robotVol<9.5f ) Flag_Stop = 1;
}
}
static uint16_t Get_Vol(void)
{
static uint16_t adcVal = 0;
static uint8_t startflag = 0;
//转换未开始时,软件触发使能
if( startflag == 0 )
{
startflag=1;
DL_ADC12_startConversion(ADC12_0_INST);
}
if( getVolFlag )
{
getVolFlag = 0;
adcVal = DL_ADC12_getMemResult(ADC12_0_INST,DL_ADC12_MEM_IDX_0);
DL_ADC12_startConversion(ADC12_0_INST);
DL_ADC12_enableConversions(ADC12_0_INST);
}
return adcVal;
}
//ADC电压值获取完毕中断
void ADC12_0_INST_IRQHandler(void)
{
switch(DL_ADC12_getPendingInterrupt(ADC12_0_INST))
{
case DL_ADC12_IIDX_MEM0_RESULT_LOADED:
getVolFlag = 1;
break;
default:
break;
}
}
static void set_pwm(int left,int right)
{
if(left>0)
{
DL_GPIO_setPins(MOTOR_DIR_PORT,MOTOR_DIR_AIN1_PIN);
DL_GPIO_clearPins(MOTOR_DIR_PORT,MOTOR_DIR_AIN2_PIN);
}
else
{
DL_GPIO_clearPins(MOTOR_DIR_PORT,MOTOR_DIR_AIN1_PIN);
DL_GPIO_setPins(MOTOR_DIR_PORT,MOTOR_DIR_AIN2_PIN);
}
if(right>0)
{
DL_GPIO_setPins(MOTOR_DIR_PORT,MOTOR_DIR_BIN1_PIN);
DL_GPIO_clearPins(MOTOR_DIR_PORT,MOTOR_DIR_BIN2_PIN);
}
else
{
DL_GPIO_clearPins(MOTOR_DIR_PORT,MOTOR_DIR_BIN1_PIN);
DL_GPIO_setPins(MOTOR_DIR_PORT,MOTOR_DIR_BIN2_PIN);
}
DL_TimerA_setCaptureCompareValue(PWM_0_INST,abs(right),GPIO_PWM_0_C0_IDX);
DL_TimerA_setCaptureCompareValue(PWM_0_INST,abs(left),GPIO_PWM_0_C1_IDX);
}
static void Get_Velocity_Form_Encoder(int encoder_left,int encoder_right)
{
float Rotation_Speed_L,Rotation_Speed_R; //Motor speed, speed = encoder reading (5ms each time) * reading frequency/multiple frequency/deceleration ratio/encoder accuracy//电机转速,转速=编码器读数(5ms每次)*读取频率/倍频数/减速比/编码器精度
Rotation_Speed_L = encoder_left*Control_Frequency/EncoderMultiples/Reduction_Ratio/Encoder_precision;
Velocity_Left = Rotation_Speed_L*PI*Diameter_67; //Find the encoder speed = rotational speed * perimeter//求出编码器速度=转速*周长
Rotation_Speed_R = encoder_right*Control_Frequency/EncoderMultiples/Reduction_Ratio/Encoder_precision;
Velocity_Right = Rotation_Speed_R*PI*Diameter_67; //Find the encoder speed = rotational speed * perimeter//求出编码器速度=转速*周长
}
static int PWM_Limit(int IN,int max,int min)
{
int OUT = IN;
if(OUT>max) OUT = max;
if(OUT<min) OUT = min;
return OUT;
}
static int Balance(float Angle,float Gyro)
{
float Angle_bias,Gyro_bias;
int balance;
Angle_bias=MiddleAngle-Angle; //求出平衡的角度中值 和机械相关
Gyro_bias=0-Gyro;
balance=-Balance_Kp/100*Angle_bias-Gyro_bias*Balance_Kd/100; //计算平衡控制的电机PWM PD控制 kp是P系数 kd是D系数
return balance;
}
static int Velocity(int encoder_left,int encoder_right)
{
static float velocity,Encoder_Least,Encoder_bias,Movement;
static float Encoder_Integral,Target_Velocity=50;
//================遥控前进后退部分====================//
// if(Flag_follow==1||Flag_avoid==1) Target_Velocity = 30; //如果进入跟随/避障模式,降低速度
// else Target_Velocity = 50;
if(Flag_front==1) Movement=Target_Velocity/Flag_velocity; //收到前进信号
else if(Flag_back==1) Movement=-Target_Velocity/Flag_velocity; //收到后退信号
else Movement=0;
//=============超声波功能(跟随/避障)==================//
// if(Mode==Ultrasonic_Follow_Mode&&(Distance>200&&Distance<500)&&Flag_Left!=1&&Flag_Right!=1) //跟随
// Movement=Target_Velocity/Flag_velocity;
// if(Mode==Ultrasonic_Follow_Mode&&Distance<200&&Flag_Left!=1&&Flag_Right!=1)
// Movement=-Target_Velocity/Flag_velocity;
// if(Mode==Ultrasonic_Avoid_Mode&&Distance<450&&Flag_Left!=1&&Flag_Right!=1) //超声波避障
// Movement=-Target_Velocity/Flag_velocity;
//================速度PI控制器=====================//
Encoder_Least =0-(encoder_left+encoder_right); //获取最新速度偏差=目标速度(此处为零)-测量速度(左右编码器之和)
Encoder_bias *= 0.86; //一阶低通滤波器
Encoder_bias += Encoder_Least*0.14; //一阶低通滤波器,减缓速度变化
Encoder_Integral +=Encoder_bias; //积分出位移 积分时间:10ms
Encoder_Integral=Encoder_Integral+Movement; //接收遥控器数据,控制前进后退
if(Encoder_Integral>11000) Encoder_Integral=11000; //积分限幅
if(Encoder_Integral<-11000) Encoder_Integral=-11000; //积分限幅
velocity=-Encoder_bias*Velocity_Kp/100-Encoder_Integral*Velocity_Ki/100; //速度控制
if(Flag_Stop==1) Encoder_Integral=0;//电机关闭后清除积分
return velocity;
}
float Velocity2(float target,float encoder)
{
static float velocity,Encoder_Least,Encoder_bias,Movement;
static float Encoder_Integral,Target_Velocity=50;
//=============超声波功能(跟随/避障)==================//
// if(Mode==Ultrasonic_Follow_Mode&&(Distance>200&&Distance<500)&&Flag_Left!=1&&Flag_Right!=1) //跟随
// Movement=Target_Velocity/Flag_velocity;
// if(Mode==Ultrasonic_Follow_Mode&&Distance<200&&Flag_Left!=1&&Flag_Right!=1)
// Movement=-Target_Velocity/Flag_velocity;
// if(Mode==Ultrasonic_Avoid_Mode&&Distance<450&&Flag_Left!=1&&Flag_Right!=1) //超声波避障
// Movement=-Target_Velocity/Flag_velocity;
//================速度PI控制器=====================//
Encoder_Least =target-encoder; //获取最新速度偏差=目标速度(此处为零)-测量速度(左右编码器之和)
Encoder_Integral +=Encoder_bias; //积分出位移 积分时间:10ms
Encoder_Integral=Encoder_Integral+Movement; //接收遥控器数据,控制前进后退
if(Encoder_Integral>11000) Encoder_Integral=11000; //积分限幅
if(Encoder_Integral<-11000) Encoder_Integral=-11000; //积分限幅
velocity=-Encoder_Least*Velocity_Kp; //速度控制
if(Flag_Stop==1) Encoder_Integral=0;//电机关闭后清除积分
return velocity;
}
static int Turn(float gyro)//Steering control//转向控制
{
static float Turn_Target,turn,Turn_Amplitude=54;
float Kp=Turn_Kp,Kd=0; //To change the steering speed, modify Turn_Amplitude//修改转向速度,请修改Turn_Amplitude即可
//===================遥控左右旋转部分=================//
//=====Remote control left and right rotation part======//
if(1==Flag_Left) Turn_Target=-Turn_Amplitude/Flag_velocity;
else if(1==Flag_Right) Turn_Target=Turn_Amplitude/Flag_velocity;
else Turn_Target=0;
if(1==Flag_front||1==Flag_back) Kd=Turn_Kd;
else Kd=0; //The gyroscope correction is cancelled when the steering is done, somewhat obscuring the idea of PID//转向的时候取消陀螺仪的纠正 有点模糊PID的思想
//===================转向PD控制器=================//
//==============Steering PD controller=============//
turn=Turn_Target*Kp/100+gyro*Kd/100;//A Z-axis gyroscope is combined for PD control//结合Z轴陀螺仪进行PD控制
return turn; //The steering loop PWM turns positive to the right and negative to the left//转向环PWM右转为正,左转为负
}
static float Turn2(float Turn_Target,float V)//Steering control//转向控制
{
static float turn;
Turn_Target=Turn_Target-V;
turn=Turn_Kp*Turn_Target;//A Z-axis gyroscope is combined for PD control//结合Z轴陀螺仪进行PD控制
return turn; //The steering loop PWM turns positive to the right and negative to the left//转向环PWM右转为正,左转为负
}Related media相关媒体
Board photos, schematic sheets, videos, and test captures that show this project at specific stages.展示这个项目具体阶段的板卡照片、原理图分页、视频和测试截图。
Video视频Aiming while driving边跑边打靶
Video视频K230 detection testK230 识别测试
Rendering of the car, front整车渲染图,前侧
Rendering of the car, rear整车渲染图,后侧
Pin map for the MSPM0 and K230MSPM0 与 K230 的引脚分配
Power topology of the car整车电源拓扑
Entries at the Jiangsu judging venue江苏赛区测评现场的作品区
The balance car built during preparation备赛时做的双轮平衡车
Debugging with the oscilloscope during preparation备赛时用示波器调试
OLED lit up during preparation备赛时点亮的 OLED
The C07A core board that burned烧掉的那块 C07A 核心板
Our bench in the lab during the contest比赛期间我们在实验室的工位
Debugging on with flying wires板子烧了以后飞线接着调
The car on the track facing the target跑道上对着靶子的小车
The box sealed by the organisers组委会封条封好的箱子
The car packed for judging装箱待测的小车
Unpacking at the venue测评现场开箱
The car on the judging track测评跑道上的小车
The target sheet靶纸
The Jiangsu division backdrop江苏赛区背景板
The team at the Jiangsu division backdrop三人在江苏赛区背景板前
Award certificate获奖证书
The team at the SAT building三人在 SAT 楼前
The car on display with its certificate和证书一起展出的小车