回答

收藏

[大赛作品提交] 【进阶六】家庭陪伴小机器人遥控舵机姿态

Raspberry Pi Raspberry Pi 6643 人阅读 | 0 人回复 | 2018-01-08

本帖最后由 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下载和测试)
  1. rm pigpio.zip
  2. sudo rm -rf PIGPIO
  3. wget abyz.co.uk/rpi/pigpio/pigpio.zip
  4. unzip pigpio.zip
  5. cd PIGPIO
  6. make
  7. sudo make install
复制代码
最好也测试下是否安装成功,GPIO 25 (pin 22).连接一个LED,LED灯会根据测试类项响应!
  1. ./x_pigpio.py   # check Python I/F to daemon
复制代码
2.编写程序
官方提供了很多example,deamo中有提供操作实例
  1. #!/usr/bin/env python

  2. # servo_demo.py
  3. # 2016-10-07
  4. # Public Domain

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

  7. import sys
  8. import time
  9. import random
  10. import pigpio

  11. NUM_GPIO=32

  12. MIN_WIDTH=1000
  13. MAX_WIDTH=2000

  14. step = [0]*NUM_GPIO
  15. width = [0]*NUM_GPIO
  16. used = [False]*NUM_GPIO

  17. pi = pigpio.pi()

  18. if not pi.connected:
  19.    exit()

  20. if len(sys.argv) == 1:
  21.    G = [4]
  22. else:
  23.    G = []
  24.    for a in sys.argv[1:]:
  25.       G.append(int(a))
  26.    
  27. for g in G:
  28.    used[g] = True
  29.    step[g] = random.randrange(5, 25)
  30.    if step[g] % 2 == 0:
  31.       step[g] = -step[g]
  32.    width[g] = random.randrange(MIN_WIDTH, MAX_WIDTH+1)

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

  35. while True:

  36.    try:

  37.       for g in G:

  38.          pi.set_servo_pulsewidth(g, width[g])

  39.          # print(g, width[g])

  40.          width[g] += step[g]

  41.          if width[g]<MIN_WIDTH or width[g]>MAX_WIDTH:
  42.             step[g] = -step[g]
  43.             width[g] += step[g]

  44.       time.sleep(0.1)

  45.    except KeyboardInterrupt:
  46.       break

  47. print("\nTidying up")

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

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

  9. pi = pigpio.pi()
  10. if not pi.connected:
  11.    exit()
  12. # for BCD.GPIO      
  13. SERVO_GPIO = 4
  14. # for RPi.GPIO      
  15. MOTOR_LEFT1_GPIO = 19
  16. MOTOR_LEFT2_GPIO = 21
  17. MOTOR_RIGHT1_GPIO = 22
  18. MOTOR_RIGHT2_GPIO = 24      
  19.       
  20. pi.set_mode(SERVO_GPIO, pigpio.OUTPUT)
  21. MIN_WIDTH = 500
  22. MAX_WIDTH = 1200
  23. width = 750
  24. step = 50

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

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

  34. @app.route('/ctl',methods=['GET','POST'])
  35. def ctrl_id():
  36.         if request.method == 'POST':
  37.                 id=request.form['id']
  38.                 GPIO.setmode(GPIO.BOARD)
  39.                 GPIO.setwarnings(False)
  40.                 GPIO.setup(MOTOR_LEFT1_GPIO,GPIO.OUT)
  41.                 GPIO.setup(MOTOR_LEFT2_GPIO,GPIO.OUT)
  42.                 GPIO.setup(MOTOR_RIGHT1_GPIO,GPIO.OUT)
  43.                 GPIO.setup(MOTOR_RIGHT2_GPIO,GPIO.OUT)

  44.                 if id == 't_left':
  45.                         t_left()
  46.                         return "left"
  47.                 elif id == 't_right':
  48.                         t_right()
  49.                         return "right"
  50.                 elif id == 't_up':
  51.                         t_up()
  52.                         return "up"
  53.                 elif id == 't_down':
  54.                         t_down()
  55.                         return "down"
  56.                 elif id == 't_stop':
  57.                         t_stop()
  58.                         return "stop"

  59.                 elif id == 's_down':
  60.                         s_down()
  61.                         return "servo_down"

  62.                 elif id == 's_up':
  63.                         s_up()
  64.                         return "servo_up"


  65.         return redirect(url_for('show_index'))

  66. def t_stop():
  67.         GPIO.output(MOTOR_LEFT1_GPIO, False)
  68.         GPIO.output(MOTOR_LEFT2_GPIO, False)
  69.         GPIO.output(MOTOR_RIGHT1_GPIO, False)
  70.         GPIO.output(MOTOR_RIGHT2_GPIO, False)

  71. def t_up():
  72.         GPIO.output(MOTOR_LEFT1_GPIO, True)
  73.         GPIO.output(MOTOR_LEFT2_GPIO, False)
  74.         GPIO.output(MOTOR_RIGHT1_GPIO, True)
  75.         GPIO.output(MOTOR_RIGHT2_GPIO, False)

  76. def t_down():
  77.         GPIO.output(MOTOR_LEFT1_GPIO, False)
  78.         GPIO.output(MOTOR_LEFT2_GPIO, True)
  79.         GPIO.output(MOTOR_RIGHT1_GPIO, False)
  80.         GPIO.output(MOTOR_RIGHT2_GPIO, True)

  81. def t_left():
  82.         GPIO.output(MOTOR_LEFT1_GPIO, False)
  83.         GPIO.output(MOTOR_LEFT2_GPIO, True)
  84.         GPIO.output(MOTOR_RIGHT1_GPIO, True)
  85.         GPIO.output(MOTOR_RIGHT2_GPIO, False)

  86. def t_right():
  87.         GPIO.output(MOTOR_LEFT1_GPIO, True)
  88.         GPIO.output(MOTOR_LEFT2_GPIO, False)
  89.         GPIO.output(MOTOR_RIGHT1_GPIO, False)
  90.         GPIO.output(MOTOR_RIGHT2_GPIO, True)

  91. def s_down():
  92.         global width
  93.         print(width)
  94.         if width>MIN_WIDTH:
  95.                 width -=step
  96.                 pi.set_servo_pulsewidth(SERVO_GPIO,width)
  97.                 time.sleep(0.1)
  98.         else:
  99.                 width = MIN_WIDTH
  100.         print(width)

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

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

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

  4.         <table border="0" cellpadding="3" cellspacing="0">
  5.                 <tr>
  6.                         <th></th>
  7.                         <th id="t_up" class="button_ctl" style="background-image:url('/static/img/up.png');"></th>
  8.                         <th></th>
  9.                         <th></th>
  10.                         <th></th>
  11.                         <th id="s_up" class="button_ctl" style="background-image:url('/static/img/s_up.png');"></th>
  12.                 </tr>
  13.                 <tr>
  14.                         <th id="t_left" class="button_ctl" style="background-image:url('/static/img/left.png');"></th>
  15.                         <th id="t_stop" class="button_ctl" style="background-image:url('/static/img/stop.png');"></th>
  16.                         <th id="t_right" class="button_ctl" style="background-image:url('/static/img/right.png');"></th>
  17.                 </tr>
  18.                 <tr>
  19.                         <th></th>
  20.                         <th id="t_down" class="button_ctl" style="background-image:url('/static/img/down.png');"></th>
  21.                         <th></th>
  22.                         <th></th>
  23.                         <th></th>
  24.                         <th id="s_down" class="button_ctl" style="background-image:url('/static/img/s_down.png');"></th>
  25.                 </tr>
  26.         </table>

  27. </div>

  28. {% endblock %}
复制代码
执行以下程序后,就可通过web控制舵机!最新效果如下!
  1. sudo pigpiod
  2. sudo python server.py
复制代码

提醒坑1:实际使用过程中发现360浏览器已打开以上界面,却无法控制,同时这种问题的还有系统自带IE浏览器!实测搜狗/chrome/百度浏览器可用!
关注下面的标签,发现更多相似文章
分享到:
回复

使用道具 举报

您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条