确保树莓派,手机在同一个局域网下。我这里树莓派的IP地址为192.168.1.149,可供参考。
1 摄像头配置
1.1 树莓派端
打开树莓派,按以下步骤将USB摄像头获取的图像传到浏览器。
首先给树莓派安装依赖包
sudo apt-get update
sudo apt-get install subversion
sudo apt-get install libjpeg8-dev
sudo apt-get install imagemagick
sudo apt-get install libv4l-dev
sudo apt-get install cmake
sudo apt-get install git
接着下载一个开源的、用C语言写的项目(相比于其他语言,使用C语言网页上的图像流畅度极高),并且进行编译。
sudo git clone https://github.com/jacksonliam/mjpg-streamer.git
cd mjpg-streamer/mjpg-streamer-experimental
make all
sudo make install
再通过以下命令行检测是否安装成功
./mjpg_streamer -i "./input_uvc.so" -o "./output_http.so -w ./www"
对于使用树莓派摄像头的用户,可以改为
./mjpg_streamer -i "./input_raspicam.so" -o "./output_http.so -w ./www"
我们可以在/home/pi/目录下新建一个sh文件,将上述命令整合在一起。
nano VR.sh
将以下内容复制到sh文件中
cd /home/pi/mjpg-streamer/mjpg-streamer-experimental/
./mjpg_streamer -i "./input_uvc.so -r 520x390" -o "./output_http.so -w ./www"
这样只要在终端输入以下命令即可
sh VR.sh
另外,要能让手机+VR box显示出VR的效果,必须要有两个一样图像,因此我们需要在服务器上添加一个专门用于vr的vr.html文件。
首先
cd mjpg-streamer/mjpg-streamer-experimental/www
接着创建一个html文件
nano vr.html
复制以下内容至文件中
<html>
<head>
<title>VR Browser</title>
</head>
<body>
<img src="./?action=stream" />
<img src="./?action=stream" />
</body>
</html>
这样就完成了树莓派端服务器的部署。
接下来打开浏览器查看图像。
1.2 手机端浏览器配置
打开google浏览器,输入我的树莓派IP地址192.168.1.149:8080/vr.html,可以看到下图
再设置手机为自动旋转模式,通过调整网页大小可以达到下图的效果
再将手机放进VR box中即可。
不过由于摄像头是静止的,我们带上VR头盔只能看到静态图像,接下来我们进行VR环境的搭建,增强VR的体验度。
2 VR环境搭建
2.1 手机端配置
首先下载手机app Wireless IMU
当然,下载左边那个app也是可以的。
打开之后选择选择对应的ip地址,选择最快的更新速率和后台运行选项,最后点击on
2.2 树莓派端配置
在树莓派端编写python脚本实现手机传感器数据接收和摄像头云台的角度控制。
2.2.1 使用socket实现udp协议
导入socket模块
import socket, traceback
import serial
配置好socket服务器并获取手机传感器数据
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind(('192.168.1.149', 5555))
print("Listening for broadcasts...")
time.sleep(0.2)
message, address = s.recvfrom(8192)
no1, no2, x1, y1, z1, no3, x2, y2, z2 = message.split(',')
2.2.2 将原始数据转化为角度
这里的angle1相当于手机绕x轴旋转的角度,采用加速度传感器的数据;
这里的angle2相当于手机绕y轴旋转的角度,采用陀螺仪的数据。
z1 = float(z1)
x1 = float(x1)
angle1 = math.atan(x1 / z1) * 57.3
if (x1 > 0):
if (angle1 < 0):
angle1 += 180
else:
if (z1 > 0):
angle1 = 0
else:
angle1 = 180
x2 = float(x2)
angle2 += x2 * dt * 57.3
2.2.3 实现舵机控制
导入树莓派GPIO库
并设置7号和13号引脚为输出引脚
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.OUT)
GPIO.setup(13, GPIO.OUT)
p = GPIO.PWM(7, 50)
p1 = GPIO.PWM(13, 50)
这里采用光滑的舵机控制,即循环微小改变舵机角度。
dater1 = angle1 - last_angle1
dater2 = angle2 - last_angle2
dater1 /= N
dater2 /= N
for i in range(N):
last_angle1 += dater1
last_angle2 += dater2
set_angle1(last_angle1)
set_angle2(last_angle2)
以下是舵机控制函数的定义,其中给舵机夹角控制设置了限制
def set_angle1(angle):
angle = 180 - angle
if (angle > 170):
angle = 170
if (angle < 10):
angle = 10
angle += t1
x = angle / 18. + 3.
p.ChangeDutyCycle(x)
def set_angle2(angle):
if (angle > 170):
angle = 170
if (angle < 10):
angle = 10
angle += t2
x = angle / 18. + 3.
p1.ChangeDutyCycle(x)
下面是完整的VR.py程序
import socket, traceback
import serial
from time import sleep
import math
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BOARD)
GPIO.setup(7, GPIO.OUT)
GPIO.setup(13, GPIO.OUT)
p = GPIO.PWM(7, 50)
p1 = GPIO.PWM(13, 50)
t1 = -25
t2 = -17
x = (90 + t1) / 18. + 3.
y = (90 + t2) / 18. + 3.
p.start(x)
p1.start(y)
angle2 = 90
last_angle1 = 90
last_angle2 = 90
last = 0
N = 150
def set_angle1(angle):
angle = 180 - angle
if (angle > 170):
angle = 170
if (angle < 10):
angle = 10
angle += t1
x = angle / 18. + 3.
p.ChangeDutyCycle(x)
def set_angle2(angle):
if (angle > 170):
angle = 170
if (angle < 10):
angle = 10
angle += t2
x = angle / 18. + 3.
p1.ChangeDutyCycle(x)
while 1:
try:
### get data
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
s.bind(('192.168.1.149', 5555))
print("Listening for broadcasts...")
time.sleep(0.2)
message, address = s.recvfrom(8192)
no1, no2, x1, y1, z1, no3, x2, y2, z2 = message.split(',')
now = float(no1)
dt = now - last
if (last == 0):
dt = 0
last = float(no1)
### calculate angle
z1 = float(z1)
x1 = float(x1)
angle1 = math.atan(x1 / z1) * 57.3
if (x1 > 0):
if (angle1 < 0):
angle1 += 180
else:
if (z1 > 0):
angle1 = 0
else:
angle1 = 180
x2 = float(x2)
angle2 += x2 * dt * 57.3
print(angle1)
print(angle2)
# slide
dater1 = angle1 - last_angle1
dater2 = angle2 - last_angle2
dater1 /= N
dater2 /= N
for i in range(N):
last_angle1 += dater1
last_angle2 += dater2
set_angle1(last_angle1)
set_angle2(last_angle2)
last_angle1 = angle1
last_angle2 = angle2
s.close();
except (KeyboardInterrupt, SystemExit):
raise
except:
traceback.print_exc()
接下来首先打开手机Wireless IMU app后台运行,然后切换至浏览器显示VR图像,然后放入VR box中,就可以开始你的VR之旅啦!