使用树莓派让你的“哑巴”汽车更智能!灵感我喜欢智能汽车的想法,但我很难证明购买一辆全新的汽车只是为了获得一些花里胡哨的东西。目前,我被我的“哑巴”车困住了,但这并不意味着我不能自己尝试让它变得更聪明!“智能汽车”这个词可以有几十种不同的含义,这取决于你问的是谁。那么让我们从我对智能购物车的定义开始:触摸屏界面倒车摄像头可让您知道物体是否太近有关汽车的基本信息,例如燃油效率也许蓝牙连接?我不确定这些项目中的哪些(如果有)我会取得成功,但我想我们会知道的。备用相机我们想要的智能汽车的第一个明显补充是备用摄像头。有许多套件可以让添加备用摄像头变得非常简单。但是他们中的大多数需要对汽车本身进行修改,而且由于我只是想测试概念验证,我真的不想开始拧开并钻入我的汽车。像这样的相机的一个警告是它们需要外部电源。通常规定将它们连接到您汽车的倒车灯之一,以便在汽车倒车时自动打开电源。由于我现在不想改装我的车,我只是打算将它连接到一些电池上。我会用可靠的旧胶带将它安装到车牌上!我将RCA电缆从相机连接到仪表板并将其连接到我的5'LCD。这个特定的LCD可以通过USB供电,所以我将它插入了USB打火机适配器(大多数旧车都有打火机适配器)。启动汽车后,屏幕立即亮起,我可以看到相机的图像。像宣传的那样工作!对于只想在他们的汽车上添加备用摄像头并且不希望它有任何花里胡哨的人来说,这将是一个很好的解决方案。不过,我认为我可以做得更好。进入树莓派。Pi是智能汽车的完美平台,因为它基本上是一台具有大量输入和输出的微型计算机。将相机连接到Pi时,您几乎可以使用任何通用USB网络摄像头,或者您可以使用PiCamera。这两款相机都不需要单独的电源。但只要确保您有足够的电缆连接到汽车后部即可。我选择了Pi相机,因为它比USB相机具有更高的吞吐量。同样,我只是将相机用胶带粘在车牌上,将扁平电缆连接到汽车前部的Pi,然后将其连接到7"触摸屏。Pi和触摸屏都可以通过USB适配器供电在车里。打开汽车,树莓派和屏幕都通电了。一个明显的缺点是Pi启动所需的启动时间……稍后我将不得不考虑这一点。为了查看Picam,我打开了终端并运行了一个简单的脚本(将来可以设置为自动启动的脚本)按回车键后,弹出了一个摄像机的提要!Pi上的视频的好处在于您可以对其进行分析,甚至可以在物体离得太近时设置警报系统!那么接下来让我们继续努力吧!物体检测方法一说到商用备用摄像机,我看到的一般有两个版本。第一个使用带有颜色范围的静态叠加,以便您可以直观地确定对象的接近程度。第二种方法是将摄像头与某种类型的传感器结合使用,可以感应物体与汽车的距离,然后在物体太近时提醒您。由于第一种方法似乎更容易,让我们先尝试一下。从本质上讲,它只是在视频流顶部过度播放的图像,所以让我们看看重新创建它是否像听起来一样简单。我们需要的第一件事是透明的图像叠加。上面的图像正好是640x480,恰好与我的相机将流式传输的分辨率相同。这是有意完成的,但如果您以不同的分辨率流式传输,请随时更改图像尺寸。接下来,我们将创建一个使用PILpython图像编辑器和PiCamera的Python脚本(如果您没有使用Pi相机,则调整视频输入的代码)。我只是将文件命名为image_overlay.py保存它并通过运行“pythonimage_overlay.py”对其进行测试,我使用玩具车对其进行了小规模测试,以了解其工作原理。将其装入车内并运行程序,结果同样迷人!然而,需要注意的一件非常重要的事情是,您在校准相机时应该特别小心,以确保视频视图的底部尽可能靠近汽车保险杠。如下图所示,相机朝向太高,因此测试对象实际上比相机告诉我的要远得多。方法二方法1测试非常成功,但它也非常基础。如果有一个系统可以检测物体与汽车的距离并在距离太近时通知您,那就太好了。正如我之前提到的,大多数具有该功能的汽车都使用可以检测物体的外部传感器。我不太热衷于在我的汽车上添加任何其他外部设备,所以我要看看我是否可以使用计算机视觉检测物体。我可以使用OpenCV和python作为我的计算机视觉API。这将使我能够分析图像中的内容并为找到的内容设置参数。因此,我们的想法是拍摄视频片段并在底部(靠近汽车保险杠)设置“警报区域”的边界。然后我会让它检测镜头中的任何大物体。如果对象的最底部区域进入“警报区域”,则应发送警报消息。作为警报声,我将通过将正极连接到引脚22,将负极连接到接地引脚,将压电蜂鸣器连接到RaspberryPi。在开始编写代码之前,我们必须先在Pi上安装OpenCV。幸运的是Pi可以通过Python的“pip”命令来做到这一点一旦安装了OpenCV,我们就可以创建一个新的Python文件并开始编写代码。对于完整记录的代码,您可以访问下方的链接。我只是将我的文件命名为car_detector.pyimporttimeimportcv2importnumpyasnpfrompicamera.arrayimportPiRGBArrayfrompicameraimportPiCameraimportRPi.GPIOasGPIObuzzer=22GPIO.setmode(GPIO.BCM)GPIO.setup(buzzer,GPIO.OUT)camera=PiCamera()camera.resolution=(320,240)#asmallerresolutionmeansfasterprocessingcamera.framerate=24rawCapture=PiRGBArray(camera,size=(320,240))kernel=np.ones((2,2),np.uint8)time.sleep(0.1)forstillincamera.capture_continuous(rawCapture,format="bgr",use_video_port=True):GPIO.output(buzzer,False)image=still.array#createadetectionareawidthAlert=np.size(image,1)#getwidthofimageheightAlert=np.size(image,0)#getheightofimageyAlert=(heightAlert/2)+100#determineycoordinatesforareacv2.line(image,(0,yAlert),(widthAlert,yAlert),(0,0,255),2)#drawalinetoshowarealower=[1,0,20]upper=[60,40,200]lower=np.array(lower,dtype="uint8")upper=np.array(upper,dtype="uint8")#usethecolorrangetocreateamaskfortheimageandapplyittotheimagemask=cv2.inRange(image,lower,upper)output=cv2.bitwise_and(image,image,mask=mask)dilation=cv2.dilate(mask,kernel,iterations=3)closing=cv2.morphologyEx(dilation,cv2.MORPH_GRADIENT,kernel)closing=cv2.morphologyEx(dilation,cv2.MORPH_CLOSE,kernel)edge=cv2.Canny(closing,175,175)contours,hierarchy=cv2.findContours(closing,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)threshold_area=400centres=[]iflen(contours)!=0:forxincontours:#findtheareaofeachcontourarea=cv2.contourArea(x)#findthecenterofeachcontourmoments=cv2.moments(x)#weedoutthecontoursthatarelessthanourthresholdifarea>threshold_area:(x,y,w,h)=cv2.boundingRect(x)centerX=(x+x+w)/2centerY=(y+y+h)/2cv2.circle(image,(centerX,centerY),7,(255,255,255),-1)if((y+h)>yAlert):cv2.putText(image,"ALERT!",(centerX-20,centerY-20),cv2.FONT_HERSHEY_SIMPLEX,0.5,(255,255,255),2)GPIO.output(buzzer,True)cv2.imshow("Display",image)rawCapture.truncate(0)key=cv2.waitKey(1)&0xFFifkey==ord("q"):GPIO.output(buzzer,False)break好的,保存并小规模测试,效果很好。它检测到很多不必要的物体,我确实注意到有时它会将阴影检测为物体。将其装入汽车并在真实世界场景中进行测试,结果出人意料地准确!然而,这是接近完美的条件。如果是在晚上,我不知道结果会如何变化。总的来说,我对结果感到高兴和惊讶,但我不会在不太理想的条件下相信它。这并不是说它不起作用,只是说它目前是基本代码,可以进行更多的测试和调试(希望读者!)在这两种方法中,方法2很酷,但方法1在多种情况下肯定更可靠。所以如果你要为你的车做这个,我会选择方法1。接下来,我将尝试连接到汽车的OBDII端口,看看我能提取什么!连接到车载诊断(OBDII)在美国,自1996年以来,汽车一直被要求具有车载诊断端口(OBDII)。其他国家稍后采用了相同的标准。OBDII端口允许您连接到它并读取有关汽车的信息,例如问题、VIN号码、速度、RPM等。每当您的“检查引擎”灯亮起时,机械师就会插入它以找出问题所在是并清除问题。我们需要做的第一件事是将适配器连接到端口,以便我们可以从RaspberryPi与其通信。对于那些不知道的人,在大多数汽车中,OBDII端口位于方向盘下方的仪表板下方。如果您在网上搜索“ODBII适配器”,您会发现主要有两种类型的适配器:USB和蓝牙。USB适配器更安全,但如果您了解蓝牙中的漏洞以及如何解决这些漏洞,则可以使用该适配器。将蓝牙适配器连接到端口,您可能会注意到适配器上的灯立即亮起。这是因为OBD端口具有“始终开启”的12v输出。这意味着蓝牙适配器将始终处于供电和活动状态,即使您不在车内......因此存在漏洞。蓝牙适配器就位后,我们现在可以将我们的Pi连接到它。我一直在使用内置蓝牙的RaspberryPi3B+,所以我不需要任何其他适配器。只需打开pi,打开终端并启动蓝牙控制器。在控制器中,按顺序输入这些命令(减去#注释)此时,适配器应该已连接,您应该回到主终端线路。由于OBD端口是一个串口,在我们开始与它通话之前,我们需要将它绑定到Pi上的一个串口。第二组值用于参数ID。有将近200种不同的可用PID,同样可以在这个Wikipedia页面上找到。在这里我们可以询问温度、速度、RPM等。对于这个测试,我将要求速度,所以我的十六进制值为0D。制作图形界面现在我们有了数据,我们需要一种更好、更有趣的方式来显示它。由于我最熟悉Python,因此我将使用它来操作数据。在网上,我找到了一个专门用于OBD连接的很棒的库,称为Python-OBD。所以我和PySerial一起安装了它。好吧,python-OBD库可以工作,但它仍然不是图形化的。要在Python中制作图形界面,有几个选项可供选择。我熟悉的几个是:PyQT特金特游戏Pygame既快速又简单,因此我将在本教程中使用它。更方便的是,Pygame预装在树莓派上,所以无需额外安装任何东西!好吧,让我们试一试。这是我用于显示的最终代码obd_hud_test.pyimportpygamefrompygame.localsimport*importobdpygame.init()#connection=obd.OBD()connect=obd.Async(fast=False)screen=pygame.display.set_mode((0,0),pygame.FULLSCREEN)screen_w=screen.get_width()screen_h=screen.get_height()circle_y=screen_h/2circle1_x=screen_w*.25circle2_x=screen_w*.5circle3_x=screen_w*.75circle_rad=(circle2_x-circle1_x)/2speed_text_x=screen_w*.25speed_text_y=screen_h*.25rpm_text_x=screen_w*.5rpm_text_y=screen_h*.25load_text_x=screen_w*.75load_text_y=screen_h*.25headerFont=pygame.font.SysFont("Arial",50)digitFont=pygame.font.SysFont("Arial",50)white=(255,255,255)black=(0,0,0)grey=(112,128,144)speed=0rpm=0load=0defdraw_hud():screen.fill(grey)pygame.draw.circle(screen,black,(int(circle1_x),int(circle_y)),int(circle_rad),5)pygame.draw.circle(screen,black,(int(circle2_x),int(circle_y)),int(circle_rad),5)pygame.draw.circle(screen,black,(int(circle3_x),int(circle_y)),int(circle_rad),5)speed_text=headerFont.render("SPEED",True,black)rpm_text=headerFont.render("RPM",True,black)load_text=headerFont.render("LOAD",True,black)speed_text_loc=speed_text.get_rect(center=(speed_text_x,speed_text_y))rpm_text_loc=rpm_text.get_rect(center=(rpm_text_x,rpm_text_y))load_text_loc=load_text.get_rect(center=(load_text_x,load_text_y))screen.blit(speed_text,speed_text_loc)screen.blit(rpm_text,rpm_text_loc)screen.blit(load_text,load_text_loc)defget_speed(s):globalspeedifnots.is_null():#speed=int(s.value.magnitude)#forkphspeed=int(s.value.magnitude*.060934)#formphdefget_rpm(r):globalrpmifnotr.is_null():rpm=int(r.value.mangitude)defget_load(l):globalloadifnotl.is_null():load=int(l.value.mangitude)connection.watch(obd.commands.SPEED,callback=get_speed)connection.watch(obd.commands.RPM,callback=get_rpm)connection.watch(obd.commands.ENGINE_LOAD,callback=get_load)connection.start()running=Truewhilerunning:foreventinpygame.event.get():ifevent.type==KEYDOWN:ifevent.key==K_ESCAPE:connection.stop()connection.close()running=Falseelifevent.type==QUIT:connection.stop()connection.close()running=Falsedraw_hud()speedDisplay=digitFont.render(str(speed),3,white)rpmDisplay=digitFont.render(str(rpm),3,white)loadDisplay=digitFont.render(""+str(load)+"%",3,white)screen.blit(loadDisplay,(circle3_x-(circle3_x/8),circle_y-45))screen.blit(rpmDisplay,(circle2_x-(circle2_x/8),circle_y-45))screen.blit(speedDisplay,(circle1_x-(circle1_x/8),circle_y-45))pygame.display.update()pygame.display.flip()添加GPS尽管大多数智能设备已经集成了GPS,但我认为专用的GPS导航系统将是我们智能汽车设置的完美补充。常见的GPS系统通常由两部分组成,一个是GPS加密狗,用于从卫星检索坐标,另一个是将这些坐标覆盖在地图上的地图绘制系统。对于RaspberryPi,您可以使用USB加密狗,或通过Pi的GPIO引脚连接的加密狗。你可以花10到40美元买到一个好的。只需确保您选择的加密狗与RaspberryPi兼容。由于我已经有一个USBGPS加密狗,我将使用它。在大多数情况下,插入GPS应该可以工作,但对我来说,我必须进行一些故障排除才能使其正常工作。首先我必须安装一些GPSD包,然后我运行“cgps-s”来检查连接状态。原来的:更改后:保存,并重新启动GPS服务,我再次测试,终于开始看到结果!现在是地图系统。大多数移动地图系统需要无线数据连接才能下载地图。但是为RaspberryPi获得无线数据连接是我不想承担的每月额外费用。因此,在网上寻找与RaspberryPi兼容的离线地图系统时,没有太多选择。真的,唯一可行的方法是Navit。如果您对此项目有任何想法、意见或问题,请在下方留言。原文链接丨以上内容来源网络,如涉及侵权可联系删除。