基于树莓派的VR设备

在这里插入图片描述

确保树莓派,手机在同一个局域网下。我这里树莓派的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之旅啦!

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值