Raspbot改造远程联网监控

既然$Raspbot$小车上面既有摄像头又有轮子,那么也许可以尝试做一个可以遥控行驶的监控器,这样即可非常方便地远程观察家中的情况,甚至脱离了固定监控的位置限制,它可以去到各个房间探查。下面就是实现这个功能的完整过程。 设备联网 (注:电脑上需要下载的应用有VNCviewer以及nmap,其中nmap可以通过其官网直接下载安装,而VNCviewer可以通过RealVNC官网安装,如果连接不上官网,可以在亚博智能网站提供的资源中下载远程登录软件.zip文件,解压后同样可以找到VNCviewer的安装包) 如果想要通过网络对小车进行控制,首先要让小车联网。本身按照官方的说法,直接用手机App中的配网按钮,生成一个专用的联网二维码,放到小车摄像头面前扫描即可,但这种方式实测并不可靠,本身如果有一根Micro-HDMI转HDMI的传输线,就可以把小车主板直接接到显示器上面,选择网络连接即可,但如果手头并没有线,必须通过远程才能访问到小车的桌面,那么就需要按照以下步骤联网: 用一根网线直接插入主板上的网线连接口,和路由器连接,强制通过有线连接的方式让它联网; 将电脑连入和小车同样的网络,运行ipconfig命令,找到WLAN的IPV4地址,可以发现显示的是一个形似A.B.C.D的局域网地址,记下四个数字,并将下文中的字母均替换为查询到的数字; 由于此时小车已经有线连接在同一个网络下,故在命令行中运行nmap -sn A.B.C.1/24命令,即可查找和电脑连接在同一网络下的所有设备。此时nmap会默认在括号中打印出设备的制造商和其局域网地址,找到括号中写着Raspberry Pi (Trading)的设备,下面的IPV4一栏即为小车的局域网地址; 打开VNCviewer,在左上角File一栏中找到New Connection,点击添加新的连接,并在弹出对话框的VNCserver一栏中填写刚刚查到的小车局域网地址,Name中填上Raspbot,其他默认即可,点击OK; 这时VNCviewer的主页中新增了一个名为Raspbot的设备,双击即可进入小车的桌面啦!至此,远程访问小车系统就已经实现了。 在小车桌面的左上角点击命令行的图标,打开命令行,开始设置无线网卡的联网: 运行以下命令,查询附近可用网络,这时会列出附近的网络名称和信号强度,如果要连接的网络在显示的列表中,即可连接; sudo nmcli device wifi list 按q退出网络查找模式,运行以下命令,将无线网卡连入网络:(注意双引号不要删掉了) sudo nmcli device wifi connect "你的WiFi名称" password "你的WiFi密码" ifname wlan0 如果连接成功,命令行就会返回: Device 'wlan0' successfully activated with 'X-X-X-X-X'. 这时,在小车的命令行中运行ifconfig,找到wlan0对应的信息,其中第二行的inet后面即为小车无线联网的局域网IPV4地址了,此时,再在VNCviewer中新建一个连接,将无线联网的这个地址输入VNCserver,重新取个名字,这样,就算将网线拔了,双击这个新增的设备也可以通过局域网无线访问小车桌面了! 但这时如果重启小车,它依然会优先进入热点模式而非连接网络,所以需要修改小车系统中连接网络和开启热点的优先级,用以下命令: sudo nmcli connection modify "你的WiFi名称" connection.autoconnect-priority 10 sudo nmcli connection modify "Raspbot" connection.autoconnect-priority 1 第一句设置连接wifi的优先级为10,第二句设置开启热点的优先级为1,提高wifi优先级,即可保证小车开机首选自动连接wifi。 至此,小车启动自连网设置完毕。 搭建网页 联网之后就需要选择一个信号传输的方式,我个人认为搭建一个网页并通过网络发送信号是最方便的,当然可以开发一个手机App,再通过网络连接小车,但这就和亚博智能官方的应用没什么区别了,甚至还更麻烦。以下就是搭建网页的步骤。 这里通过python第三方包flask进行网页搭建,这样,只需要在树莓派中运行一个.py文件,即可打开一个地址类似A.B.C.D:X的端口,其中A.B.C.D是小车自己的IP地址,而X则是一个可以在flask中自定义的一个端口编号,这样,只需用手机访问这个网址,即可开始和小车进行信号传输。 我的小车网页总共分四部分:主页、遥控页面、人脸识别页面、聊天室,其中: 主页集成了监控画面和三个功能页面的跳转按钮; 遥控页面中功能较多,集成了以下功能: 监控画面; 摄像头角度控制; 小车行驶控制; 蜂鸣器控制; 抓拍并下载监控当前画面; 人脸识别页面在进入时,小车会将摄像头转到几个设定的角度,寻找人脸,在找到人脸后自动调整摄像头角度使得人脸居于画面中央,并在对应人脸上标明绿色方框,如果人脸已经录入在人脸数据库中则会在方框右上角标注人名; 聊天室中集成以下功能: 发送信息,记录并显示聊天历史; 根据发送信息的IP地址不同,调用不同的人声对信息进行阅读; 可在后台修改不同IP对应的昵称,用于聊天历史的显示。 下面是具体代码,注意这些网页均需要用.py文件和.html文件联合搭建。 一些基本搭建网页的代码如下: python语句: from flask import Flask, request, render_template, url_for, Response, send_file, jsonify # 初始化网页对象,之后所有网页地址对应功能的实现都需要靠它 app = Flask(__name__) # @app.route(path)命令需要配合在其下方的函数一起执行,表示当网址"A.B.C.D:X"+path被访问的时候,下方的函数就会开始运行。传入path表示网页路径,单一的"/"表示根目录 @app.route("/") def home(): # render_template函数中传入的是当前要渲染的网页对应html文件的名字,通常文件结构如下: # │————当前.py文件 # └────templates # │————homePage.html # └────所有html文件均在templates目录下 return render_template("homePage.html") # 以下语句需要写在@app.route()语句下面的函数中 # 返回一个字典化的东西,使得html可以读取到函数返回的信息 return jsonify({"status":"ok"}) # 当html在运行时转到了类似:A.B.C.D:X/something?button=xxx的网址时,"?"后面的东西相当于对python函数中给出了一些变量,必须通过request.args.get()语句获得,并且里面填入的名称必须和传入的变量名相同 button = request.args.get("button") # 实现抓拍并下载监控当前画面功能时,需要用到send_file命令,它会将抓拍下来的照片tmp.jpg作为网页附件发送给手机并自动开始下载,其中download_name表示手机下载时的图片名 send_file('tmp.jpg', as_attachment=True, download_name=curTime+'.jpg') # 实现实时预览监控画面的功能时,需要用到Response函数,其中generate_frames()函数是自己定义的一个获取图像并用yield函数生成数据流的函数,后面的mimetype告诉了浏览器这个地方需要用多个图像不断替换的 return Response( generate_frames(), mimetype="multipart/x-mixed-replace; boundary=frame" ) # 可以在下面的函数中写入资源释放的语句,例如car.Car_Stop(),当Ctrl+C中断程序时就会自动执行该函数 def cleanup_and_exit(signum, frame): sys.exit(0) signal.signal(signal.SIGINT, cleanup_and_exit) signal.signal(signal.SIGTERM, cleanup_and_exit) # 这一句放在if __name__ == "__main__":中,启动网页,开启5000端口 app.run(host = '0.0.0.0', port = 5000, use_reloader = False) html语句: ...

Raspbot拍照实现(带预览)

这辆小车最有特色的地方就是它的摄像头以及由此派生出来的视觉处理程序,因此玩视觉的前提就是先将小车的摄像头调用出来,查看它的图像信息。在程序中,可以利用小车自带的$picamera2$库中的函数对摄像头进行读取,具体实现代码如下。 初始化摄像头 from picamera2 import Picamera2, Preview picam2 = Picamera2() # 获取摄像头组件信息,准备好之后调用 调整颜色及方向 摄像头默认的读取参数并不能直接用在显示照片的函数中,两者的不同之处主要有以下几点: 由于安装时的物理问题,摄像头默认是倒过来装的,因此如果直接读取并显示,就会出现照片被旋转了180°的情况; 摄像头对颜色的处理默认是按照$RGB$格式进行转换的,但用$cv2$展示图片时却是按照$BGR$格式进行展示的,因此如果直接读取并显示,就会出现颜色混乱的情况,配色极不正常。 解决上述问题有两种调整方式,一种是直接配置摄像头读取图像时的参数,一种是先按照默认的配置读取图像,之后对读取到的图像用$cv2$库进行调整。 方案1:配置摄像头参数 这里可以直接利用$picam2$和$libcamera$自带的配置函数对摄像头读取参数进行配置。 比较奇怪的一点是,摄像头本身确实是用$RGB$格式读取信息的,这与$cv2$展示时的格式不符合,但在代码中仍然要规定format:RGB888,这是因为根据官方文档的下面一段表述可知,为了让$cv2$用户用得更加方便,在自定义颜色读取时所写的$RGB$实际上代表着底层读取时要用$BGR$。这确实容易让人搞混。 cameraConfig = picam2.create_preview_configuration( main={"format":"RGB888", # 这就是比较奇怪的地方 "size":(picWidth, picHeight)} # 设定摄像头读取图片时的大小 ) cameraConfig["transform"] = libcamera.Transform(vflip=1, hflip=1) # 规定读取图片时将图像旋转180度,即左右和上下均进行翻转。vflip表示垂直翻转,hflip表示上下翻转 picam2.configure(cameraConfig) # 设定完配置后一定要用这句话启用配置! 方案2:读取照片后操作 若已经按照默认参数读取了照片,则需用$cv2$库中自带的函数进行转换。 frame = picam2.capture_array() # 先获取一帧 frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR) # 将RGB格式转为BGR格式 frame = cv2.flip(frame, -1) 增加预览功能 上面只是说了拍照如何实现,但如果只是拍一张照片,在此之前其实并不能知道摄像头的取景框现在在哪里,有多大,能不能拍全,因此最好加一个拍照前预览几秒的功能。这个功能同样有两种方式可以实现,一种是直接在程序中调用命令行中的预览指令,一种是自己写一个可以持续几秒钟的无限循环。 方案1:模拟命令行执行预览指令 这里需要用到$python$自带的模拟命令行的库以及树莓派提供的预览指令,具体实现如下: import subprocess # 可以模拟在命令行中执行指令 subprocess.run(['rpicam-vid', '-t', '5000', '--vflip', '1', '--hflip', '1']) # 调用树莓派自带的预览指令,其中-t后的数字表示预览持续多少毫秒,--vflip后的数字表示是否进行垂直翻转,--hflip后的数字表示是否进行水平翻转 方案2:编写循环实现 本质上和视频是一个道理,间隔一定时间后更新一帧图片,只要时间间隔足够短,就可以营造出视频的效果,而自定义持续时间即可用$time$库的时间戳之差控制循环的结束。 需要注意的是,如果采用这种方案,必须先采用上面「调整颜色及方向」中的方案1,提前对摄像头进行配置,否则会按照默认的参数进行显示。 import time startTime = time.time() # 获取开始时的时间戳 while time.time()-startTime < 5: # 当预览到达5秒时结束预览 cur = picam2.capture_array() # 获取当前帧 # 将当前帧更新到创建的Preview窗口中,不必担心创建很多窗口,因为imshow函数是根据窗口名称进行更新的 cv2.imshow('Preview', cur) cv2.waitKey(1) # 等待1毫秒,让新的一帧加载到窗口中 cv2.destroyAllWindows() # 删除预览窗口,等待拍照 写入照片文件 写入照片文件非常简单,只需要调用$cv2$中自带的$imwrite$函数即可将照片写入对应名称的文件中。 ...

Pico2小车初始化及功能简介

配置主板 拿到小车,首先将它组装好,然后即可开始配置$Pico2$主板,总共需要下载两个文件,一个是配置$micropython$的$.uf2$文件,一个是官方自带的$pico\_car.py$文件。 下载后,将主板接入电脑,然后会弹出一个类似U盘的文件,首先将$.uf2$文件直接复制到U盘中,这时它会自动重新启动,配置$micropython$环境,之后就会被电脑识别成一个端口,可以通过系统的设备管理器中的端口(COM和LPT)栏目下看到新增的端口,这就是小车的主板,并且在此之后不需要将它作为U盘操作,直接连入电脑,用编辑器写指令即可。 之后是编辑器,为了更方便地控制小车执行指令,需要下载一个Thonny编辑器,在这个编辑器中可以通过上方栏目中的工具->选项->解释器中将解释器设置为MicroPython (Raspberry Pi Pico),这样,在将主板接入电脑后,Thonny就会自动识别该主板,在下方的Shell窗口执行指令即可直接被小车运行。 两个文件均可从官方下载网址中进行下载。 小车基本功能 板载LED灯 该功能可控制$Pico2$主板上的LED灯开关,具体代码如下: import time import machine led_onboard = machine.Pin(25, machine.Pin.OUT) led_onboard.value(1) # 开启LED灯 time.sleep(1) # 等待1秒 led_onboard.value(0) # 关闭LED灯 板载温度传感器 该功能可以利用主板上的温度传感器读取当前环境温度,具体代码如下: import machine sensor_temp = machine.ADC(29) # 29号接口可以传递温度信号 conversion_factor = 3.3 / (4096-1) # 读数与实际温度之间转换因子 reading = sensor.read_u16()*conversion_factor # 读取并转换为实际温度 无源蜂鸣器 该功能可以控制小车车尾部的蜂鸣器发出声音,具体代码如下: from machine import Pin, PWM BZ = PWM(Pin(22)) # 22号针脚连接蜂鸣器,通过发射PWM信号可控制其工作 BZ.duty_u16(500) # 设定为大于0的整数即为开启蜂鸣器,数字越大,蜂鸣器的响度越大 BZ.freq(330) # 设定频率 # CM = [0, 330, 350, 393, 441, 495, 556, 624] 这是各个音调的频率,从1到7 BZ.duty_u16(0) # 设定为0,蜂鸣器关闭 小车灯光 该功能可以独立控制小车下方的总共8个灯的亮度以及颜色,具体代码如下: import time from pico_car import ws2812b # ws2812b为每个灯的芯片名称 num_leds = 8 # 总共8个灯 pixels = ws2812b(num_leds, 0) # 初始化控制灯光的变量 pixels.set_pixel(0, 0, 255, 255) # 将0号灯的RGB设置为(0,255,255) # set_pixel中,第一个变量为灯的编号,其余3个分别为颜色的RGB值,取值从0到255 pixels.show() # 注意!只有执行了这一句话,设定的灯才会亮! time.sleep(1) pixels.set_pixel(0, 0, 0, 0) # 关闭0号灯 小车OLED屏幕显示 该功能可以控制小车外挂的OLED屏幕上面显示文字,具体代码如下: ...