javaandroidc++openvr

Custom OpenVR driver, with jittery android rotation


I'm working on a simple (I thought) OpenVR driver that sends the compositors output to my android phone to display with google cardboard. I've got the basics working but when my driver receives the rotation data from my android device it's very noisy and with my phone sat still on my desk it jitters loads.

the floats are being sent over in network byte order.

Here is the code receiving the rotation data:

float BytesToFloat(unsigned char* buffer, int start)
{
    float f = (buffer[start] << 24) | (buffer[start + 1] << 16) | (buffer[start + 2] << 8) | buffer[start + 3];
    return f;

}

void MobileDeviceReceiver::PoseThread(std::function<void(MobileVector*)> PoseUpdateCallback)
{
    sockaddr_in client;
    int inLen,clientStructLen = sizeof(client);

    MobileVector currentPose;

    DriverLog("started pose tracking thread %d\n",m_isActive);

    bool errorLastCall = false;

    char pchBuffer[65535];

    while (m_isActive)
    {
        if ((inLen = recvfrom(m_socket, pchBuffer, 65535, 0, (sockaddr*)&client, &clientStructLen)) == SOCKET_ERROR)
        {
            if (errorLastCall == false)
            {
                DriverLog("Error receiving data: %d\n", WSAGetLastError());
            }
            errorLastCall = true;
        }
        else {
            errorLastCall = false;
        }

        currentPose.x = floorf(BytesToFloat((unsigned char*)pchBuffer, 0)*10000)/10000;
        currentPose.y = 0;//BytesToFloat((unsigned char*)pchBuffer, 4);
        currentPose.z = 0;//BytesToFloat((unsigned char*)pchBuffer, 8);

        PoseUpdateCallback(&currentPose);
    }


}

And the code sending it from the phone:

class Task implements Runnable
{
    public Queue<DatagramPacket> packets = new LinkedList<DatagramPacket>();
    private boolean isActive = true;

    @Override
    public void run() {
        try{
            DatagramSocket socket = new DatagramSocket();

            while(isActive)
            {
                if(packets.size() > 0)
                {
                    socket.send(packets.remove());
                }
            }

        }catch(Exception e)
        {
            e.printStackTrace();
        }
    }

    public void Kill()
    {
        isActive = false;
    }
}

ByteBuffer buffer = ByteBuffer.allocate(12);

    protected float ALPHA = 0.05f;

    private float[] lowPassFilter(float[] input,float[] output)
    {
        if(output == null) return input;

        for ( int i=0; i<input.length; i++ ) {
            output[i] = output[i] + ALPHA * (input[i] - output[i]);
        }

        return output;
    }

    @Override
    public void onSensorChanged(SensorEvent sensorEvent) {
        if(sensorEvent.sensor == sRotation)
        {
            float x,y,z;
            x = (float) Math.toRadians(sensorEvent.values[0]);
            y = (float) Math.toRadians(sensorEvent.values[1]);
            z = (float) Math.toRadians(sensorEvent.values[2]);

            float[] values = lowPassFilter(new float[]{x,y,z},new float[3]);

            buffer.order(ByteOrder.BIG_ENDIAN);
            buffer.putFloat(values[0]);
            buffer.putFloat(values[1]);
            buffer.putFloat(values[2]);

            try {
                DatagramPacket packet = new DatagramPacket(buffer.array(), 12, InetAddress.getByName(IP), 8888);

                if(task != null) {
                    task.packets.add(packet);
                }
            }catch(Exception e)
            {
                e.printStackTrace();
            }

            buffer.clear();
        }
    }

Thanks in advance


Solution

  • For future reference I was doing two things wrong:

    1. I was sending the float in network byteorder and not rearranging it to native byte order on the local machine.
    2. Bitshifts don't seem to work for floats, so I used memset instead.

    After changing these two things it all worked perfectly.