阿莫斯 发表于 2018-1-8 15:23:03

【进阶六】家庭陪伴小机器人遥控舵机姿态

本帖最后由 ky123 于 2018-1-31 14:07 编辑

感谢E络盟提供的助赛基金。
本章节的编写是为了下一步视频安防做准备,也遥控小车的扩展!

因为选择的USB摄像头为定焦摄像头,只有通过调整自身的状态才形成清晰的成像!当通过运动电机将目标调整至显示窗口时,由于距离发生了变化成像往往是模糊的!因此,在保证距离稳定成像清晰的前提下,调整舵机的俯仰位置将目标调整至显示窗内!

本章的两个工作:
1)底层驱动,PWM控制舵机;
2)操作应用,web实时控制舵机比摄像头显示目标

DuerOS和小车运动电机占用的GPIO如下:


树莓派只有一路 硬件PWM 输出( GPIO.1即BOARD中的引脚12,BCM编码中18,wiringPi编码中1 );
同时 wiringPi 库为我们提供了用软件 多线程 实现的PWM输出,我们可以利用这个库提供的函数很方便的将 任意GPIO 配置为PWM输出,即soft PWM;(个人模拟的PWM可能存在精度不准的情况)

由第一张图可以看出,硬件PWM已被DuerOS占用了! python提供的RPI.GPIO提供的PWM输出为硬件PWM,且未提供软件的PWM,也以使用wiringPi编码,软件模拟PWM;
另外也有人使用pigpio library来控制GPIO口,pigpio是一个允许控制GPIO的C语言库,同时pigpio是一个适用于树莓派的Python 模块,允许用过pigpio daemon程序控制通用GPIO口,不仅有PWM库,同时还有现成的Servo控制API(其实该库还是很强大的,此外还有IIC/SPI/ADC/DMA等,推荐给大家),因此本设计采用pigpio库来实现舵机控制!注意:所有的GPIO是按BCD编码命名。

1.安装pigpio库(pigpio下载和测试)rm pigpio.zip
sudo rm -rf PIGPIO
wget abyz.co.uk/rpi/pigpio/pigpio.zip
unzip pigpio.zip
cd PIGPIO
make
sudo make install最好也测试下是否安装成功,GPIO 25 (pin 22).连接一个LED,LED灯会根据测试类项响应!./x_pigpio.py   # check Python I/F to daemon2.编写程序
官方提供了很多example,deamo中有提供操作实例#!/usr/bin/env python

# servo_demo.py
# 2016-10-07
# Public Domain

# servo_demo.py          # Send servo pulses to GPIO 4.
# servo_demo.py 23 24 25 # Send servo pulses to GPIO 23, 24, 25.

import sys
import time
import random
import pigpio

NUM_GPIO=32

MIN_WIDTH=1000
MAX_WIDTH=2000

step = *NUM_GPIO
width = *NUM_GPIO
used = *NUM_GPIO

pi = pigpio.pi()

if not pi.connected:
   exit()

if len(sys.argv) == 1:
   G =
else:
   G = []
   for a in sys.argv:
      G.append(int(a))
   
for g in G:
   used = True
   step = random.randrange(5, 25)
   if step % 2 == 0:
      step = -step
   width = random.randrange(MIN_WIDTH, MAX_WIDTH+1)

print("Sending servos pulses to GPIO {}, control C to stop.".
   format(' '.join(str(g) for g in G)))

while True:

   try:

      for g in G:

         pi.set_servo_pulsewidth(g, width)

         # print(g, width)

         width += step

         if width<MIN_WIDTH or width>MAX_WIDTH:
            step = -step
            width += step

      time.sleep(0.1)

   except KeyboardInterrupt:
      break

print("\nTidying up")

for g in G:
   pi.set_servo_pulsewidth(g, 0)

pi.stop()该库函数中关于舵机控制有编写专门的API,set_servo_pulsewidth(user_gpio, pulsewidth)其中gpio遵循BCM编码规则!set_servo_pulsewidth      Start/Stop servo pulses on a GPIO
get_servo_pulsewidth      Get servo pulsewidth set on a GPIO重头戏来了!参考以上程序修改我们的运动控制程序即server/pi_car/views.py,在其中添加舵机控制程序段!本次也修改的之前对运动电机GPIO口的配置方式,在开始采用全局变量定义GPIO,这样大家根据个人自身情况更换GPIO更方便!
注意:本项目中电机和舵机由于使用的库不一样,编码方式也不一样!GPIO配置时数值一定要注意!from flask import Flask, request, session, g, redirect, url_for, abort, render_template, flash
from contextlib import closing
from pi_car import app
import re
import RPi.GPIO as GPIO
import pigpio
import time
import sys

pi = pigpio.pi()
if not pi.connected:
   exit()
# for BCD.GPIO      
SERVO_GPIO = 4
# for RPi.GPIO      
MOTOR_LEFT1_GPIO = 19
MOTOR_LEFT2_GPIO = 21
MOTOR_RIGHT1_GPIO = 22
MOTOR_RIGHT2_GPIO = 24      
      
pi.set_mode(SERVO_GPIO, pigpio.OUTPUT)
MIN_WIDTH = 500
MAX_WIDTH = 1200
width = 750
step = 50

@app.route('/')
def show_index():
      return render_template('home.html')

@app.route("/login", methods=["GET", "POST"])
def login():
      if request.method=="GET":
                return "get"+request.form["user"]
      elif request.method=="POST":
                return "post"

@app.route('/ctl',methods=['GET','POST'])
def ctrl_id():
      if request.method == 'POST':
                id=request.form['id']
                GPIO.setmode(GPIO.BOARD)
                GPIO.setwarnings(False)
                GPIO.setup(MOTOR_LEFT1_GPIO,GPIO.OUT)
                GPIO.setup(MOTOR_LEFT2_GPIO,GPIO.OUT)
                GPIO.setup(MOTOR_RIGHT1_GPIO,GPIO.OUT)
                GPIO.setup(MOTOR_RIGHT2_GPIO,GPIO.OUT)

                if id == 't_left':
                        t_left()
                        return "left"
                elif id == 't_right':
                        t_right()
                        return "right"
                elif id == 't_up':
                        t_up()
                        return "up"
                elif id == 't_down':
                        t_down()
                        return "down"
                elif id == 't_stop':
                        t_stop()
                        return "stop"

                elif id == 's_down':
                        s_down()
                        return "servo_down"

                elif id == 's_up':
                        s_up()
                        return "servo_up"


      return redirect(url_for('show_index'))

def t_stop():
      GPIO.output(MOTOR_LEFT1_GPIO, False)
      GPIO.output(MOTOR_LEFT2_GPIO, False)
      GPIO.output(MOTOR_RIGHT1_GPIO, False)
      GPIO.output(MOTOR_RIGHT2_GPIO, False)

def t_up():
      GPIO.output(MOTOR_LEFT1_GPIO, True)
      GPIO.output(MOTOR_LEFT2_GPIO, False)
      GPIO.output(MOTOR_RIGHT1_GPIO, True)
      GPIO.output(MOTOR_RIGHT2_GPIO, False)

def t_down():
      GPIO.output(MOTOR_LEFT1_GPIO, False)
      GPIO.output(MOTOR_LEFT2_GPIO, True)
      GPIO.output(MOTOR_RIGHT1_GPIO, False)
      GPIO.output(MOTOR_RIGHT2_GPIO, True)

def t_left():
      GPIO.output(MOTOR_LEFT1_GPIO, False)
      GPIO.output(MOTOR_LEFT2_GPIO, True)
      GPIO.output(MOTOR_RIGHT1_GPIO, True)
      GPIO.output(MOTOR_RIGHT2_GPIO, False)

def t_right():
      GPIO.output(MOTOR_LEFT1_GPIO, True)
      GPIO.output(MOTOR_LEFT2_GPIO, False)
      GPIO.output(MOTOR_RIGHT1_GPIO, False)
      GPIO.output(MOTOR_RIGHT2_GPIO, True)

def s_down():
      global width
      print(width)
      if width>MIN_WIDTH:
                width -=step
                pi.set_servo_pulsewidth(SERVO_GPIO,width)
                time.sleep(0.1)
      else:
                width = MIN_WIDTH
      print(width)

def s_up():
      global width
      print(width)
      if width<MAX_WIDTH:
                width +=step
                pi.set_servo_pulsewidth(SERVO_GPIO,width)
                time.sleep(0.1)
      else:
                width = MAX_WIDTH
      print(width)代码中通过MIN_WIDTH和MAX_WIDTH限定舵机的控制范围!根据实际情况修改,避免结构干涉引起舵机堵转!
web中添加舵机控制的图标和相关程序,在server/pi_car/static/img路径下添加舵机控制的图片

以及修改server/pi_car/templates/home.html中内容:{% extends "layout.html" %}
{% block body %}

<div style="width:600px;height:300px;margin:30px auto;">

      <table border="0" cellpadding="3" cellspacing="0">
                <tr>
                        <th></th>
                        <th id="t_up" class="button_ctl" style="background-image:url('/static/img/up.png');"></th>
                        <th></th>
                        <th></th>
                        <th></th>
                        <th id="s_up" class="button_ctl" style="background-image:url('/static/img/s_up.png');"></th>
                </tr>
                <tr>
                        <th id="t_left" class="button_ctl" style="background-image:url('/static/img/left.png');"></th>
                        <th id="t_stop" class="button_ctl" style="background-image:url('/static/img/stop.png');"></th>
                        <th id="t_right" class="button_ctl" style="background-image:url('/static/img/right.png');"></th>
                </tr>
                <tr>
                        <th></th>
                        <th id="t_down" class="button_ctl" style="background-image:url('/static/img/down.png');"></th>
                        <th></th>
                        <th></th>
                        <th></th>
                        <th id="s_down" class="button_ctl" style="background-image:url('/static/img/s_down.png');"></th>
                </tr>
      </table>

</div>

{% endblock %}执行以下程序后,就可通过web控制舵机!最新效果如下!sudo pigpiod
sudo python server.py
提醒坑1:实际使用过程中发现360浏览器已打开以上界面,却无法控制,同时这种问题的还有系统自带IE浏览器!实测搜狗/chrome/百度浏览器可用!
页: [1]
查看完整版本: 【进阶六】家庭陪伴小机器人遥控舵机姿态

Baidu
map