简 介: 本文给出了多车软件使用说明。多车软件及其配套的计时器硬件和线圈,用于第十七届全国大学生智能车竞赛的多车组。
关键词
: 多车组,智能车竞赛
§01 多车组软件
在第十七届全国大学智能汽车竞赛竞速比赛中,包括有多车组,它要求测量多车前后两次通过比赛起跑线上的时间差来比较车模编队前后的距离。
一、背景介绍
在多车组比赛计时软件中,需要部署两套计时系统,一个是记录总比赛时间,另外一个是记录多车通过起跑线时的时间差。记录比赛总时间的比赛系统,它的部署与其他组别是相同的,在车库门口设置一个计时线圈或者计时光带,记录车模从车库驶出和驶入之间的时间差。记录比赛时间差则使用另外单独的计时系统和比赛系统,它会自动记录多车通过时前后车模之间的时间差,并乘以比率 5 进行显示。
▲ 图1.1 线圈部署示意图
二、时间差计时系统
时间差计时系统使用龙邱的单独一个计时线圈和相应的计时软件。
1、计时器和计时线圈
用于测量时间差的计时器也是基于 ESP32 的单片机系统,但它内部的 Python 程序是经过修改后的程序。其中四个拨码开关的设置如下图所示。
-
计时器拨码开关设置:
-
开关1
:OFF,这一位开关决定电磁线圈触发灵敏度
开关2
:ON
开关3
:OFF
开关4
:OFF
▲ 图1.2.1 计时器内部拨码开关设置
2、计时软件
计时器模块通过 TypeC USB 连线与计算机相连, 计算机需要安装 CH340 USB 驱动软件 。 安装后,可以在 可以在计算机惯例-设备管理-端口 中看到 USB-SERIAL CH340 (COM n) 。 其中 COMn 是计算机分配给 USB 窗口号。 建议将 COM 号修改到 1 ~ 8 之间。
PC 软件使用智能车竞赛比赛裁判系统-22-7-12。 由于只需要测量两次前后车模通过起跑线时的时间差,所以该软件是独立使用。 程序启动后直接在“时间差” 页面完成计时器清零和计时工作。
▲ 图1.2.2 计时软件界面
(1)软件设置
软件设置有三个参数。
1. 串口设置并打开 :根据前面 USB 对应的串口端口, 在打开串口 后面选择对应的串口端口,然后按动打开串口按钮,此时界面右上角接收数字会递增;
2. 设置最大延时:这个数字缺省情况下是 10秒钟;
3. 设置时间比率:根据本届比赛规则,延迟时间是按照 5 倍的比例进行显示;
▲ 图1.2.3 软件连接计时模块后,打开串口对应的接受数字就会递增
3、软件使用
比赛开始,首车和尾车从车库出发之后,按动“清零”按钮,界面数字显示时间为 0.
当车队运行一周之后,第一次通过计时线圈,软件根据计时器返回的数字计算出头车与尾车之间的时间差,使用 5 倍的比率进行显示。
当车队创二次通过计时线圈,软件继续测量头车与尾车之间的时间差,并累加前面时间差,使用 5 倍比率进行显示。
最后将改时间与比赛系统记录的运行时间叠加之后作为最终的比赛成绩。
※ 总 结 ※
本文给出了多车软件使用说明。多车软件及其配套的计时器硬件和线圈,用于第十七届全国大学生智能车竞赛的多车组。
一、ESP32软件
from machine import UART,Pin,Timer,ADC,PWM
import time
import machine, math
machine.freq(240000000)
adc1 = ADC(Pin(36))
adc2 = ADC(Pin(39))
adc3 = ADC(Pin(34))
adc4 = ADC(Pin(35))
adc1.atten(ADC.ATTN_6DB)
adc2.atten(ADC.ATTN_6DB)
adc3.atten(ADC.ATTN_6DB)
adc4.atten(ADC.ATTN_6DB)
button = Pin(32, Pin.IN, Pin.PULL_UP)
sw4 = Pin(15, Pin.IN, Pin.PULL_UP)
sw3 = Pin(2, Pin.IN, Pin.PULL_UP)
sw2 = Pin(19, Pin.IN, Pin.PULL_UP)
sw1 = Pin(4, Pin.IN, Pin.PULL_UP)
led1 = Pin(5, Pin.OUT)
led2 = Pin(18, Pin.OUT)
led1.off()
led2.off()
bz1 = Pin(21, Pin.OUT)
bz1.off()
gled = Pin(25, Pin.OUT)
rled = Pin(33, Pin.OUT)
speaker = Pin(26, Pin.OUT)
gled.off()
rled.off()
speaker.off()
def sw1234Read():
workmode = 0
if sw2.value() == 0: workmode |= 0x1
if sw3.value() == 0: workmode |= 0x2
if sw4.value() == 0: workmode |= 0x4
return sw1.value(), workmode
WORKMODE_TIMER = 0 # Check two line
WORKMODE_NULL1 = 1 #
WORKMODE_NULL2 = 2 #
WORKMODE_NULL3 = 3 #
WORKMODE_FRUIT = 4 # Target is fruit, check laser
WORKMODE_ANIMAL = 5 # Target is Animal, check laser
WORKMODE_DIGIT1 = 6 # Target is digit, check first pass
WORKMODE_DIGIT2 = 7 # Target is digit, check first pass
SAMPLE_NUM = const(500)
ad1dim = [0] * SAMPLE_NUM
ad2dim = [0] * SAMPLE_NUM
LASER_THRESHOLD = 50000 # Laser light check threshold
SAMPLE_AVERAGE_LENGTH = 40
ad3average = [0] * SAMPLE_AVERAGE_LENGTH
ad4average = [0] * SAMPLE_AVERAGE_LENGTH
ad34point = 0
ad3sigma = 0
ad4sigma = 0
AD34_BASE_ALPHA = 0.0005
ad3baseline = 0
ad4baseline = 0
AD34_CHECK_THRESHOLD_LOW = 250
AD34_CHECK_THRESHOLD_HIGH = 500
AD34_CHECK_THRESHOLD = AD34_CHECK_THRESHOLD_HIGH
ad3checktime = 0
ad4checktime = 0
sample_mode = 0 # 0 : sample adc3, adc4
sample_point = 0
stop_flag = 0
total_count = 0
uart1 = UART(2, baudrate=115200, rx=16, tx=17, timeout=10)
DSCMD_NONE = 0xff
DSCMD_HELLO = 0x00
DSCMD_INIT = 0x01
DSCMD_STARTSEND = 0x10
DSCMD_STOPSEND = 0x11
DSCMD_BEEP = 0x12
DSCMD_SENDSNAPSHOT = 0x13
DSCMD_TURNOFFLIGHT = 0x14
DSCMD_SETCONTINUECHECK = 0x15
DSCMD_SETBEACONSEQUENCY = 0x16
DSCMD_BEACONSTART = 0x17
DSCMD_BEACONSTOP = 0x18
DSCMD_GETBEACONSTATE = 0x19
DSCMD_BEACONINIT = 0x1a
DSRET_NCHECK = 0x80
DSRET_CHECK = 0x81
DSRET_LAST = 0x82
DSRET_HELLO = 0x90
DSRET_INIT = 0x91
SENDFLAG_LAST = 0x82
SENDFLAG_CHECK = 0x81
SENDFLAG_NOCHECK = 0x80
SENDFLAG_STOP = 0xff
SENDFLAG_SNAPSHOT = 0x83
def receCmd():
if uart1.any() == 0: return DSCMD_NONE,0
framebyte = uart1.read(4)
if len(framebyte) != 4: return DSCMD_NONE, 0
framelist = list(framebyte)
time = int.from_bytes(framebyte[1:3], 'big')
sumnum = sum(framelist[0:3]) & 0xff ^ 0xff
if sumnum != framelist[3]: return DSCMD_NONE, 0
return framelist[0], time
def sendCmd(cmd, time):
senddim = [0x55,cmd]
senddim.extend(list(time.to_bytes(4, 'big')))
sumnum = sum(senddim)&0xff^0xff
senddim.extend([sumnum])
sendbytes = bytes(senddim)
uart1.write(sendbytes)
def procCmd(cmd, time):
global count32,sendflag,delay3s,count32,sendenableflag
global initflag,lastcount32,snapshot32,speakercount,senddelay,sendcount
if cmd == DSCMD_NONE: return
if cmd == DSCMD_HELLO:
sendCmd(DSRET_HELLO, 0x0)
return
if cmd == DSCMD_INIT:
sendCmd(DSRET_INIT, 0x0)
count32 = 0x0
delay3s = time
count3s = time
initflag = 1
lastcount32 = 0
snapshot32 = 0
sendcount = 0
sendenableflag = 1
sendflag = SENDFLAG_STOP
return
if cmd == DSCMD_STARTSEND:
sendCmd(SENDFLAG_LAST, lastcount32)
count3s = delay3s
sendflag = 0x0
sendenableflag = 0x1
senddelay = time
sendcount = 0
return
if cmd == DSCMD_STOPSEND:
sendCmd(SENDFLAG_CHECK, count32)
sendenableflag = 0
sendflag = 0
sendcount = 0
return
if cmd == DSCMD_BEEP:
speakercount = 500
return
if cmd in (DSCMD_SETBEACONSEQUENCY,
DSCMD_BEACONSTART,
DSCMD_BEACONSTOP,
DSCMD_GETBEACONSTATE,
DSCMD_TURNOFFLIGHT,
DSCMD_BEACONINIT):
return
print(cmd, time)
speakercount = 0
flash50mscount = 0
flash50inc = 0
resultflag = 0 # 1 :OK; 2:ERROR; 0:NULL
buzzcount = 00
def resultOK():
global resultflag, speakercount, flash50mscount, flash50inc
resultflag = 1
speakercount = 4500
flash50mscount = 0
flash50inc = 0
def resultERROR():
global resultflag, speakercount, flash50mscount, flash50inc
resultflag = 2
speakercount = 4500
flash50mscount = 0
flash50inc = 0
def speaker1ms():
global resultflag, speakercount, flash50mscount, flash50inc
global detectflag1, detectflag2, detectcount, buzzcount
if detectflag1 != detectflag2:
detectcount += 1
if buzzcount > 0:
buzzcount -= 1
if speakercount > 0:
speakercount -= 1
if speakercount == 0:
if resultflag > 0:
resultflag = 0
rled.off()
gled.off()
flash50mscount += 1
if flash50mscount >= 50:
flash50mscount = 0
flash50inc += 1
if resultflag == 0:
speaker.on()
elif resultflag == 1:
gled.on()
speaker.on()
elif resultflag == 2:
if flash50inc & 0x1 == 0:
rled.on()
speaker.on()
else:
rled.off()
speaker.off()
def sendTime():
global count32,snapshot32,lastcount32,sendflag
if sendflag == SENDFLAG_STOP:
return
if initflag == 0: return
if keepWorkMode > 0:
sendCmd(sendflag, snapshot32)
sendflag = SENDFLAG_STOP
return
timesend = count32
if sendflag == SENDFLAG_LAST:
timesend = lastcount32
elif sendflag == SENDFLAG_CHECK or sendflag == SENDFLAG_NOCHECK:
timesend = count32
elif sendflag == SENDFLAG_SNAPSHOT:
timesend = snapshot32
sendCmd(SENDFLAG_SNAPSHOT, snapshot32)
sendflag = SENDFLAG_NOCHECK
elif keepWorkMode > 0:
timesend = count32
sendCmd(SENDFLAG_SNAPSHOT, snapshot32)
sendflag = SENDFLAG_NOCHECK
sendCmd(sendflag, timesend)
sendflag = SENDFLAG_STOP
count32 = 0 # Global 1ms counter
sendflag = SENDFLAG_STOP # send flag
sendenableflag = 0 # Enable send
senddelay = 100 # Everay send period
sendcount = 0 # count for send delay
delay3s = 3000 # No check delay
count3s = 3000 # count for no check delay
initflag = 0
lastcount32 = 0
snapshot32 = 0
detectflag1 = 0 # Stand for line1 check
detectflag2 = 0 # Stand for line2 check
detectcount = 0 # Count the detectflag1 detectflag2 no equal
def ADC4Sample(_):
global count32,sendenableflag,sendflag,senddelay,sendcount
global delay3s,count3s,initflag,lastcount32,snapshot32
global speakercount, keepWorkMode
global detectflag1, detectflag2, buzzcount
count32 += 1
speaker1ms()
if keepWorkMode == 0:
if count32 & 0x100:
led1.on()
else: led1.off()
else:
if count32 & 0x80:
led1.on()
else: led1.off()
if sendenableflag != 0:
sendcount += 1
if sendcount >= senddelay:
sendcount = 0
if sendflag == SENDFLAG_STOP:
if count32 < delay3s:
sendflag = SENDFLAG_NOCHECK
else: sendflag = SENDFLAG_CHECK
else:
sendcount += 1
if sendcount >= senddelay:
sendcount = 0
if sendflag == SENDFLAG_STOP:
sendflag = SENDFLAG_CHECK
global ad1dim,ad2dim
global sample_point
global adc1,adc2,adc3, adc4
global ad3average, ad4average, ad34point, ad3sigma, ad4sigma
global ad3checktime, ad4checktime,total_count
global ad3baseline, ad4baseline
total_count += 1
detectflag = 0
if sample_mode == 1:
ad1dim[sample_point] = adc1.read()
ad2dim[sample_point] = adc2.read()
if sample_mode == 0 or sample_mode == 1:
adc = adc3.read()
ad3sigma += adc
ad3sigma -= ad3average[ad34point]
ad3average[ad34point] = adc
adc = adc4.read()
ad4sigma += adc
ad4sigma -= ad4average[ad34point]
ad4average[ad34point] = adc
ad34point += 1
if ad34point >= SAMPLE_AVERAGE_LENGTH:
ad34point = 0
value = ad3sigma / SAMPLE_AVERAGE_LENGTH
if ad3baseline == 0:
if ad34point == SAMPLE_AVERAGE_LENGTH - 1:
ad3baseline = value
else: ad3baseline = ad3baseline * (1 - AD34_BASE_ALPHA) +AD34_BASE_ALPHA * value
if abs(value - ad3baseline) > AD34_CHECK_THRESHOLD:
if ad3checktime == 0:
ad3checktime = total_count
detectflag = 1
detectflag1 = 1
if keepWorkMode == 6 or keepWorkMode == 7:
gled.on()
value = ad4sigma / SAMPLE_AVERAGE_LENGTH
if ad4baseline == 0:
if ad34point == SAMPLE_AVERAGE_LENGTH - 1:
ad4baseline = value
else: ad4baseline = ad4baseline * (1 - AD34_BASE_ALPHA) + AD34_BASE_ALPHA * value
if abs(value - ad4baseline) > AD34_CHECK_THRESHOLD:
if ad4checktime == 0:
ad4checktime = total_count
detectflag = 1
detectflag2 = 1
if keepWorkMode == 6 or keepWorkMode == 7:
rled.on()
sample_point += 1
if sample_point >= SAMPLE_NUM:
sample_point = 0
if detectflag > 0:
buzzcount = 100
bz1.on()
if count3s >= delay3s:
if sendenableflag > 0:
if detectflag > 0:
count3s = 1
lastcount32 = count32
snapshot32 = coutn32
if keepWorkMode == 0:
count32 = 0
sendflag = SENDFLAG_LAST
else:
if detectflag > 0:
snapshot32 = count32
count3s = 1
else:
if detectflag > 0:
snapshot32 = count32
count3s += 1
time0 = Timer(0)
time0.init(period=1, mode=Timer.PERIODIC, callback=ADC4Sample)
showcount = 0
keepThreshold,keepWorkMode = sw1234Read()
def initDevice():
global sample_mode, detectflag1, detectflag2, detectcount
global speakercount, flash50mscount, flash50inc, resultflag, buzzcount
speakercount = 0
buzzcount = 50
flash50mscount = 0
flash50inc = 0
resultflag = 0 # 1 :OK; 2:ERROR; 0:NULL
detectflag1 = 0
detectflag2 = 0
detectcount = 0
print("Initialize device:%d,%d"%(keepThreshold, keepWorkMode))
if keepThreshold == 1:
AD34_CHECK_THRESHOLD = AD34_CHECK_THRESHOLD_LOW
else:
AD34_CHECK_THRESHOLD = AD34_CHECK_THRESHOLD_HIGH
led1.off()
led2.off()
bz1.off()
gled.off()
rled.off()
speaker.off()
if keepWorkMode in (4, 5):
sample_mode = 1 # Sample adc1,2,3,4
else: sample_mode = 0 # Sample adc3,4
SAMPLE_PERIOD = 1
FREQUENCY_MOD = 125
def angle1(n):
return n*2*3.1415926*SAMPLE_PERIOD / 1000.0 * FREQUENCY_MOD
def wval(w):
if w < SAMPLE_NUM / 2:
return w * 2 / SAMPLE_NUM
else: return (SAMPLE_NUM - w) * 2 / SAMPLE_NUM
cosdim = [int(math.sin(angle1(a)) * wval(a) * 0x7ff) for a in range(SAMPLE_NUM)]
sindim = [int(math.cos(angle1(a)) * wval(a) * 0x7ff) for a in range(SAMPLE_NUM)]
def sample_amp(s):
global cosdim,sindim,sample_point
cos_sam = 0
sin_sam = 0
scopy = s.copy()
if sample_point > 0:
scopy = scopy[sample_point:] + scopy[:sample_point]
cos_sum = sum([s*w for s,w in zip(scopy,cosdim)]) / SAMPLE_NUM
sin_sum = sum([s*w for s,w in zip(scopy,sindim)]) / SAMPLE_NUM
return math.sqrt(cos_sum**2 + sin_sum**2)
initDevice()
while True:
threshold, workmode = sw1234Read()
if threshold != keepThreshold or workmode != keepWorkMode:
keepThreshold = threshold
keepWorkMode = workmode
initDevice()
if button.value() == 0:
time.sleep(0.01)
if button.value() == 0:
initDevice()
while button.value() == 0:
speakercount = 10
time.sleep(.01)
if keepWorkMode == 4: # Fruit mode
check1 = sample_amp(ad1dim)
check2 = sample_amp(ad2dim)
print((check1, check2))
if check1 > LASER_THRESHOLD:
if resultflag == 0:
resultOK()
detectflag1 = 0
detectflag2 = 0
if check2 > LASER_THRESHOLD:
if resultflag == 0:
resultERROR()
detectflag1 = 0
detectflag2 = 0
if detectcount > 10000:
detectflag1 = 0
detectflag2 = 0
detectcount = 0
bz1.on()
buzzcount = 200
if detectflag1 > 0 and detectflag2 > 0:
if resultflag == 0:
resultERROR()
detectflag1 = 0
detectflag2 = 0
detectcount = 0
if keepWorkMode == 5: # Animal mode
check1 = sample_amp(ad1dim)
check2 = sample_amp(ad2dim)
if check1 > LASER_THRESHOLD:
resultERROR()
if check2 > LASER_THRESHOLD:
resultERROR()
if detectcount > 6000:
detectflag1 = 0
detectflag2 = 0
detectcount = 0
bz1.on()
buzzcount = 200
elif detectcount > 3000:
bz1.on()
buzzcount = 50
if detectflag1 > 0 and detectflag2 > 0:
if detectcount < 2500:
resultERROR()
else: resultOK()
detectflag1 = 0
detectflag2 = 0
detectcount = 0
if resultflag != 0:
detectflag1 = 0
detectflag2 = 0
detectcount = 0
if speakercount == 0:
speaker.off()
if buzzcount == 0:
bz1.off()
showcount += 1
if showcount > 50:
showcount = 0
cmd,tm = receCmd()
if cmd != DSCMD_NONE:
led2.on()
procCmd(cmd, tm)
led2.off()
sendTime()
time.sleep_ms(1)
■ 相关文献链接:
● 相关图表链接: