会员们脑洞打开说要搞个无人小车,目标自动环汇智湖,捡钱,夏天吹妹子裙底。
坑就这样挖好了,第一个实验版本就先室内搞起吧。
经过群里的吵架,项目就开始。第一个版本先在室内跑。
激光雷达(闲鱼二手货,土豪可以在df商城买那个好用,资料齐全,直接支持ros)
树莓派3b+(这里有坑 Ubuntu mate不支持 ros安装不方便)
减速电机 机器人底盘(还没开始 没型号推荐哈哈)
硬件链接部分:
看文档就是motor的1脚接到lds的4脚,motor的2脚接到lds的6脚
然后整个激光雷达就是 :6接5v ,3接gnc ,5和2接串口。
数据部分:
看到数据长度为42bytes
0 为sync就是同步头,固定值为0xfa
1 是degree 换算算法是 angle=angle index*6+angle offset,angleindex的取值范围是:0xA0~0xDB (也就是0~60)因为每组数据包含6组距离 所以 60*6正好是360度的数 据。
2、3 是转速
4~9 是第一组数据 前面4、5是强度,6、7 是距离,8、9是保留,这里的数据要注意大小端。
40、41 是checksum
2.激光雷达与树莓派接线说明
树莓派 | LDS | 4 | vcc | 6 | gnd | 8 | TX | 10 | RX |
树莓派开启串口需要进行设置,串口开启后 蓝牙就失效了,大家自己看着选择吧,想保留蓝牙就用usb转ttl线。
下面是开启串口的py脚本,写的懒,不接受review,python3。
- import os
- #<a href="mailto:Question_h@sina.com" target="_blank">Question_h@sina.com</a> 2019.03.18
-
- def execCmd(cmdstr):
- pipeline = os.popen(cmdstr)
- print(pipeline.read())
-
- def isConfig():
- with open('/boot/config.txt','r+') as fd:
- linetmp=fd.readline()
- while linetmp:
- if linetmp=="dtoverlay=pi3-miniuart-bt":
- print('config ok')
- fd.close()
- return True
- linetmp=fd.readline()
- fd.write("linetmp=fd.readline()")
- fd.close()
- return False
-
- def isCmdline():
- strlists=None
- with open('/boot/cmdline.txt','r+') as fd:
- strlists=fd.readlines()
- fd.close()
- for i in range(len(strlists)):
- flagstart=strlists<i>.find("console=serial0,115200 ")
- if flagstart:
- strlist=strlists<i>
- print('cmdline ok')
- strlists<i>=strlist[0:flagstart]+strlist[flagstart+23:]
- with open('/boot/cmdline.txt','w') as fd:
- fd.writelines(strlists)
- fd.close()
- return True
- return False
-
- isConfig()
- execCmd("sudo systemctl stop <a href="mailto:serial-getty@ttyAMA0.service" target="_blank">serial-getty@ttyAMA0.service</a>")
- execCmd("sudo systemctl disable <a href="mailto:serial-getty@ttyAMA0.service" target="_blank">serial-getty@ttyAMA0.service</a>")
- isCmdline()</i></i></i>
复制代码
3.雷达数据接收并且通过tcp传到笔记本进行画图
下面是树莓派端代码(python3):
- import sys,getopt,time
- import serial
- import queue
- #from queue import Queue
- import socket
- import signal
- import json
- import threading
- import binascii
- #BaudRate 230400
- ldread = True
- lddata = queue.Queue()
- #sockfs=None
- #serip='127.0.0.1'
- #serport = 80
-
- def tcpcli(serip,serport):
- print(serip,serport)
- try:
- sockfs=socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sockfs.connect((serip,int(serport)))
- except socket.error as msg:
- print(msg)
- sockfs.close()
- return sockfs
-
- def senddata(serip,serport,lddata):
- print('senddata')
- sockfd=tcpcli(serip,serport)
- while(True):
- try:
- datatmp = lddata.get(timeout=5.0)
- sockfd.send((json.dumps(datatmp)).encode('utf-8'))
- except queue.Empty:
- continue
- except socket.error as msg:
- print(msg)
- sockfd.close()
- sockfd=tcpcli(serip,serport)
- continue
- sockfs.close()
-
-
- def openser(device,lddata):
- print('openser')
- datalist=[]
- datadict={}
- ldser=serial.Serial(device, 230400, timeout=1)
- ldser.write(b'b')
- i=0
- #for i in range(0,60):
- while(True):
- if ldread:
- sync=ldser.read()
- if sync and sync[0]==0xfa: #找到数据头
- distlist=[]
- ldtmp=ldser.read(41)
- #print(binascii.b2a_hex(ldtmp))
- degree=(ldtmp[0]-0xa0)*6
- for i in range(0,6):
- distdict={}
- #print("degree:%d,dist:%d,data[%d]:%x,data[%d]:%x"%(degree+i,ldtmp[6+6*i]*0xff+ldtmp[5+6*i],5+6*i,ldtmp[5+6*i],6+6*i,ldtmp[6+6*i]))
- distdict["degree"]=degree+i
- distdict["dist"]=ldtmp[6+6*i]*0xff+ldtmp[5+6*i]
- distlist.append(distdict)
- datadict['data']=distlist
- #print(datadict)
- lddata.put(datadict)
- #sockfd.send((json.dumps(datadict)).encode('utf-8'))
-
-
- else:
- i=i+1
- if i>60:
- print("can't find sync,drop data",sync,type(sync))
- #lddata.put(i)
- i=0
- else:
- ldser.write(b'e')
- ldser.close()
- #lddata.put("1")
-
-
- def usage():
- print("lider 1.0.0 - (C) 2019 Question\n\n-d device\n-h hostnma\n-p tcp port\n")
-
- def main():
- serip='127.0.0.1'
- serport=80
- device=None
- try:
- opts, args = getopt.getopt(sys.argv[1:], "-d:-h:-p:",["help","version"])
- for op, value in opts:
- if op == "-d":
- device = value
- elif op == "-h":
- #hostname = value
- serip=value
- elif op == "-p":
- serport = value
- except getopt.GetoptError:
- usage()
- sys.exit()
- threads = []
- t1 = threading.Thread(target=openser,args=(device,lddata))
- threads.append(t1)
- t2 = threading.Thread(target=senddata,args=(serip,serport,lddata))
- threads.append(t2)
- for t in threads:
- t.setDaemon(True)
- t.start()
- t.join()
- #time.sleep(10)
- #sockfd=tcpcli(serip,serport)
- #openser(sockfd,device)
- print("serial:%s,hostname:%s,tcp port:%s"%(device,serip,serport))
- #lddata.get()
-
- if __name__ == '__main__':
- main()
复制代码
运行命令:python3 lidar.py -d /dev/ttyUSB0 -h 172.16.201.93 -p 20002
4.笔记本用 matplotlib显示点图,第一次用matplotlib 写的不好 还有bug,退出报错,大家自己改着玩吧。
- import socket
- import threading
- import time
- import queue
- import json
- import matplotlib.pyplot as plt
- #from matplotlib.animation import FuncAnimation
- import matplotlib.animation as animation
- import math
- import numpy as np
-
- carsocket=[]
- lddata = queue.Queue()
- distdict={}
- dot={}
- fig = plt.figure(figsize=(8, 8)) #设置画布 600*600 貌似不设置会变形
- ax = fig.add_subplot(111)
- ax.set(xlim=[-4000, 4000], ylim=[-4000, 4000], title='lidar',
- ylabel='Y-Axis', xlabel='X-Axis')
-
- for i in range(0,360):
- dot<i>, = ax.plot([], [],'b,')
-
- def init():
- #ax.set_xlim(-2, 2)
- #ax.set_ylim(-2, 2)
- plt.scatter(0, 0, color='red', marker='+')
- #x_out = [r_out*np.cos(theta<i>) for i in range(len(theta))]
- #y_out = [r_out*np.sin(theta<i>) for i in range(len(theta))]
- #ln1.set_data(x_out, y_out)
- return None
-
-
- def update(i):
- global distdict
- for i in range(0,360):
- xp=int(distdict<i>)*math.sin(math.radians(i))
- yp=int(distdict<i>)*math.cos(math.radians(i))
- dot<i>.set_data(xp,yp)
- #plt.scatter(xp, yp, color='black', marker='.')
-
- return
-
-
-
- def carser(port):
- datatmp=''
- csok=socket.socket(socket.AF_INET,socket.SOCK_STREAM,0)
- csok.bind(('0.0.0.0',port))
- csok.listen(5)
- print("小车接收数据socket进入监听:")
- while True:
- clients,addr = csok.accept()
- print("小车发送,地址: %s" % str(addr))
- #carsocket.append(clients)
-
- while clients:
- try:
- datatmp=datatmp+clients.recv(100).decode()
- jsonflag=datatmp.find("}{"data":")
- if jsonflag >0:
- #print(datatmp[0:jsonflag+1])
- lddata.put(json.loads(datatmp[0:jsonflag+1]))
- datatmp=datatmp[jsonflag+1:]
- except Exception as e:
- #print('28',datatmp[0:jsonflag+1])
- print (e,str(jsonflag),datatmp[0:jsonflag+1])
- except socket.error as msg:
- break
- except KeyboardInterrupt:
- print("KeyboardInterrupt---")
- break
- csok.close()
-
-
- def handledata(maxx,maxy):
- global distdict
- while True:
- try:
- datatmp = lddata.get(timeout=5.0)
- datalist=datatmp['data']
- print(distdict)
- for dl in datalist:
- distdict[int(dl["degree"])]=int(dl["dist"])
- #print(type(datatmp))
- except queue.Empty:
- continue
-
-
-
-
-
- def main():
-
- threads = []
- t1 = threading.Thread(target=carser,args=(8000,))
- threads.append(t1)
- t2 = threading.Thread(target=handledata,args=(4000,4000))
- threads.append(t2)
-
- for t in threads:
- t.setDaemon(True)
- t.start()
-
- plt.scatter(0, 0, color='red', marker='+')
- ani = animation.FuncAnimation(fig, update, 100, init_func=init, interval=10)
- #ani.save('roll.gif', writer='imagemagick', fps=100)
-
- plt.show()
- '''
- t.join()
- print ("退出主线程")
- '''
- if __name__ == '__main__':
- main()</i></i></i></i></i></i>
复制代码
5.效果图
十字是激光雷达的位置 红色圈是墙,箭头是我的椅子哈哈
|