- Управление камерой на сервоприводе с помощью Raspberry Pi 2

Управление камерой на сервоприводах с помощью Raspberry Pi 2 и фреймворка WebIOPi

Практика для студентов. Мясищев А.А.

Необходимо создать систему удаленного управления камерой, входящей в состав мини компьютера Raspberry Pi 2 с помощью сервоприводов, вращающих камеру в двух плоскостях. Для управления сервоприводами используется фреймворк WebIOPi, видео поток с камеры на удаленный браузер будет формировать mjpg-streamer. Для ознакомления с материалом предполагается, что была прочитана статья https://sites.google.com/site/webstm32/internet_rozetka. На рисунке 1 показано устройство в сборе.

Рис. 1. Фото камеры на сервоприводах с подключенным к ней Raspberri Pi 2

На рисунке 2 показана картинка с камеры для одного из ее положений и кнопки управления сервоприводами(серые) с индикацией положения(синие). В строку ввода Input step вводится шаг поворота сервопривода в градусах. Рассмотрен самый простой случай - загружены два окна браузера Chrome. Первое окно подключено к web - серверу, который запускается при запуске mjpg-streamer(port 9000). Второе окно подключено к web - серверу фреймворка WebIOPi (port 8000).

Рис.2. Интерфейс при работе с камерой.

Этапы решения задачи:

1. Схема подключений

На рисунке 3 показана схема подключения сервоприводов камеры к Raspberry Pi 2. Целесообразно сервоприводы подключать к отдельному от компьютера источнику питания.

Рис.3. Схема подключения сервоприводов камеры к Raspberry P 2.

2. Установка фреймворка WebIOPi

Предполагается, что на Raspberry Pi 2 установлена операционная система RASPBIAN с IP адресом 192.168.1.38.

Для работы 40 выводов порта GPIO целесообразно установить фреймворк WebIOPi версии 0.7.1:

$ wget http://sourceforge.net/projects/webiopi/files/WebIOPi-0.7.1.tar.gz

$ tar xvzf WebIOPi-0.7.1.tar.gz

$ cd WebIOPi-0.7.1

Устанавливаем patch для работы с 40 пинами порта GPIO Raspberry Pi 2:

$wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi-pi2bplus.patch

$ patch -p1 -i webiopi-pi2bplus.patch

$ sudo ./setup.sh

Для автоматического старта WebIOPi после перегрузки компьютера необходимо выполнить команду (действительно для образа системы 2015-05-05-raspbian-wheezy.img):

sudo update-rc.d webiopi defaults

Для более поздних версий выполняются следующие команды:

$ cd /etc/systemd/system/

$ sudo wget https://raw.githubusercontent.com/doublebind/raspi/master/webiopi.service

$ sudo systemctl start webiopi

$ sudo systemctl enable webiopi

Редактируем конфигурационный файл config:

sudo nano /etc/webiopi/config

Настраиваем порты GPIO 23,24 как выходы с низким стартовым уровнем. В секции [GPIO] записываем:

23 = OUT 0

24 = OUT 0

В секции [SCRIPTS] указываем имя и расположение файла - скрипта на Питоне, необходимый для управления сервоприводами

myproject = /home/pi/myproject/python/script.py

В секции [HTTP] указываем имя и расположение html файла:

doc-root = /home/pi/myproject/html

В секции [REST] прописываем активные порты(только они будут работать):

gpio-export = 23,24

После этого перегружаем Raspberry Pi 2:

sudo reboot

Для входа по адресу http://192.168.1.38:8000 используется логин - "webiopi" , пароль - "raspberry"

3. Настройка фреймворка WebIOPi. Построение файлов сценария на Python и HTML файла с JavaScript

Принимается, что сервоприводы поворачивают камеру Right-Left на угол -90...+90 градусов и Up-Down на угол -90...+90 градусов соответственно. Исходное состояние при старте или рестарте WebIOPi для Right-Left 0 градусов и Up-Down также 0 градусов.

В скрипте scrypt.py используются встроенные в WebIOPi функции:

GPIO.setFunction(SERVO1, GPIO.PWM) - устанавливает режим работы вывода SERVO1, как ШИМ вывод.

GPIO.pwmWriteAngle(SERVO1, 0) - для сервопривода,подключенного к выводу SERVO1 устанавливает угол 0 градусов.

Задержка, формируемая командой webiopi.sleep(0.25) и последующее изменение режима работы вывода SERVO1 (GPIO.setFunction(SERVO1, GPIO.OUT)) необходимы для предотвращения "дрожания" сервопривода (см. принцип работы сервопривода).

Аналогично для вывода SERVO2.

Файл сценария /home/pi/myproject/scrypt.py

# Imports

import webiopi

import datetime

GPIO = webiopi.GPIO

SERVO1=23

SERVO2=24

SERRL = 0 # Angle rotation Right-Left

STE = 0 # Step angle rotation

SERUD = 0 # Angle rotation Up-Down

# setup function is automatically called at WebIOPi startup

def setup():

# set the GPIO used by the light to output

GPIO.setFunction(SERVO1, GPIO.PWM)

GPIO.setFunction(SERVO2, GPIO.PWM)

GPIO.pwmWriteAngle(SERVO1, 0)

GPIO.pwmWriteAngle(SERVO2, 0)

webiopi.sleep(0.25)

GPIO.setFunction(SERVO1, GPIO.OUT)

GPIO.setFunction(SERVO2, GPIO.OUT)

# destroy function is called at WebIOPi shutdown

def destroy():

GPIO.digitalWrite(SERVO1, GPIO.OUT)

GPIO.digitalWrite(SERVO2, GPIO.OUT)

@webiopi.macro

def steps():

global SERRL,STE

return "%d" % SERRL

@webiopi.macro

def steps1():

global SERUD,STE

return "%d" % SERUD

@webiopi.macro

def gets():

global SERRL

return "%d" % STE

@webiopi.macro

def lef(on):

global SERRL,STE

STE = int(on)

GPIO.setFunction(SERVO1, GPIO.PWM)

SERRL=SERRL+STE

if (abs(SERRL)>=90):

SERRL=90

GPIO.pwmWriteAngle(SERVO1, SERRL)

webiopi.sleep(0.25)

GPIO.setFunction(SERVO1, GPIO.OUT)

return gets()

@webiopi.macro

def ri(on):

global SERRL,STE

STE = int(on)

GPIO.setFunction(SERVO1, GPIO.PWM)

SERRL=SERRL-STE

if (abs(SERRL)>=90):

SERRL=-90

GPIO.pwmWriteAngle(SERVO1, SERRL)

webiopi.sleep(0.25)

GPIO.setFunction(SERVO1, GPIO.OUT)

return gets()

@webiopi.macro

def downs(on):

global SERUD,STE

STE = int(on)

GPIO.setFunction(SERVO2, GPIO.PWM)

SERUD=SERUD+STE

if (abs(SERUD)>=90):

SERUD=90

GPIO.pwmWriteAngle(SERVO2, SERUD)

webiopi.sleep(0.25)

GPIO.setFunction(SERVO2, GPIO.OUT)

return gets()

@webiopi.macro

def ups(on):

global SERUD,STE

STE = int(on)

GPIO.setFunction(SERVO2, GPIO.PWM)

SERUD=SERUD-STE

if (abs(SERUD)>=90):

SERUD=-90

GPIO.pwmWriteAngle(SERVO2, SERUD)

webiopi.sleep(0.25)

GPIO.setFunction(SERVO2, GPIO.OUT)

return gets()

HTML файл /home/pi/myproject/index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html>

<head>

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">

<title>servo and camera</title>

<script type="text/javascript" src="/webiopi.js"></script>

<script type="text/javascript">

setInterval ("callMacro_steps()", 500);{

}

function callMacro_steps(){

webiopi().callMacro("steps", [], macro_steps_Callback);

}

function macro_steps_Callback(macro, args, data) {

$("#step").text("Right Left: "+data);

}

setInterval ("callMacro_steps1()", 500);{

}

function callMacro_steps1(){

webiopi().callMacro("steps1", [], macro_steps1_Callback);

}

function macro_steps1_Callback(macro, args, data) {

$("#step1").text("Up Down: "+data);

}

webiopi().ready(function() {

// Following function will process data received from set/gets macro.

var update = function(macro, args, response) {

var servo=response;

// Following lines use jQuery functions

$("#inputOn").val(servo);

}

// Immediately call gets macro to update the UI with current values

// "gets" refers to macro name

// [] is an empty array, because gets macro does not take any argument

// update is the callback function, defined above

webiopi().callMacro("gets", [], update);

// Create a button to call lef macro

var sendButton1 = webiopi().createButton("sendButton1", "Left", function() {

// Arguments sent to the macro

var servo = $("#inputOn").val();

// Call the macro

webiopi().callMacro("lef", servo, update);

});

// Append the button to the controls box using a jQuery function

$("#controls").append(sendButton1);

// Create a button to call ri macro

var sendButton2 = webiopi().createButton("sendButton2", "Right", function() {

// Arguments sent to the macro

var servo = $("#inputOn").val();

// Call the macro

webiopi().callMacro("ri", servo, update);

});

// Append the button to the controls box using a jQuery function

$("#controls").append(sendButton2);

//-------------

// Create a button to call downs macro

var sendButton3 = webiopi().createButton("sendButton3", "Down", function() {

// Arguments sent to the macro

var servo = $("#inputOn").val();

// Call the macro

webiopi().callMacro("downs", servo, update);

});

// Append the button to the controls box using a jQuery function

$("#controls").append(sendButton3);

// Create a button to call ups macro

var sendButton4 = webiopi().createButton("sendButton4", "Up", function() {

// Arguments sent to the macro

var servo = $("#inputOn").val();

// Call the macro

webiopi().callMacro("ups", servo, update);

});

// Append the button to the controls box using a jQuery function

$("#controls").append(sendButton4);

//-------------

// Refresh GPIO buttons

// pass true to refresh repeatedly of false to refresh once

webiopi().refreshGPIO(true);

});

</script>

<style type="text/css">

#step, #step1 {

margin: 5px 5px 5px 5px;

width: 160px;

height: 45px;

background-color: Blue;

font-size: 16pt;

font-weight: bold;

color: white;

}

</style>

<style type="text/css">

button {

display: block;

margin: 5px 5px 5px 5px;

width: 160px;

height: 45px;

font-size: 20pt;

font-weight: bold;

color: white;

}

</style>

</head>

<body>

<div align="center">

Input step:<input type="text" maxlength="2" size="2" id="inputOn" /><br/>

<div id="controls"></div>

<div id="step"></div>

<div id="step1"></div>

</div>

</body>

</html>

4. Установка и настройка MJPG-Streamer (https://miguelmota.com/blog/raspberry-pi-camera-board-video-streaming/)

Предположим, наш текущий каталог /home/pi. Создадим каталог:

sudo mkdir /opt/mjpg-streamer

Установим библиотеку libjpeg62-dev:

sudo apt-get install libjpeg62-dev

Устанавливаем cmake:

sudo apt-get install cmake

Загружаем mjpg-streamer с плагином raspicam:

git clone https://github.com/jacksonliam/mjpg-streamer.git ~/mjpg-streamer

Заходим в директорию:

cd ~/mjpg-streamer/mjpg-streamer-experimental

Выполняем компиляцию

make clean all

Перемещаем файлы и удаляем рабочую директорию:

sudo mv ~/mjpg-streamer/mjpg-streamer-experimental /opt/mjpg-streamer

sudo rm -rf ~/mjpg-streamer

Создаем файл /opt/mjpg-streamer/start_stream.sh для старта MJPG-Streamer:

#!/bin/bash if pgrep mjpg_streamer > /dev/null then echo "mjpg_streamer already running" else LD_LIBRARY_PATH=/opt/mjpg-streamer/ /opt/mjpg-streamer/mjpg_streamer -i "input_raspicam.so -fps 10 -q 50 -x 640 -y 480" -o "output_http.so -p 9000 -w /opt/mjpg-streamer/www" > /dev/null 2>&1& echo "mjpg_streamer started"

fi

Создаем файл /opt/mjpg-streamer/stop_stream.sh для останова MJPG-Streamer:

#!/bin/bash

if pgrep mjpg_streamer then kill $(pgrep mjpg_streamer) > /dev/null 2>&1 echo "mjpg_streamer stopped" else echo "mjpg_streamer not running" fi

Таким образом для запуска необходима команда:

/opt/mjpg-streamer/stop_stream.sh

Для останова:

/opt/mjpg-streamer/stop_stream.sh

Просмотреть видеопоток можно, набрав в браузере адрес:

http://192.168.1.38:9000/stream_simple.html

Получим изображение, как в левом окне рисунка 2.

Выводы

1. Сервоприводы чувствительны к броскам напряжения. Например, при включении обогревателя сервоприводы "дергаются" и меняется положение камеры.

2. Замечено "подвисание" WebIOPi при управлении камерой. После рестарта по команде /etc/init.d/webiopi restart, управление камерой возобновляется.

tabl

Написана 16.04.2016