树莓派救援机器人制作

前言:

利用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里面,这却未能达到理想效果,因此这是一个待改进的地方。

基于Arduino leonardo主控器4轮驱动智能小车概述: Arduino四轮驱动智能小车是一款面向教育的集成机器人,将Arduino leonardo主控器、优质电机动力系统、电机驱动和传感器集成到109*122mm的空间之上。让玩家不用耗费精力在繁琐的组装和调试上,从而集中精力发挥自己的想象。 另外,小车利用Arduino IDE编程,是目前世界上最普及的硬件入门编程软件。即使没有任何技术背景,也能快速入门,掌控小车的操控。 下面的文档中具备8节课程,让玩家循序渐进的学习。教程和代码包下载见附件内容。 课程1:小车入门 课程2:控制蜂鸣器 课程3:蜂鸣器播报光线方向 课程 4:小车巡线程序 :小车巡线程序 课程 5:RGBRGB 灯的使用 课程 6:小车避障程序 :小车避障程序 课程 7:编码器的使用 :编码器的使用 课程8:红外遥控小车 4WD mini型集成了以下功能: 红外发射管:发射红外信号,用于物体探测等 光敏二极管:用于检测是否有光照,使小车进行巡光运动等 红外接收管:接收红外发射管发射出的红外信号 按键:用于输入信号给小车,以控制小车 全彩LED灯:可以使用程序使其发出不同颜色的光,可用于装饰或者程序调试等 USB程序下载与通讯接口:下载程序会使用到,在调试时可以和电脑通讯观察程序运行状况 蜂鸣器(无源):发出报警声或音乐等 控制器:运行编写程序的芯片 电机:通过控制电机的不同动作,使小车前进后退或转弯 重启按键;使小车的程序重新运行 电源开关按键:开关小车电源 电源接口:给整个小车供电 电池充电接口:如果使用的是充电电池,可以直接用这个口给电池充电。 红外巡线传感器 四轮智能小车参数如下: 重量: 350g 工作电压: 4.5--6V Bootloader: Arduino Leonardo 巡线传感器x5 光敏二极管 x2 硅胶软质按键 WS2812 RGB LED 通信端口IIC,Micro USB 尺寸: 109*122mm N20电机规格 工作电压:3V或6V 6V空载转速:15000 rpm 齿轮箱减速比:30:1 6V负载转速:500 rpm6V 电流:40mA@6V 堵转电流:100mA@6V 力矩:1.2kg/cm@6V 类似设计资料共享:https://www.cirmall.com/circuit/4202/(A4WD四轮驱动机器人,基于Arduino设计) 实物购买链接:https://item.taobao.com/item.htm?spm=2013.1.w10035...
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值