VRPN-OSVR介绍

全称:虚拟现实外设网络(Virtual Reality Peripheral Network)

链接:获取并参与

版本控制:https://github.com/vrpn/vrpn

源代码:https://github.com/vrpn/vrpn/releases

支持的设备:https://github.com/vrpn/vrpn/wiki/Available-hardware-devices

文档:http://dev.vrpn.org/docs/

新代码模板生成器:http://dev.vrpn.org/boilerplate/

简介:

VRPN是由会在虚拟现实系统中使用到的一系列类库和服务构成,可用它来实现应用程序和物理设备(比如追踪器)之间的网络透明接口。主要思想是在VR基础上使用PC或其他的主机来控制外设(追踪器,按钮设备,触觉设备,模拟输入,声音等)。VRPN提供了应用程序与使用相对应服务类的设备之间的连接,而应用程序不用知道网络拓扑结构。需要了解的是,使用VRPN的设备是可直接连上正在运行应用程序的机器上的,要么使用独立控制程序方式要么以单一程序运行方式。

VRPN所包含的驱动,部分列表如地址:https://github.com/vrpn/vrpn/wiki/Available%20hardware%20devices

其中OSVR Hacker Developer Kit:

为了提升性能与兼容性,OSVR部分使用并扩展了VRPN软件和设备模型。早期的OSVR版本提供一种实验性的方式集成外部VRPN追踪器。但是0.2版本为了通过外部(本地或远程)VRPN服务完全支持追踪器,按键以及模拟设备进而删除了该实验性的支持。

该改变要求将这些设备集成进OSVR中使用的富元数据“path tree”模型中。本地OSVR设备驱动不仅提供设备数据的访问,而且提供一个JSON设备描述符文件来描述该设备的兼容性以及已经编号的传感器的语义名。由于标准的VRPN服务缺少这些附加数据,所以在OSVR中使用VRPN设备就需要用户提供这个信息,通过配置文件,来正确的集成外设。

以上所提及的要求OSVR-Core 0.2及以上的版本才行。客户端(应用程序)DLL以及服务包也必须都是0.2及以上版本才行。

若用户在同一个机器上运行一个vrpn_server的进程作为OSVR服务,则必须以一个命令行参数的形式传入一个替换端口号(比如3884)到vrpn_server中去,是为了避免与内置VRPN服务冲突。这样的一个外部服务配置超出本文档所讨论的范围:假设已知一个设备名(通常类似于Tracker0之类的)以及服务(通常只是一个主机名类似trackerserver,但也有可能是主机名和端口号的组合:localhost:3884作为本地推荐的vrpn_server,或者甚至包含传输协议名:tcp://trackerserver:3884)。这两部分一般会使用符号@来隔开。比如:Tracker0@loacalhost:3884

为了文档叙述方便,假设用户使用类似指挥棒的追踪器或者Razer Hydra。也就是说,一个凭借一个名字就可提供追踪,按键以及模拟数据的设备。该进程可重复添加任意数量的外部VRPN设备名到系统中。

提示:

用户可参考从样例配置文件osvr_server_config.externalvrpn.sample.json开始创建自己的配置文件。本文档以下都是一步一步地解析说明该文件的结构。

{
  "externalDevices": {
    "/myExternalDevice": {
      "deviceName": "Tracker0",
      "server": "localhost:3884",
      "descriptor": {
        "interfaces": {
          "tracker": {},
          "button": {},
          "analog": {}
        },
        "Note": "can also provide a file path here, or this is the minimal"
      }
    }
  },
  "aliases": {
    "/me/head": {
      "rotate": {
        "axis": "-x",
        "degrees": 180
      },
      "child": {
        "changeBasis": {
          "x": "x",
          "y": "-z",
          "z": "-y"
        },
        "child": "/myExternalDevice/tracker/0"
      }
    },
    "/me/hands/right": {
      "rotate": {
        "axis": "-x",
        "degrees": 180
      },
      "child": {
        "changeBasis": {
          "x": "x",
          "y": "-z",
          "z": "-y"
        },
        "child": "/myExternalDevice/tracker/1"
      }
    },
    "/controller/trigger": "/myExternalDevice/analog/0",
    "/controller/a": "/myExternalDevice/button/0"
  }
}

在编辑这些配置文件时,一个支持JSON的文本编辑器会起到很大的用途,它有语法检查,代码折叠以及自动缩进功能。

1.若不能在本地安装软件,则可使用JSON Editor Online在线编辑器。最左上角的时缩进功能按钮。出现X标志说明解析错误,且移动到X上面会弹出浮动提示内容。另外左边若有修改一定要记得同步到右边,可使用界面中间的箭头同步。


2.若能安装本地软件,则可安装本地软件Atom来编辑JSON。它没有一个类似上面的编辑器所提供的图形视觉,但是有更为有用的错误解析信息。作为一个本地安装应用,更容易用于编辑本地文件(不需要在网页于文本编辑器中间去做拷贝粘贴或者重命名从网页上保存下来的文件)。然而,由于它使用的时Chromium WebGL的内核框架,导致它会在一些远程X连接或者X转接上不工作(可参考issue tracker)。

配置流程:

步骤1:导入以及描述VRPN设备

第一个创建路径树节点用来表示外部设备,它包含设备名,服务,以及描述数据。这些在配置文件的顶级元素中的一个叫做externalDevices的对象中完成。该节样例如下:

"externalDevices": {
    "/myExternalDevice": {
      "deviceName": "Tracker0",
      "server": "localhost:3884",
      "descriptor": /* can also provide a file path here, or this is the minimal */ {
        "interfaces": {
          "tracker": {},
          "button": {},
          "analog": {}
        }
      }
    }
  }

关键字externalDevices表示一个JSON对象,在这之后,每个key都是路径path并创建一个设备节点。同时value值是一个对象要创建那个节点时所包含的信息。(如果是本地OSVR设备,该路径path有两个级别:首先是插件名字随后是设备名,类似(com_osvr_Multiserver/OSVRHackerDevKit0。一旦该externalDevices部分被建立,就可像引用本地OSVR设备一样引用该外部设备)。

在上述实例中,随意的选择/myExternalDevice作为路径path。设备名devicename包含VRPN设备名(Tracker0),然而server键包含server信息(loacalhost:3884)。该对象的最后元素,标为descriptor,改元数据在OSVR中它会被用到,但是在VRPN中没有提供。在最基本层,仅仅是一个带interfaces成员的内嵌JSON对象,它包含了用户所想要访问的各种接口类型。不一定要用对象,还可只提供一个字符串,它会被解析成一个包含有JSON设备描述符的文件名。当在多种场合使用同一个设备时显得尤为有用,因为可独立于server config文件而只共享设备描述符文件。

对以上描述符很小的改动就足以按照剩下的指令来让设备在OSVR上使用了。对完整设备描述符格式的更深入分析就超出本文档所讨论的范围了。以下是HDK tracker的样例文件:

{
    "deviceVendor": "OSVR",
    "deviceName": "Hacker Development Kit (HDK) Integrated IMU Tracker",
    "author": "Ryan Pavlik <ryan@sensics.com>",
    "version": 3,
    "lastModified": "2015-11-05T20:44:16+00:00",
    "interfaces": {
        "tracker": {
            "count": 1,
            "bounded": true,
            "position": false,
            "orientation": true,
            "angularVelocity": true
        },
        "analog": {
            "count": 2,
            "traits": [{
                "min": 0
            }, {
                "min": 0,
                "max": 3
            }]
        }
    },
    "semantic": {
        "hmd": {
            "$target": {
                "rotate": {
                    "axis": "x",
                    "degrees": 90
                },
                "child": {
                    "changeBasis": {
                        "x": "-x",
                        "y": "-z",
                        "z": "y"
                    },
                    "child": "tracker/0"
                }
            }
        },
        "status": {
            "reportVersion": "analog/0",
            "videoStatus": "analog/1"
        }
    },
    "automaticAliases": {
        "/me/head": "semantic/hmd"
    }
}

以及Razer Hydra的文件:

{
  "deviceVendor": "Razer",
  "deviceName": "Hydra motion controller",
  "author": "Ryan Pavlik <ryan@sensics.com>",
  "version": 2,
  "lastModified": "2015-04-10T17:38:49.659Z",
  "interfaces": {
    "tracker": {
      "count": 2,
      "position": true,
      "orientation": true
    },
    "analog": {
      "count": 6,
      "traits": [
        {
          "min": -1,
          "max": 1,
          "rest": 0
        },
        {
          "min": -1,
          "max": 1,
          "rest": 0
        },
        {
          "min": 0,
          "max": 1,
          "rest": 0
        },
        {
          "min": -1,
          "max": 1,
          "rest": 0
        },
        {
          "min": -1,
          "max": 1,
          "rest": 0
        },
        {
          "min": 0,
          "max": 1,
          "rest": 0
        }
      ]
    },
    "button": {
      "count": 15
    }
  },
  "semantic": {
    "left": {
      "1": "button/1",
      "2": "button/2",
      "3": "button/3",
      "4": "button/4",
      "$target": {
        "changeBasis": {
          "x": "x",
          "y": "z",
          "z": "-y"
        },
        "child": "tracker/0"
       },
      "middle": "button/0",
      "bumper": "button/5",
      "joystick": {
        "button": "button/6",
        "x": "analog/0",
        "y": "analog/1"
      },
      "trigger": "analog/2"
    },
    "right": {
      "1": "button/9",
      "2": "button/10",
      "3": "button/11",
      "4": "button/12",
      "$target": {
        "changeBasis": {
          "x": "x",
          "y": "z",
          "z": "-y"
        },
        "child": "tracker/1"
       },
      "middle": "button/8",
      "bumper": "button/13",
      "joystick": {
        "button": "button/14",
        "x": "analog/3",
        "y": "analog/4"
      },
      "trigger": "analog/5"
    }
  },
  "automaticAliases": {
    "/me/hands/left": "semantic/left",
    "/me/hands/right": "semantic/right",
    "/controller/left": "semantic/left/*",
    "/controller/right": "semantic/right/*"
  }
}

可使用Web应用OSVR JSON Editor来帮助组合这些段落;它是一个使用设备描述符规范的纯页面应用,用于自动生成一个编辑接口。

验证结果:

到此为止,可能需要暂停以测试配置文件是否正确。此时当使用配置文件运行osvr_server应用时可看到类似如下行:

[OSVR Server] External devices found and parsed from config file.

运行osvr_print_tree辅助工具可看到类似如下路径树:

[   DeviceElement] /myExternalDevice
                     - corresponds to Tracker0@localhost:3884
[InterfaceElement] /myExternalDevice/analog
[InterfaceElement] /myExternalDevice/button
[InterfaceElement] /myExternalDevice/tracker

步骤二:

OSVR系统强烈建议用户使用语义路径而不是使用与硬件相关的路径。语义路径可在不同的系统上指向不同的硬件资源。(在老版本的OSVR内,可能看到过routes,这个是同样的概念。老的基于routes的配置文件语法已经被抛弃不用了,优先使用新的别名语法。)在OSVR的插件上,设备描述符常在设备节点下面设置一个/semantic的树,也可能包含一个automaticAliases段提供全局别名路径。在步骤1中除非已经添加所有的属性到设备描述符中,否则不得不在配置文件中设置合适的别名。

常用路径包括:

/me/head-用于头部追踪

/me/hands/left-用于手柄追踪或者一个左手握着的设备(比如指挥棒)

/me/hands/right-同上,只是左右换为右手

当输入设备与一个追踪器关联起来时,/controller下还有代表控制器输入设备的语义路径(按键,扳机,游戏杆),以及更为深入的/controller/left和/controller/right。在这个路径树上面,很少的特殊路径为人所熟知。鼓励大家在应用程序以及配置文件中创建以及使用其他的语义路径作为别名(比如/actions/jump代替/controller/a)。

在配置文件JSON对象中配置的外部设备的别名,此时在关键字aliases下面。类似如下:

"aliases": {
    "/controller/trigger": "/myExternalDevice/analog/0",
    "/controller/a": "/myExternalDevice/button/0",
    "/me/head": {
      "rotate": {
        "axis": "-x",
        "degrees": 180
      },
      "child": {
        "changeBasis": {
          "x": "x",
          "y": "-z",
          "z": "-y"
        },
        "child": "/myExternalDevice/tracker/0"
      }
    },
    "/me/hands/right": {
      "rotate": {
        "axis": "-x",
        "degrees": 180
      },
      "child": {
        "changeBasis": {
          "x": "x",
          "y": "-z",
          "z": "-y"
        },
        "child": "/myExternalDevice/tracker/1"
      }
    }
  }


该实例显示了两种不同的语法。

1.最简单的,在模拟以及按键设备中被使用到的,还有不需要任何转换变形的用来在OSVR全局坐标系中校准对齐的追踪器。仅仅依据键就可以创建别名路径,以及仅仅依据字符串值就可以使别名指向路径path。上例中的前面两个入口就使用了这种形式。

2.第二种语法更复杂(在接下来的两种入口中使用到了)。由于它使能了一个转换变形树的应用到追踪数据。键key像以前一样是创建的别名路径。然而,在这个案例中,该值是一个JSON对象。这个对象中可能还有随意的嵌套级别,是使用每个键child来指定的内部级别。最后一级必须是以child键终止且它的值为字符串,它是别名所要转换变形以及指向的路径。每一个级别都可能包含转换变形的对象(类似changeBasis以及rotate所显示的)-可参考其他的例子文件以及关于支持的转换变形的文档。

在所有的案例中,别名终止于在步骤1中的设备路径下所设置的一个路径。语法规则为:/devicename/interfacename/sensornumber(或者有时候,.devicename/intefacename表示所有的传感器)。当然,如果设置了一个包含语义路径的设备描述文件,可直接引用它们而不用管本步骤中的原始设备路径。

验证结果:

到此位置,可再次运行配置文件中的osvr_server。server输出不会改变,但是运行osvr_print_tree时会反应别名所构造的路径树的改变。比如上面的比别名,将能看到如下输出:

[   DeviceElement] /myExternalDevice
                     - corresponds to Tracker0@localhost:3664
[InterfaceElement] /myExternalDevice/analog
[   SensorElement] /myExternalDevice/analog/0
[InterfaceElement] /myExternalDevice/button
[   SensorElement] /myExternalDevice/button/0
[InterfaceElement] /myExternalDevice/tracker
[   SensorElement] /myExternalDevice/tracker/1
[   SensorElement] /myExternalDevice/tracker/0
[    AliasElement] /controller/a
                     -> /myExternalDevice/button/0
[    AliasElement] /controller/trigger
                     -> /myExternalDevice/analog/0
[    AliasElement] /me/hands/right
                     -> {"child":{"changeBasis":{"x":"x","y":"-z","z":"-y"},"child":"/myExternalDevice/tracker/1"},"rotate":{"axis":"-x","degrees":180}}
[    AliasElement] /me/head
                     -> {"child":{"changeBasis":{"x":"x","y":"-z","z":"-y"},"child":"/myExternalDevice/tracker/0"},"rotate":{"axis":"-x","degrees":180}}

AliasElement入口是配置的别名路径,osvr_print_tree会打印每个别名的目标路径,不管它是一个字符串还是一个复杂的JSON转换变形版本。此外,每个路径代表一个sensor,它也是别名所指定的有效目标设备,每个sensor都明显被标识为SensorElement。当别名解析时,这些sensor element自动生成。如果没有看到所指定的SensorElement,那么很有可能在指定相应别名时出现了错误。

当要要测试自己所设置的别名时,可使用OSVR Tracker Viewer应用程序验证。(独立于core/server发布的版本,点击此处下载编译好的二进制包)。在命令行带参数-h运行它,可看到如何让所想要的path可视化。该应用是在OSVR标准坐标系中打开的,因此可验证各轴转换是否正确。


tracker view:


以上就是OSVR HDK所使用到的VRPN相关。


VRPN还提供了一个抽象层使得所有的设备有着看起来相同的基类;比如,所有的追踪设备都是vrpn_tracker类型的。这完全意味着所有的追踪器都产生相同类型的上报数据。与此同时,对应用来说请求访问某个追踪设备的特定属性而派生一个类来与该类型的追踪设备进行通信也是有可能的(比如,告诉某个追踪设备的类型产生上报数据的频率),

如果这个专用类被一个不知道怎么去设置它的更新速率的追踪设备使用,那么该命令会被那个追踪设备所忽略。当前的系统类型有:Analog,Button,Dial,ForceDevice,Image,Sound,Text以及Tracker。每个都为某一种设备类型抽象出了一些列语义。对每种设备类型都有一个或更多的服务与之像对应,并且有着一个客户端类从设备中读取数据用来控制它的行为。

VRPN当前正由Sensics来维护支持,且与一大群有着活力的社区自愿者一起协作开发。它内置在OSVR平台中

在VRST 2001的大会上一份关于VRPN的论文已经提交,在这儿可以找到复印版本,Powerpoint版本在这儿可找到,还有一个关于vrpn_Imager的Powerpoint版本可在这儿找到。

VRPN已经在PC/Win32,PC/Cygwin,PC/Linux,以及Mac/OSX(32位和64位)都测试过,还有ARM Linux系统以及安卓上也都测试过。在平台SGI/Irix, HP700/Hpux, Sparc/Solaris, Ipaq/Linux, and Zaurus/Linux上曾经有效过一段时间,但是不会一直有效(若运行在手持式平台Linux/WinCE上,请参考VRPN PDA页)。



展开阅读全文

没有更多推荐了,返回首页