PicoVRAndroidSDK_Unity¶
1 Introduction¶
1.1 SDK¶
To facilitate the vast Unity 3D developers with creating Pico VR Headset applications, our company released PicoVRAndroidSDK_Unity (hereinafter referred to as the SDK). The SDK provides mainly the functionalities including sensor fusion, binocular stereo rendering, optical distortion correction, asynchronous time warping, single buffer rendering, 3DoF/6DoF multi interaction support, 3D stereo sound effect, power and cooling management, account and payment management etc.
For the convenience of integration, the SDK is provided in UnityPackage format and developers can find the following directory after import:

Figure1.1 SDK Structure
Every subdirectory under Assets> UnityMobileSDK corresponds to an SDK functionality and the Scenes directory under subdirectory provides scenarios for you to refer to and when you have problems during SDK integration, you can check out the documentation or refer to the methods in referential scenes.
1.2 Documentation¶
This document mainly introduces the SDK integration methods including integration of stereo rendering, sensor fusion and other features, usage of device controllers, integration of payment functionality. It also described the directory structure of the SDK and the functionalities of interface APIs and in addition, answered some frequently asked questions. Before using the SDK, it’s highly recommended to read this document for best results.
2 Device Support¶
The SDK only supports the following versions under Pico brand:
Table 2.1 List of Supported Devices
Device Type | Model |
---|---|
VR Glasses | Pico1/1s、Pico U |
All-in-one Machine | Pico Neo DK/ DKS、Pico Goblin、Pico Neo |
3 Development Environments¶
For Unity 5, the SDK is compatible with Unity 5.2 and above versions.
For Unity 2017, the SDK supports Unity 2017.1.1 and Unity2017.2.0. Other Unity 2017 versions are not yet validated.
In addition, Android development environment should be configured before integration starts and the specific requirements are as follows:
Table 3.1 Android Development Environments
Software Name | Software Version |
---|---|
JDK | jdk1.7.0_01and above |
Android SDK | API Level 19 and above |
Moreover, if you develop applications for Pico 1/1s or Pico U, that is, Android mobile apps, please do make sure that the Android phones meet the following requirements:
Table 3.2 Requirements for Mobile Phones
List of Requirements | Specifics of Requirements |
---|---|
Android Version | Android 4.4 and above |
Sensor | Equipped with gyroscope and acceleration sensor |
4 QuickStart for SDK Integration¶
Step 1: Create new project¶
Open Unity, create a new project as shown below:
Figure 4.1 Create New Project
Create cube1, cube2, cube3, and configure their Transform information as follows:

Figure 4.2 cube1 Transform

Figure 4.3 cube2 Transform

Figure 4.4 cube3 Transform
Step 2: Import SDK¶
Choose menu Assets>Import Package>Custom Package…

Figure 4.5 Import Custom Package
At this moment, the system will pop up a dialog, choose “PicoVR_Unity_SDK-versionnumber.unitypackage”, and click to open:

Figure 4.6 Select Unity Package
Once open, the system will pop up another dialog. Please import the corresponding sections according to your needs:

Figure 4.7 Import Options
Step 3: Use SDK¶
Go to Project tab, expand Assets>Pvr_UnitySDK>Prefabs in turn, drag Pvr_UnitySDK prefab into the scene and set the Position and Rotation of its Transform component to (0, 0, 0):

Figure 4.8 Directory for Pvr_UnitySDK Prefab
With Unity Prefab, the hierarchy of the scene should look like the following figure:

Figure 4.9 Scene Hierarchy
In order to avoid that other cameras in the scene interfere with the stereo rendering of the SDK, the last step is to delete the Main Camera shown in the above figure.
Step 4: Mock Run¶
Click on the Run button and you can see the screen below in the Game window:

Figure 4.10 Run Simulation
Press and hold Alt , then move the mouse, the screen will follow your mouse to rotate up, down, left and right; Press and hold Alt + click the left mouse button to select VR mode or Mono mode (Unity Editor only).
Step 5: Packaging¶
Before packaging, you still need to set the tracking type for head and hand according to your current platform: Go to the Inspector panel of Pvr_UnitySDK, if the current target platform is not Pico Neo, you’ll need to set the Head Pose property of Pvr_Unity SDK Manager component to “Three Dof”and Hand Pose to “Three Pose”:

Figure 4.11 Adapting Target Platform
Save your current scene before packaging, the go to File>Build Settings…, click “Add Current”to add current scene to the build list. Then select Android in Platform field, then click “Switch Platform”, and finally click Build to complete packaging.

Figure 4.12 Packaging
Till now, a complete SDK usage process is complete. The specific SDK adaptation methods for various Pico VR hardware will be given in detail in the following sections.
5 Hardware Product Development Guide¶
This section will describe how to use SDK on the various Pico hardware products. Developers can choose to read the corresponding content accordingly.
5.1 Pico Goblin & Pico U¶
5.1.1 Implementing Head Tracking and Stereo Rendering¶
The implementation of head tracking is consistent with the previous SDK QuickStart, just to put Pvr_UnitySDK prefab to the scene. However, there is one thing to note that when Pvr_UnitySDK prefab is placed into the scene, expand it and switch to its details panel:

Figure 5.1 Switch Tracking Options for Pico Goblin
Make sure that Pvr_Unity SDK Manager components have the following attributes: Head Pose: Three Dof; Hand Pose: Three Dof; Controller Num: One.
5.1.2 Using 3dof Controller Prefab¶
Pico 3dof Controller currently supports Pico Goblin and Pico U two devices. Please follow the steps below to use Pico 3dof Controller:
- Expand Assets> Pvr_Controller> Prefabs, place Goblin_Controller prefab into the scene as the child Game Object of Pvr_UnitySDK at the same level as Head.

Figure 5.2 Goblin_ControllerPrefab Drag&Drop Location
- Expand Assets> Pvr_Controller> Prefabs, place ControllerManager into the scene, then attach Goblin_Controller to the Pvr_Controller script of ControllerManager and attach the toast in Goblin_Controller to the Pvr_ControllerManager script.

Figure 5.3 Configure ControllerManager
5.1.3 Using the keys and touchpad of 3dof controllers¶
To use the keys and touchpad of 3dof controllers, it’s necessary to call controller related interfaces. For specific interfaces, please refer to section 6.3 in Chapter 6 Overview of API Functions. Here we’ll explain the corresponding relationship between the parameters of the following interfaces and the physical controller keys.
First about the keys, and the correspondence of the keys and API functions are as follows:
Table 5.1 the Correspondence of Physical Controller Keys and API Function Parameters
Buttons | KeyCodes |
---|---|
![]() |
Pvr_KeyCode.APP |
![]() |
Pvr_KeyCode.TOUCHPAD |
![]() |
Pvr_KeyCode.HOME |
![]() |
Pvr_KeyCode.VOLUMEUP |
![]() |
Pvr_KeyCode.VOLUMEDOWN |
And then the touchpad, and the touchpad diagram is as follows:
Touchpad Diagram¶

Figure 5.4 Touchpad Diagram
Note: The swipe function of the controller determines the end of the swipe only when the finger is lifted.
5.1.4 Using the Goblin HMD Keys¶
Goblin HMD Keys are illustrated below:

Figure 5.5 Goblin HMD Keys
The corresponding relationship between physical keys and Unity input keys are as follows:
Table 5.2 the Correspondence between RGoblin HMD Keys and Unity Input Keys
Goblin HMD Keys | Unity Input Keys |
---|---|
Key 1 | Power Button — System occupied |
Key 2 | Home Key — System occupied |
Key 3 | JoystickButton0 |
Key 4 | Volume+ |
Key 5 | Volume- |
5.2 Pico Neo DK/ DKS¶
5.2.1 Implementing Head Tracking and Stereo Rendering¶
The implementation of head tracking and stereo rendering with Pico Neo DK/ DKS is the same as Pico Goblin and this will not be repeated here.
5.2.2 Enabling Pose Tracking with Split Controllers¶
Pico Neo DK/DKS split controller is illustrated below:

Figure 5.6 Pico Neo DK/DKS Split Controller
If you want to use the pose tracking of split controllers, please expand Assets> Pvr_ExtraSensor> Scripts and attach Pvr_ExtraSensor scripts to the GameObject that you want to track split controller pose with.

Figure 5.7 Enable Split Controller Pose Tracking
When Neo Controller pose tracking is enabled, the PicoVRManager.SDK.boxQuaternion variable will be updated at real-time. You can read the boxQuaternion variable directly or you can obtain Controller’s pose data with the interface public Quaternion getBoxQuaternion().
5.2.3 Using the Split Controller Keys¶
The split controller of Pico Neo DK/DKS adopts the game controller’s standard keys and the keys are distributed as follows:

Figure 5.8 Pico Neo DK/DKS Split Controller Key Distribution
Follow the table below to use the key input of split controller:
Table 5.3 The Key value correspondence of Split Controller and Unity
ID | Key Name | Unity Key Value 1 | Unity Key Value 2 |
---|---|---|---|
1 | A | JoystickButton0 | JoystickButton0 |
2 | B | JoystickButton1 | JoystickButton1 |
3 | X | JoystickButton2 | JoystickButton2 |
4 | Y | JoystickButton3 | JoystickButton3 |
5 | Menu | Menu | None |
6 | Return | Escape | None |
7 | Left Trigger | JoystickButton4 | JoystickButton4 |
8 | Right Trigger | JoystickButton5 | JoystickButton5 |
9 | Power Supply | None | None |
10 | Horizontal Axis | Input.GetAxis(“Mouse X”) | Input.GetAxis(“Horizontal”) |
11 | Vertical Axis | Input.GetAxis(“Mouse Y”) | Input.GetAxis(“Vertical”) |
12 | Pico | None | None |
Please refer to the image below to configure Unity’s input before use:

Figure 5.9 Unity Input Settings
5.3 Pico Neo¶
5.3.1 Implementing Head Tracking and Stereo Rendering¶
The implementation of head tracking is consistent with the previous SDK QuickStart, just to put Pvr_UnitySDK prefab into the scene. However, there is one thing to note that Pico Neo supports multiple tracking methods. Expand the Pvr_UnitySDK prefab and switch to its details panel:

Figure 5.10 Switch Tracking Options for Pico GoblinS
Head Recenter: When Head Pose is Six Dof, you can only reset position by checking “Six Dof Head Recenter”, otherwise, long press Home key can only reset controller poses.
- Show SafePanel:When Show SafePanel is checked, safe panel will be shown when the game starts.
- Head Pose:
- Three Dof, indicates that head tracking is 3 DOF, tracking only poses, not position;
- Six Dof, indicates that head tracking is 6 DOF, tracking both poses and position.
- Hand Pose:
- Three of, indicates that hand tracking is 3 DOF. It tracks poses, but the position is computed based on the head pose and the data of controller sensor. The tracking scope is limited.
- Six Dof, the hand tracking is 6 DOF. Both poses and positions are tracked.
- Safe Range: namely the safe area, divided into 3 types: Min (with radius of 0.5m), Med (with radius of 1m), And Max (with radius of ∞). There will be area prompts and visual darkening effects beyond safe range.
5.3.2 Using 6dof controller Prefab¶
Follow the steps below to use 6dof controllers:
- Place CV_Controller0 and CV_Controller1 prefabs under Pvr_UnitySDK, at the same level as Head. See illustration below:

Figure 5.11 6dof Controller Prefab Hierarchy
- Place ControllerManager prefab into the scene, then enter CV_Controller0, CV_Controller1 for Pvr_Controller in ControllerManager, as illustrated below:

Figure 5.12 ControllerManager Details Panel
To use the controller keys, the interface APIs should be called. Please refer to chapter 6 controller related interfaces for specific API.
Note: We recommend that when you use the motion controller, present the beam and the motion controller in a certain angle, which can increase user comfort and avoid tracking errors caused by blocking ultrasonic modules.

Figure 5.13 Beam Angle Recommendation
5.3.3 Using 6dof Controller Keys and Touchpad¶
To use 6dof controller keys and touchpad, it’s necessary to call interface APIs as detailed in section 6.3. Here we’ll only introduce the correspondence between interface API parameters and physical controller keys.

Figure 5.14 the Correspondence of 6dof Controller Related API Key Parameters and Physical Keys
In addition, the touchpad is the same as 3dof and it will not be repeated here.
6 Overview of API Functions¶
6.1 Get Version Info¶
UPvr_GetUnitySDKVersion¶
Name
- public static string UPvr_GetUnitySDKVersion ()
Functionality
- Acquire SDK version number
Parameters
- None
Return Value
- SDK Version Number
Call Method
- Pvr_UnitySDKAPI.System.UPvr_GetUnitySDKVersion()
6.2 Sensor Tracking¶
UPvr_StartSensor¶
Name
- public static int UPvr_StartSensor(int index)
Functionality
- Enable sensor tracking
Parameters
- Index: 0, main sensor; 1, subsidiary sensor.
- Main sensor is the HMD sensor of Pico Neo DK/DKS, Pico Neo and Goblin, namely the head tracking sensor;
- subsidiary sensor is the sensor of DK/DKS game controller, which is the hand tracking sensor, the same below.
Return Value
- 0: Call succeeded; 1: Call failed
Call Method
- Pvr_UnitySDKAPI.Sensor.UPvr_StartSensor(index)
UPvr_ResetSensor¶
Name
- public static int UPvr_ResetSensor(int index)
Functionality
- Reset sensor tracking
Parameters
- Index: 0, main sensor; 1, subsidiary sensor
Return Value
- 0: Call succeeded; 1: Call failed
Call Method
- Pvr_UnitySDKAPI.Sensor.UPvr_ResetSensor(index)
UPvr_StopSensor¶
Name
- public static int UPvr_StopSensor(int index)
Functionality
- Close sensor tracking
Parameters
- Index: 0, main sensor; 1, subsidiary sensor.
Return Value
- 0: Call succeeded; 1: Call failed
Call Method
- Pvr_UnitySDKAPI.Sensor.UPvr_StopSensor(index)
6.4 Battery, Volume, Brightness Services¶
UPvr_InitBatteryVolClass¶
Name
- public bool UPvr_InitBatteryVolClass()
Functionality
- Initialize battery, volume and brightness services
- (Please call this interface for initialization before using battery, volume and brightness services)
Parameters
- None
Return Value
- Initialization succeeded or not
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_InitBatteryVolClass()
UPvr_StartAudioReceiver¶
Name
- public bool UPvr_StartAudioReceiver ()
Functionality
- Start audio service
Parameters
- None
Return Value
- Whether it’s started successfully or not
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_StartAudioReceiver()
UPvr_SetAudio¶
Name
- public void UPvr_SetAudio(string s)
Functionality
- Notify Unity of the value of current volume when the volume changes
Parameters
- The value of the volume after change
Return Value
- None
Call Method
- This interface is a low-level Android call and unity doesn’t need to call it. If you need to perform any operations when volume changes, write the related logics in this method.
UPvr_StopAudioReceiver¶
Name
- public bool UPvr_StopAudioReceiver ()
Functionality
- Stop volume service
Parameters
- None
Return Value
- Whether it’s stopped or not
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_StopAudioReceiver()
UPvr_StartBatteryReceiver¶
Name
- public bool UPvr_StartBatteryReceiver ()
Functionality
- Start battery service
Parameters
- None
Return Value
- Whether it’s started or not
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_StartBatteryReceiver()
UPvr_SetBattery¶
Name
- public void UPvr_SetBattery(string s)
Functionality
- Notify Unity of the current battery level when battery level changes
Parameters
- The battery level after change (in 0.00~1.00)
Return Value
- None
Call Method
- This interface is a low-level Android call and unity doesn’t need to call it. If you need to perform any operations when battery level changes, write the related logics in this method.
UPvr_StopBatteryReceiver¶
Name
- public bool UPvr_StopBatteryReceiver ()
Functionality
- Stop battery service
Parameters
- None
Return Value
- Whether it’s stopped or not
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_StopBatteryReceiver()
UPvr_VolumeUp¶
Name
- public bool UPvr_VolumeUp ()
Functionality
- Tune up the volume
Parameters
- None
Return Value
- Whether it succeeded or not
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_VolumeUp()
UPvr_VolumeDown¶
Name
- public bool UPvr_VolumeDown ()
Functionality
- Tune down the volume
Parameters
- None
Return Value
- Whether it succeeded or not
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_VolumeDown()
UPvr_SetBrightness¶
Name
- public bool UPvr_SetBrightness(int brightness)
Functionality
- Set brightness (available to regular mobile phone versions, not applicable for Pico Neo)
Parameters
- The value of the brightness (the value is between 0 and 255)
Return Value
- Whether it succeeded or not
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_SetBrightness(bn)
UPvr_GetScreenBrightnessLevel¶
Name
- public static int[] UPvr_GetScreenBrightnessLevel()
Functionality
- Get current screen brightness level (applicable for Goblin only)
Parameters
- None
Return Value
- int array. The first digit is the total brightness level supported, the second is the current brightness level and from the third to the end is the brightness interval values.
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_GetScreenBrightnessLevel()
UPvr_SetScreenBrightnessLevel¶
Name
- public static void UPvr_SetScreenBrightnessLevel(int vrBrightness, int level)
Functionality
- Set screen brightness (applicable for Goblin only)
Parameters
- vrBrightness:brightness mode; level: brightness value (value of the brightness level)
- if vrBrightness passes 1, level should pass the brightness level; if vrBrightness passes 0, representing the system default brightness mode, then level can be set to any value in 1~255.
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_SetScreenBrightnessLevel(vrBrightness,level)
UPvr_IsHmdExist¶
Name
- public bool UPvr_IsHmdExist()
Functionality
- Check if it’s an HMD headset
Parameters
- None
Return Value
- If true, it is HMD; false, not HMD
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_IsHmdExist()
UPvr_GetHmdScreenBrightness¶
Name
- public int UPvr_GetHmdScreenBrightness()
Functionality
- Get current brightness value of current HMD device (applicable for Pico Neo only)
Parameters
- None
Return Value
- Int, current brightness value (in 0~255)
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_GetHmdScreenBrightness()
UPvr_SetHmdScreenBrightness¶
Name
- public bool UPvr_SetHmdScreenBrightness(int brightness)
Functionality
- Set the brightness value of HMD device (applicable for PicoNeo only)
Parameters
- Brightness value (in 0~255)
Return Value
- Whether it’s successfully set or not
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_SetHmdScreenBrightness(brightness)
UPvr_GetCommonBrightness¶
Name
- public int UPvr_GetCommonBrightness()
Functionality
- Get the current brightness value of common devices (applicable for Pico Neo and other regular mobile phones)
Parameters
- None
Return Value
- Current brightness value (in 0~255)
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_GetCommonBrightness()
UPvr_SetCommonBrightness¶
Name
- public bool UPvr_SetCommonBrightness(int brightness)
Functionality
- Set brightness for common devices (applicable for Pico Neo and other regular mobile phones)
Parameters
- Current brightness value (in 0~255)
Return Value
- Whether it’s successfully set or not
Call Method
- Pvr_UnitySDKAPI.VolumePowerBrightness.UPvr_SetCommonBrightness(brightness)
6.5 Setting Surround Stereo Sound (Applicable for PicoNeo DK/DKS Only)¶
UPvr_OpenEffects¶
Name
- public void UPvr_OpenEffects()
Functionality
- Open effects library
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.Audio3D.UPvr_OpenEffects()
UPvr_CloseEffects¶
Name
- public void UPvr_CloseEffects()
Functionality
- Close effects library
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.Audio3D.UPvr_CloseEffects()
UPvr_EnableSurround¶
Name
- public void UPvr_EnableSurround()
Functionality
- Enable surround sound
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.Audio3D.UPvr_EnableSurround()
UPvr_SetSurroundroomType¶
Name
- public void UPvr_SetSurroundroomType(int type)
Functionality
- Set the size of the surround sound mock room
Parameters
- Value of type: 1 - small room, 2 - medium, 3 - large (Surround sound must be enabled first)
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.Audio3D.UPvr_SetSurroundroomType()
UPvr_OpenRoomcharacteristics¶
Name
- public void UPvr_OpenRoomcharacteristics()
Functionality
- Turn on the sound reflection from the mock room wall material when damped (surround sound must be enabled first)
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.Audio3D.UPvr_OpenRoomcharacteristics()
UPvr_CloseRoomcharacteristics¶
Name
- public void UPvr_CloseRoomcharacteristics()
Functionality
- Turn off sound reflection from the mock room wall material when damped
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.Audio3D.UPvr_CloseRoomcharacteristics()
UPvr_EnableReverb¶
Name
- public void UPvr_EnableReverb()
Functionality
- Algorithm to enable echo
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.Audio3D.UPvr_EnableReverb()
6.6 Audio Play¶
UPvr_StartAudioEffect¶
Name
- public void UPvr_StartAudioEffect(String audioFile,bool isSdcard)
Functionality
- Set the absolute path of audio file to play
Parameters
- audioFile, the absolute path that audio files in Pico Android devices.
- For example: string audioFile = “/sdcard/ test.mp3”;
- string audioFile = ” /system/newdir/GuitarLoop.wav”;
- where “isSdcardis” a reserved interface that can be set to true
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.Audio3D.UPvr_StartAudioEffect(audioFile,isSdcard)
UPvr_StopAudioEffect¶
Name
- public void UPvr_StopAudioEffect()
Functionality
- Stop playing audio
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.Audio3D.UPvr_StopAudioEffect()
UPvr_ReleaseAudioEffect¶
Name
- public void UPvr_ReleaseAudioEffect()
Functionality
- Release audio
- (cannot reload audio when it’s called. We recommend to invoke it upon exit)
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.Audio3D.releaseAudioEffect()
6.7 Head-mounted Distance Sensor¶
UPvr_InitPsensor¶
Name
- public static void UPvr_InitPsensor()
Functionality
- Initialize distance sensor
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI. Sensor. UPvr_InitPsensor ()
UPvr_GetPsensorState¶
Name
- public static int UPvr_GetPsensorState()
Functionality
- Get the state of head-mounted distance sensor
Parameters
- None
Return Value
- Return 0 when it’s worn on head, return 1 when it’s away
Call Method
- Pvr_UnitySDKAPI. Sensor. UPvr_GetPsensorState()
- Note: UPvr_InitPsensor should be called for initialization before getting Psensor’s state
UPvr_UnregisterPsensor¶
Name
- public static void UPvr_UnregisterPsensor ()
Functionality
- Release distance sensor
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI. Sensor. UPvr_UnregisterPsensor ()
6.8 Motor Vibration (Available to PicoNeo DK/DKS only)¶
UPvr_HasControllerVibrator¶
Name
- public static bool UPvr_HasControllerVibrator()
Functionality
- Check whether motor vibration is supported
Parameters
- None
Return Value
- Whether motor vibration is supported
Call Method
- Pvr_UnitySDKAPI. Haptics. UPvr_HasControllerVibrator ()
UPvr_SetControllerVibrateMode¶
Name
- public static void UPvr_SetControllerVibrateMode(int[] pattern, int length, int repeat)
Functionality
- Set intermittent vibration mode
Parameters
- int[] pattern =new int[5] { vibrationDuration,silienceDuration,repeat_times, vibrationStrength, whichHaptic }
- vibrationDuration: vibration duration in ms
- silienceDuration: silent duration in ms
- repeat_times: times to repeat
- vibrationStrength: vibration strength (in 0—127)
- whichHaptic: specify the motor: 1 – left, 2 – right, 3 – left and right
- length: pattern length, must be 5
- repeat: set to 1
Return Value
- None
Call Method
- Pvr_UnitySDKAPI. Haptics. UPvr_SetControllerVibrateMode(pattern, length, repeat)
UPvr_SetControllerVibrateTime¶
Name
- public static void UPvr_SetControllerVibrateTime(int milliseconds)
Functionality
- Set continued vibration
Parameters
- Vibration time
Return Value
- None
Call Method
- Pvr_UnitySDKAPI. Haptics. UPvr_SetControllerVibrateTime (milliseconds)
UPvr_CancelControllerVibrate¶
Name
- public static void UPvr_CancelControllerVibrate()
Functionality
- Cancel controller vibration
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI. Haptics. UPvr_CancelControllerVibrate ()
6.9 Hardware Devices¶
UPvr_GetDeviceMode¶
Name
- public static DeviceMode UPvr_GetDeviceMode ()
Functionality
- Get device type
Parameters
- enum DeviceMode, including Pico NeoDKS, Pico NeoDK, Goblin, Pico Neo, Other
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.System.UPvr_GetDeviceMode ()
UPvr_GetDeviceSN¶
Name
- public static string UPvr_GetDeviceSN ()
Functionality
- Get device SN number
Parameters
- None
Return Value
- Get device SN number
Call Method
- Pvr_UnitySDKAPI.System.UPvr_GetDeviceSN ()
UPvr_ShutDown¶
Name
- public static void UPvr_ShutDown()
Functionality
- Shut down
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.System.UPvr_ShutDown ()
UPvr_Reboot¶
Name
- public static void UPvr_Reboot ()
Functionality
- Reboot
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI.System.UPvr_Reboot ()
UPvr_Sleep¶
Name
- public static void UPvr_Sleep ()
Functionality
- Turn off screen
Parameters
- None
Return Value
- None
Call Method
- Pvr_UnitySDKAPI. System. UPvr_Sleep ()
Note: When usingUPvr_ShutDown, UPvr_Reboot, UPvr_Sleepinterfaces, it’s necessary to add the following permissions to AndroidManifest and get system Name:
android:sharedUserId="android.uid.system"
<uses-permission android:name="android.permission.DEVICE_POWER" />
7 Payment System¶
Pico Pay is a game currency payment system based on the Pico account system and it’s settled according to the current game currency unit (P coin) under Pico. If your project needs an in-app-purchase feature, please read this chapter carefully; if not, please ignore this chapter.
7.1 Getting Ready¶
7.1.1 Getting Payment Strings¶
When developers integrate the payment SDK, they need to create an app on the developer platform and obtain corresponding strings. Here is the application process:
- Log in developer platform and register as a Pico member(http://dev.picovr.com/)
- Apply to be a developer
Developers include individual developers and enterprise developers, please apply according to your actual situation. When the submission is reviewed, we’ll give feedback within 3 working days. Please check the status on developer platform timely.
- Check Merchant ID
After becoming a developer, click on the nickname in the upper right corner to view developer ID, which will be the unique merchant identification in the payment system:

Figure 7.1 Merchant ID
- Acquire corresponding strings
Developers can enter the application creation step from the administration center. After clicking create application, first select a platform to publish:

Figure 7.2 Select the Platform to Publish App
Then get into the corresponding platform to complete app related information:

Figure 7.3 Complete App Related Info
Please pay attention to the read area in the above figure and fill in app types carefully. Once filled in, the app type cannot be modified! If there exists an inside-props payment in game applications, we require developers to use the developer backend to add a merchandise code for unified management.
After the app is created successfully, the developer platform will assign it strings, including APP ID, APP KEY, APP Secret:

Figure 7.4 APP ID, APP KEY, and APP Secret
Then select“In-Game Payment Settings” to configure in-game purchase information:

Figure 7.5 In-Game Purchase Settings
Note that the rules for merchandise codes are defined as “first character is for letters, only letters and numbers are allows and no more than 20 characters”. The merchandise codes for different props cannot be duplicated. The props are categorized as consumable props and inconsumable props. Consumable props are merchandise that can be purchased repeatedly, such as gold coins, blood bottles etc.; Inconsumable props are only one-time purchases such as weapons, unlock checkpoints.
7.1.2 Using Payment Strings¶
This SDK has integrated AndroidManifest file. If your project doesn’t include AndroidManifest file, use the file in this SDK directly. If your project already has it, please make sure to consolidate the relevant items in the AndroidManifest of the SDK into your existing AndroidManifest. The items to consolidate includes the following:
Required Permissions:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
Activity declarations:
<activity android:name="com.pico.loginpaysdk.UnityAuthInterface">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:name="com.pico.loginpaysdk.component.PicoSDKBrowser"
android:configChanges="keyboardHidden|orientation"
android:windowSoftInputMode="adjustResize"
android:exported="false">
</activity>
Developer information (domestic)
<!--APPID-->
<meta-data
android:name="pico_app_id"
android:value="APP ID"/>
<!--APPKEY-->
<meta-data
android:name="pico_app_key"
android:value="APPK EY"/>
<!—Authorization scope-->
<meta-data
android:name="pico_scope"
android:value="SCOPE"/>
<!—Developer ID-->
<meta-data
android:name="pico_merchant_id"
android:value="DEVELOPER ID"/>
<!—Pay Key-->
<meta-data
android:name="pico_pay_key"
android:value="APP SECRET"/>
Developer information (foreign)
<!--APPID-->
<meta-data
android:name="pico_app_id_foreign"
android:value="APP ID"/>
<!--APPKEY-->
<meta-data
android:name="pico_app_key_foreign "
android:value="APPK EY"/>
<!—Authorization scope-->
<meta-data
android:name="pico_scope_foreign "
android:value="SCOPE"/>
<!—Developer ID-->
<meta-data
android:name="pico_merchant_id_foreign "
android:value="DEVELOPER ID"/>
<!—Pay Key-->
<meta-data
android:name="pico_pay_key_foreign "
android:value="APP SECRET"/>
Note that the developer info (domestic) and developer info (foreign) in the parameters above can be filled in one group only according to the actual engineering needs. For pico_app_id/pico_app_id_foreign and pico_app_key/ pico_app_key_foreign, please fill in the string obtained officially. As for merchant_id/ pico_merchant_id_foreign and pico_pay_key/pico_pay_key_foreign, please enter the above values if you haven’t got the official values.
Note: In this configuration file, pico_pay_key/ pico_pay_key_foreign corresponds to the AppSecret of the developer platform.
7.2 Using Payment System¶
The payment system workflow is more complex and we have provided a demo for reference. Expand Assets> Pvr_Payment>Demo>Scenes and open the Demo scene:

Figure 7.6 Payment Demo
As illustrated above, the left part of the button represents the method to invoke and the right part, the callback method. Please refer to the above Demo for implementation when you use the payment system
Note:
- There is a “PicoPayment” prefab in the folder Prefabs and it’s used for system callback. Please make sure that you have added this object to your project.
- Bound to the “Callback”script in PicoPayment, some callback data have been pre-processed. If you need to process other data, please modify the content of corresponding functions,
but function names cannot be changed
.
7.3 Description Functional Interfaces¶
7.3.1 Log in¶
- Call method: void Login()
- Callback method: void LoginOrUserInfoCallback(string LoginOrUserInfo)
Where “LoginOrUserInfo”is the login info returned by the backend. A sample format of successful login is as follows:
{"access_token":"25ba00fb73343ff1ec32e1c152fff291",
"open_id":"2890d4a291108e73ef0e87340affe7a4",
"refresh_token":"5a189befeb3b33f7df101fbecffe4f98",
"expires_in":"1d6ef7f25a7b0ec3bbd5b6bf247adf71"}
The following is a sample format of login failure:
{"exception":"AccessToken is null"}
Or:
{"exception":"auth code of response is null}
Here is a sample format of cancelled login:
{"cancel":"cancel"}
7.3.2 Payment¶
- Call method:oid Pay(string payOrderJson)
Where “payOrderJson” is a Json string that contains order information, including:
subject | The subject of the order |
body | Order description |
order_id | Order ID |
total | Total merchandise price |
goods_tag | Merchandise tag |
notify_url | URL to notify |
pay_code | Merchandise code |
Example 1:
Pay("{'subject':'游戏',' body ':'购买完整游戏','order_id ':'10000','total ':'10','goods_tag ':'game' }");
Example 2:
Pay("{'subject':'游戏','body ':'购买完整游戏','order_id ':'10000',','goods_tag ':'game','pay_code':'123' }");
Note: example 1 uses direct pay and example 2 uses merchandise code to pay and these two payment methods cannot be carried out at the same time. Merchandise code cannot be entered in direct pays and “total” property cannot be filled out or set to “0”when using merchandise code. In addition, these two payment methods must be consistent with the payment type configured in developer platform accounts.
- Callback method:void QueryOrPayCallback(string queryOrPayInfo)
Where “queryOrPayInfo” is pay information returned by the backend and the following is a sample format:
{"code ":"12000","msg":"Paid successfully"}
Here is the list of payment callback codes and messages:
Code | Msg |
---|---|
00000 | Network error |
10000 | Login success |
10001 | User not logged in |
10002 | Please enter the correct amount |
10003 | Login expired, please log in again |
11000 | Merchant validation succeeded |
11001 | Merchant validation failed |
11002 | User validation parameter error or request expired |
11003 | Merchant isn’t validated |
12000 | Payment succeeded |
12001 | Payment failed |
12003 | Insufficient P coins |
12004 | Balance available |
13000 | Generating order |
13001 | Failed to retrieve data |
13002 | Failed to create order |
14000 | Order is found |
14001 | Order does not exist/has error |
14002 | User has cancelled payment operation |
15000 | Merchandise info is missing |
15001 | Pre-pay ID is missing |
15002 | Please enter Pico pay order number or merchant odder number |
NOAUTH | Merchant is not authorized for this interface |
SYSTEMERROR | System error |
APP_ID_NOT_EXIST | APP_ID does not exist |
MCHID_NOT_EXIST MCHID | MCHID does not exist |
APP_ID_MCHID_NOT_MATCH | app_id and mch_id does not match |
LACK_PARAMS | Missing parameters |
SIGNERROR | Name error |
NO_DATA | Data not found |
7.3.3 Querying Orders¶
- Call method:void QueryOrder(string orderId)
Where “order” is the ID of the order to query
- Callback method:void QueryOrPayCallback(string queryOrPayInfo)
Where “queryOrPayInfo” is the order information returned by the backend and it’s an unprocessed Json string. The following is a sample format of successful query:
{
"trade_no":"22016082314719505878171324",//Pico pay order number
"open_id":"4f3148bdc34d9bca104927729a173b64",
"ret_msg":"",
"coupon_fee":0.00,
"fee_type":"PIC",
"pay_time":1471950587000,//the time payment completed
"nonce_str":"yiUzuv4VQO1OXBAzVyZSRztOmRgIOioT",
"out_trade_no":"12345678903",
"trade_status":"SUCCESS",//SUCCESS - payment succeeded
"trade_type":"EGG",
"result_code":"SUCCESS",
"mch_id":"company_id",
"ret_code":"SUCCESS",
"sub_msg":"OK",
"total_fee":100.00,//total amount of the order
"app_id":"bf18ac2de375095d63428134e44d1867",
"sub_code":"SUCCESS",
"receipt_fee":100.00,//Actual fee received
"signature":"be3fae4d68fec9c444fde821659bce69",
"buyer_pay_fee":100.00//the fee that the buyer paid
}
A sample format of query failure is as follows:
{"code ":"14001","msg":"Order does not exist"}
7.3.4 Getting User Information¶
- Call method: void GetUserAPI()
- Callback method: void UserInfoCallback (string userInfo)
Where “userInfo” is the user information returned by the backend and it’s an unprocessed Json string. The following is a sample of successful query:
{"ret_code":"0000",
"data":{
"aboutme":"",
"birthday":1460476800000,
"phone":"13100000000",
"username":"Admin",
"email":"",
"gender":"male",
"lastname":"",
"openid":"4f3148bdc34d9bca104927729a173b64",
"firstname":"",
"avatar":"http://172.31.83.11/upload/6dd6ee103714e967846c3d38ae48d511",
"signature":"14a25d7219d8dfc91e55f63286ae5c0a",
"country":"China",
"city":""
},
"ret_msg":"Call succeeded"
}
A sample of query failure is as follows:
{
"ret_code":"00003000",
"ret_msg":"Name validation failed"
}
List of other ret_code and ret_msg:
0000 | Request success |
00020000 | Database operation failed |
9999 | System error |
00001000 | Parameter error |
00002000 | Data parsing error |
00003000 | Name validation failed |
00003001 | Time validation failed |
00060000 | User not found |
00060001 | User password error |
00060002 | User login unknown error |
00061000 | User token not found error |
00061001 | User token validation failed |
00061002 | User token unknown error |
00070001 | App validation failed |
00071001 | App secret key validation failed |
00080001 | OAUTH_CODE validation failed |
00090001 | REFRESH_TOKEN validation failed |
00100001 | ACCESS_TOKEN validation failed |
00110001 | SCOPE validation failed |
7.4 Developer Server Interactions¶
When payment completes, the pay system will send the corresponding pay result and user information to the merchant, and the merchant needs to receive and process them and return a response.
When interacting with backend notifications, if the response that the payment system receives from the merchant is not success or timeout, it will treat it as notification failure and the payment system will periodically resend notifications with a certain strategy to improve the success rate of the notification as much as possible, but it cannot guarantee the success of the notification.
The same notification may be sent to the merchant system many times and the merchant system must be able to process repeated notifications correctly. It’s recommended that when receiving a notification for processing, first to check the status of the corresponding business data and determine if this notification has been processed, then process it if not and return success directly if it’s being processed already. Before checking and processing business data, data lock should be used for concurrency control to avoid data confusion caused by function reentry.
The merchant’s server should implement the following interfaces to receive the requests from Pico server and get payment results and user info from Pico payment system.
Name | Callback interface for payment result |
Request Type | POST |
Request URL | Pay, the parameter “notify_url” that PayOrder passes |
Request Format | JSON |
Return Format | JSON |
Is login required? | Yes |
Request Parameters | See details in “Table 7.1 Params in Payment Result Notification” below |
Example of Request Parameter | |
Update Description |
Return Params
Parameter | Type | Description |
---|---|---|
ret_code | string | Error code |
ret_msg | string | Error message |
Return Param Example
{
"ret_code":"SUCCESS",
"ret_msg":"OK"
}
Table 7.1 Parameters in Payment Result Notification
Field Name | Param Name | Required | Type | Description |
---|---|---|---|---|
Return Status Code | ret_code | Yes | String | SUCCESS/FAILThis field is a notification identification, not a trade identification. The result_code is used to determine whether a trade is successful |
Return Message | ret_msg | No | String | Return message, if not empty, then it’s the reason of the error: Name failed – param format validation error |
Error Code | sub_code | No | String | Error code |
Error code description | sub_msg | No | String | The description of the error return message |
Pico pay order number | trade_no | Yes | String | Pico payment order number |
Merchant order number | out_trade_no | Yes | String | The internal order number in merchant system |
App ID | app_id | Yes | String | The app APP_ID that the platform has audited |
Merchant ID | mch_id | Yes | String | The merchant ID that the payment assigned |
User ID | open_id | Yes | String | The unique ID of the user under the merchant’s appid |
Device ID | device_id | No | String | The ID of the terminal device |
Random string | nonce_str | Yes | String | Random string, less than 32 chars. Random number generation algorithm is recommended. |
Name | signature | Yes | String | Name, see details in Name generation algorithm. |
Business Result | result_code | Yes | String | SUCCESS/FAIL |
Trade Type | trade_type | Yes | String | Payment type |
Currency Type | fee_type | Yes | String | Currency type |
Total Fee | total_fee | Yes | String | Total order amount |
Actual Fee | receipt_fee | Yes | String | Actual Fee |
The amount of the fee the buyer paid | buyer_pay_fee | No | String | The amount of the fee the buyer paid |
Voucher or Discount Amount | coupon_fee | No | String | Vouchers or Discount Amount |
Merchant Packet | attach | No | String | Merchant packets, returning as-is |
Pay completion time | pay_time | Yes | String | The time that payment completes, the format is “yyyy-MM-dd HH:mm:ss” |
Table 7.2 Return Results
Field Name | Param | Required | Type | Description |
---|---|---|---|---|
Return status code | ret_code | Yes | String | SUCCESS/FAIL SUCCESS represents that the merchant has successfully received notification and validated. |
Return message | ret_msg | No | String | Return message, if not empty, then it’s the reason of error: Name failed - parameter format validation error |
Special Reminder: the merchant system must perform Name validation for payment result notification contents, in order to avoid loss of fund caused by “fake notification” due to data leakage.
Name validation rules:
- In the list of returned parameters, remove Name parameter and add “key = “app_secret”, value=paykey”, then perform natural sort according to the value of “key”, use “&”to separate multiple parameters and conduct MD5 encryption.
- Compare the encrypted string with the Name you obtained
The Name function is as follows:
/**
* result: the map collection of retrieved data
* paykey: It’s the paykey on the developer platform
*/
public static String createSign(Map<String, Object> result, String paykey)
{
if (result == null || result.size() == 0)
return null;
result.put("app_secret", paykey); //1.Add key = “app_secret”, value=payke
String sign = result.get("Name");//2.Save Name value, to be used for validation
result.remove("Name"); //3.remove Name parameter
String[] tmp = new String[result.size()];
int i = 0;
for (String key : result.keySet())
{
tmp[i++] = key;
}
Arrays.sort(tmp); //4.natural sort
String sign = "";
for (String string : tmp)
{
if (m.get(string) == null)
continue;
sign += string + "=" + URLEncoder.encode(m.get(string).toString()
, "utf-8") + "&";
}
if (sign.endsWith("&"))
sign = sign.substring(0, sign.length() - 1);
Log.i(TAG, "createSign: " + sign);
String localSign = MD5.MD5(sign); //5.generate MD5 encrypted string
return localSign.equal(sign);//6.validate with “sign” in 2
}
8 Development Considerations¶
8.1 Compatibility with Unity Versions¶
This SDK is compatible with Unity 5.2 and above (supports Unity2017.1.1 and Unity2017.2.0. Other Unity2017 versions are not verified yet). Please pay attention to the following items before integration:
- Some games can only run normally when Use 32-bit Display Buffer in Player Settings is checked during integration.
- There may exist difference of FPS frame rates between different Unity versions.
- UGUI cannot be displayed in Unity 5.3.5f1 version, but this issue has been fixed and it can be displayed in 5.3.5 P5.
- Do not select “Multithreaded Rendering” option in Unity Player Setting.
- In Unity5.4.0 and later versions, it’s necessary to verify the V Sync setting and the steps are as follows: Go to “Edit>Project Settings > Quality”, check “Simple” under “Levels” and make sure that the value of “V Sync Count” under “Other”is “Don’t Sync”.

Figure 8.1 Verify V Sync Settings
- Unity2017.2.0 compilation requires setting target API level to Andriod5.0 (except 2017.2.0f3).
8.2 Android Manifest File¶
If the APP does not contain AndroidManifest file, please use the AndriodManifest file in the SDK directly. It the APP contains the file, please do consolidate the AndriodManifest file from the SDK with it. Here are the major items:
- In Pico Neo DK/DKS projects, add special meta-data, otherwise it won’t display normally.
<meta-data android:name="com.picovr.type" android:value="vr"/>
<meta-data android:name="com.picovr.display.orientation" android:value="180"/>
- In Pico Neo DK/DKS projects, all Activity that require display must inherit
com.unity3d.player.UnityPlayerNativeActivityPico
- Add two Service definitions to the projects that use Pico1 and Pico2 blue tooth controls.
<service android:name="com.picovr.picovrlib.service.LarkConnectService" />
<service android:name="com.picovr.picovrlib.ble.BluetoothLeService" />
- Add necessary permissions
<uses-permission android:name="android.permission.WRITE_SETTINGS"/>
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.INJECT_EVENTS" />
9 Auxiliary Tools¶
9.1 Show FPS¶
If you want to show FPS, please go to the Inspector panel of Pvr_UnitySDK and check “Show FPS in Scene”under Pvr_Unity SDK Manager component.

Figure 9.1 Turn on FPS
10 FAQ¶
10.1 How to configure Camera Culling Mask¶
You can configure Culling Mask property in LeftEye and RightEye Camera in Pvr_UnitySDK.
- If you have integrated with Cardboard SDK and also used toggle culling mask option, you can modify Camera property directly to complete the steps.
- If you need to modify “toggle culling mask”in the code, then refer to the modification method of regular cameras.
- When RightEye and LeftEye cameras need to look at different objects, you can control the layer display, with the Culling Mask of the RightEye and LeftEye cameras in PicoVR, then don’t check right-eye object’s layer in leftEye camera’s Culling Mask nor lefteye object’s layer in the culling mask of RightEye camera.
10.2 How to implement exit functionality in PicoNeo¶
Developers can implement this functionality by themselves or find QuitGame.cs script in the AssetsPicoVRSDKScripts directory of the SDK and drag it onto GameObject of PicoVR, then users can quit by pressing return key when the game is running. Please note that in this case, developers should release the resource dynamically loaded by the game or app.
10.3 How to apply sensor to other objects in the scene¶
Follow the steps below to configure it:
- Uncheck PicoVRHeadTrack script for Head in PicoVR of the scene.

- Choose the objects you want to apply sensor, add PicoVRHeadTrack script.
10.4 What are the requirements on FPS and Scene in order to achieve a smoother effect in PicoNeo¶
FPS:
The FPS in PicoNeo scene cannot be below 30 frames and 45 frames and above are recommended.
Scenes:
Control the triangle slices of the model within 100,000
Control the number of vertex of the model within 100, 000
Control the number of regular unity lights such as electric light source within 50
Control the number of regular unity particle system within 50
Try to use more efficient unity shaders
Optimization examples:
Reduce the number of model slice anchor points while ensuring display
Try to share materials and animations
Try to use compressed texture formats
Use as little light effects as possible
Use static batch processing as much as possible
Optimize scripts to reduce unnecessary consumption of memory, computing and other resources.
10.5 How to replace the loading animation on app start¶
The loading animation replacement on app start is only available to Goblin and Pico Neo, which load the Pico proprietary loading interface before the app is open. If you want to use the default Unity loading interface or customize it, please open AndroidManifest, find platform_logo label and change the value of android:value to 1.

10.6 How to turn off the auto-connection to 3dof when running games on mobile phones¶
On regular mobile phones, after running Pvr_Controller Demo, the game will automatically search for controllers nearby and connect to the first Pico 3dof Controller it found and stop searching when connected. If it fails to connect, it will pop up a window after 15 seconds to prompt the user to search again or stop the search.
If you need to turn off the auto-connect feature, you only need to modify the bool isAutoConnect value to false in Pvr_ControllerLink.cs file.
Contents¶
1 Introduction | Introduction |
2 Device Support | Device Support |
3 Development Environments | Development Environments |
4 QuickStart for SDK Integration | QuickStart for SDK Integration |
5 Hardware Product Development Guide | How to use SDK on the various Pico hardware products |
6 Overview of API Functions | Overview of API Functions |
7 Payment System | How to use Pico game currency payment system based on the Pico account system |
8 Development Considerations | Development Considerations |
9 Auxiliary Tools | Auxiliary Tools |
10 FAQ | Frequently asked questions |