树莓派救援机器人制作

   日期:2020-10-05     浏览:89    评论:0    
核心提示:前言:利用APP inventor构建一个APP作为客户端程序,利用Flask框架结合树莓派构建一个服务器端程序,两者间通信,制作出一个木质外壳结构、带有摄像头和机械臂,同时具备人脸检测和红外目标搜索功能的救援机器人。材料准备:横截面为边长1.5cm正方形的木条若干米、树莓派4B、BST-4WD拓展板、金属TT电机X4、金属舵机及必要配件X6、12.6V动力锂电池、3D打印齿轮X8、PCA9685舵机驱动板、人体热释红外传感器、手机X2、杜邦线若干条、废弃瓶盖若干硬件结构:软件原理:实物图:

前言:

利用APP inventor构建一个APP作为客户端程序,利用Flask框架结合树莓派构建一个服务器端程序,两者间通信,制作出一个木质外壳结构、带有摄像头和机械臂,同时具备人脸检测和红外目标搜索功能的救援机器人。

材料准备:

横截面为边长1.5cm正方形的木条若干米、树莓派4B、BST-4WD拓展板、金属TT电机X4、金属舵机及必要配件X6、12.6V动力锂电池、3D打印齿轮X8、PCA9685舵机驱动板、人体热释红外传感器、手机X2、杜邦线若干条、废弃瓶盖若干

硬件结构:

软件原理:

实物图:





实现功能:

1.通过点击APP上的方向按钮和速度调节滑动条来操纵机器人前、后、左、右、转向的运动以及速度调节。
2.通过点击APP的上摄像头云台控制按钮实现对摄像头方向的水平和垂直调节,并通过APP图像显示区域实时显示opencv采集并处理过的视频流,如果检测到人脸则对人脸进行矩形框标记,从而实现对环境和人脸的感知。
3.通过点击人脸检测按钮,opencv采集单张图像,然后调用百度人脸检测接口进行人脸检测,将返回的数据处理后发送到手机,最终实现在信息显示框查看年龄、性别、表情、是否佩戴口罩、配戴眼镜类型等检测数据,APP调用百度语音合成接口朗读以上数据的效果。
4.点击红外目标搜索按钮,开始进行生命体搜索,如果搜索到红外目标则APP语音合成提示信息。
5.通过点击机械臂控制按钮实现对4自由度机械臂的控制,从而达到机械臂抓取物体并放置到车体上带回的目的。

程序实现:

树莓派Python代码:

# main.py
from flask import Flask, render_template, Response,request
from camera import VideoCamera
from urllib.parse import urlencode
import urllib
import RPi.GPIO as GPIO
import Adafruit_PCA9685
import requests
import base64

#引脚定义
left_moto1=20
left_moto2=21
left_pwm=16

right_moto1=19
right_moto2=26
right_pwm=13

hongwai_pin=22

#变量定义
speed=0

pwm_left=None
pwm_right=None

servo_min = 150  
servo_max = 600  

pwm_servo=None

face_check_flag='0'

#图片存储路径
pic_path='/home/pi/wifi_car/test.jpg'
#百度AI appkey secretkey
ak="qTKX7mY59YeZ1GfiW0HYv1mK"
sk="UHu5yYuQahn7L4DGxPYhi1WL6v5tjnXm"
data_str='收到此检测消息表明人脸检测功能正常,请正式开始使用!'

#初始化函数
def init():
    GPIO.setmode(GPIO.BCM)
    GPIO.setwarnings(False)
    GPIO.setup(left_pwm,GPIO.OUT,initial=GPIO.HIGH)
    GPIO.setup(left_moto1,GPIO.OUT,initial=GPIO.LOW)
    GPIO.setup(left_moto2,GPIO.OUT,initial=GPIO.LOW)
    GPIO.setup(right_pwm,GPIO.OUT,initial=GPIO.HIGH)
    GPIO.setup(right_moto1,GPIO.OUT,initial=GPIO.LOW)
    GPIO.setup(right_moto2,GPIO.OUT,initial=GPIO.LOW)
    GPIO.setup(hongwai_pin,GPIO.IN)
   
    global pwm_left
    global pwm_right
    pwm_left = GPIO.PWM(left_pwm, 2000)
    pwm_right = GPIO.PWM(right_pwm, 2000)
    
    global pwm_servo
    pwm_servo = Adafruit_PCA9685.PCA9685()
    pwm_servo.set_pwm_freq(60)
    

#前进函数
def car_forward():
    GPIO.output(left_moto1,GPIO.HIGH)
    GPIO.output(left_moto2,GPIO.LOW)
    GPIO.output(right_moto1,GPIO.HIGH)
    GPIO.output(right_moto2,GPIO.LOW)
    pwm_left.start(speed)
    pwm_right.start(speed)

#后退函数
def car_back():
    GPIO.output(left_moto1,GPIO.LOW)
    GPIO.output(left_moto2,GPIO.HIGH)
    GPIO.output(right_moto1,GPIO.LOW)
    GPIO.output(right_moto2,GPIO.HIGH)
    pwm_left.start(speed)
    pwm_right.start(speed)

#左转函数
def car_left():
    GPIO.output(left_moto1,GPIO.LOW)
    GPIO.output(left_moto2,GPIO.HIGH)
    GPIO.output(right_moto1,GPIO.HIGH)
    GPIO.output(right_moto2,GPIO.LOW)
    pwm_left.start(speed)
    pwm_right.start(speed)

#右转函数
def car_right():
    GPIO.output(left_moto1,GPIO.HIGH)
    GPIO.output(left_moto2,GPIO.LOW)
    GPIO.output(right_moto1,GPIO.LOW)
    GPIO.output(right_moto2,GPIO.HIGH)
    pwm_left.start(speed)
    pwm_right.start(speed)

#停止函数
def car_stop():
    GPIO.output(left_moto1,GPIO.LOW)
    GPIO.output(left_moto2,GPIO.LOW)
    GPIO.output(right_moto1,GPIO.LOW)
    GPIO.output(right_moto2,GPIO.LOW)

#获取百度AI access_token
def getAccess_token(AK,SK):
    host = "https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id="+AK+"&client_secret="+SK
    response = requests.get(host)
    access_token=''
    if response:
        dict=response.json()
        access_token=dict.get("access_token","none")
        #print(dict.get("access_token","none"))
        
    return access_token

#图片进行base64编码函数
def Base64(img_path):
    with open(img_path, 'rb') as f:
        image_data = f.read()
        base64_data = base64.b64encode(image_data)  # base64编码
        string=str(base64_data,"utf-8")
        # print(string)
        
    return string

#请求数据函数
def request_post(base64_code,access_token):
    request_url = "https://aip.baidubce.com/rest/2.0/face/v3/detect"
    #请求参数 年龄 性别 表情 口罩 眼镜
    params={ 'image':''+base64_code+'','image_type':'BASE64','face_field':'age,gender,expression,mask,glasses'}
    params=urlencode(params)
    request_url = request_url + "?access_token=" + access_token
    request = urllib.request.Request(url=request_url,data=params.encode("utf-8"))
    request.add_header('Content-Type', 'application/json')
    response = urllib.request.urlopen(request)
    content = response.read()
    
    return content

#返回数据处理
def baidu_api(path,ak,sk):
    global data_str
    base64_code = Base64(path)
    token=getAccess_token(ak,sk)
    data_set=request_post(base64_code,token)
    print('**********************')
    print(data_set)
    print('**********************')
    string=bytes.decode(data_set)
    #print(string)
    dict_data=eval(string)
    dict_data2=dict_data.get("result","none")
    dict_data3=dict_data2.get("face_list","none")
    dict_data4=dict_data3[0]
    age=dict_data4.get("age","none")
    age_str="年龄:"+str(age)+","
    print(age_str)
    # beauty=dict_data4.get("beauty","none")
    # beauty_str="beauty:"+str(beauty)
    # print(beauty_str)
    gender=dict_data4.get("gender","none").get("type","none")
    gender_str="性别:"+str(gender)+","
    print(gender_str)
    glasses=dict_data4.get("glasses","none").get("type","none")
    glasses_str="眼镜类型:"+str(glasses)+","
    print(glasses_str)
    mask=dict_data4.get("mask","none").get("type","none")
    mask_str="是否佩戴口罩:"+str(mask)
    print(mask_str)
    expression=dict_data4.get("expression","none").get("type","none")
    expression_str="表情:"+str(expression)+","
    print(expression_str)
    
    data_str=age_str+gender_str+glasses_str+expression_str+mask_str

#flask
app = Flask(__name__)

#默认路由
@app.route('/')
def index():
    
    return render_template('index.html')
 
def gen(camera):
    global face_check_flag
    while True:
        if face_check_flag=='1':
            camera.save_pic()#保存图像
            print("save pic OK")
            baidu_api(pic_path,ak,sk)
            face_check_flag='0'
        
        frame = camera.get_frame()
        yield (b'--frame\r\n'
               b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n\r\n')

#获取视频流路由 
@app.route('/video_feed')
def video_feed():
    
    return Response(gen(VideoCamera()),
                    mimetype='multipart/x-mixed-replace; boundary=frame')

#人脸检测路由
@app.route('/face_check',methods=['GET'])
def face_check():
    global face_check_flag
    data=request.args.get('data')
    print('The data is :',data)
    #print("Type is :",type(data))
    face_check_flag=data
        
    return data_str

#运动控制路由
@app.route('/sport',methods=['GET'])
def sport():
    data=request.args.get('data')
    if data=='forward':     
        car_forward()
    if data=='back':
        car_back() 
    if data=='left':
        car_left()
    if data=='right':
        car_right()
    if data=='stop':
        car_stop()
    

    print("the data is :",data)
    #print(type(data))
    
    return 'Sport OK'

#速度调节路由
@app.route('/speed',methods=['GET'])
def getSpeed():
    data=request.args.get('data')
    global speed
    speed=float(data)
    
    return 'Speed OK'

#舵机1控制路由 
@app.route('/servo1',methods=['GET'])
def getServo1():
    data=request.args.get('data')
    angle=int(data)
    servo_val=int(450/270*angle)+150 
    pwm_servo.set_pwm(1,0,servo_val)
    
    return 'Servo1 OK'

#舵机2控制路由 
@app.route('/servo2',methods=['GET'])
def getServo2():
    data=request.args.get('data')
    angle=int(data)
    servo_val=int(450/270*angle)+150 
    pwm_servo.set_pwm(2,0,servo_val)
    
    return 'Servo2 OK'

#舵机3控制路由 
@app.route('/servo3',methods=['GET'])
def getServo3():
    data=request.args.get('data')
    angle=int(data)
    servo_val=int(450/270*angle)+150 
    pwm_servo.set_pwm(3,0,servo_val)
    
    return 'Servo3 OK'

#舵机4控制路由 
@app.route('/servo4',methods=['GET'])
def getServo4():
    data=request.args.get('data')
    angle=int(data)
    servo_val=int((servo_max-servo_min)/270*angle)+150 
    pwm_servo.set_pwm(4,0,servo_val)
    
    return 'Servo4 OK'

#摄像头云台水平调节路由 
@app.route('/camera_horizon',methods=['GET'])
def get_cam_horizon():
    data=request.args.get('data')
    angle=int(data)
    servo_val=int(450/270*angle)+150 
    pwm_servo.set_pwm(5,0,servo_val)
    
    return 'camera_horizon OK'

#摄像头云台垂直调节路由 
@app.route('/camera_vertical',methods=['GET'])
def get_cam_vertical():
    data=request.args.get('data')
    angle=int(data)
    servo_val=int(450/270*angle)+150 
    pwm_servo.set_pwm(6,0,servo_val)
    
    return 'camera_vertical OK'

#红外检测路由
@app.route('/hongwai',methods=['GET'])
def hongwai():
    if GPIO.input(hongwai_pin)==True:
	    print("hongwai_OK")
	    return "hongwaiok"
    else:
	    print("hongwai_ERROR")
	    return "hongwaierror"
        
if __name__ == '__main__':

    #初始化函数调用
    init()
    #flask运行
    app.run(host='192.168.43.180' ,port=8123, debug=True)
        

        
    

# camera.py
import cv2 as cv

#IP摄像头地址
camera_url='http://admin:admin@192.168.43.73:8081'


class VideoCamera(object):
    #实例视频流获取对象
    def __init__(self):
        self.video = cv.VideoCapture(camera_url)
 
    def __del__(self):
        self.video.release()

    #图像保存函数 
    def save_pic(self):
        ret, image = self.video.read()
        cv.imwrite('/home/pi/wifi_car/test.jpg',image)
    
    #获取视频流帧 处理
    def get_frame(self):
        success, frame = self.video.read()
        
        gray=cv.cvtColor(frame,cv.COLOR_BGR2GRAY)
        #opencv级联分类器检测
        face_cascade = cv.CascadeClassifier("data/haarcascade_frontalface_alt.xml")
        faces=face_cascade.detectMultiScale(gray,scaleFactor=1.2,minNeighbors=4,flags=cv.CASCADE_SCALE_IMAGE,minSize=(100, 100),maxSize=(250,250))
        # print(faces)
        
        #矩形框标记人脸
        for (x,y,w,h) in faces:
            frame= cv.rectangle(frame,(x,y),(x+w,y+h),(255,255,0),2)
            
        ret, jpeg = cv.imencode('.jpg', frame)
        
        return jpeg.tobytes()

<!--index.html 视频显示页面-->
<html>
  <head>
    <title>Video Streaming Demonstration</title>
  </head>
  <body>
    
    <img src="{ { url_for('video_feed') }}" width="100%" height="120%">
  </body>
</html>

APP inventor代码块(部分):



结束语:

受树莓派引脚和拓展板的限制,加装更多的传感器很不方便,在Arduino上安装传感器,利用串口将数据发送给树莓派理论上应当可行,但是在实际的编程中要将读取功能放在Flask里面,这却未能达到理想效果,因此这是一个待改进的地方。

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服