vendredi 10 janvier 2020

How to control a camera with a joystick without spamming messages?

I'd like a recommandation on how to approach the problem I'm facing as a software developer.

Context:

I have an IP Camera that can be moved with a PTZ (Pan, Tilt, Zoom) command that can be called like so:

PTZ(float pan, float tilt, float zoom)

I have a joystick that update its input values every ~0.0001 sec and the available input values are:

  • joystickX: from -1(left) to 1(right) 0 being the center
  • joystickY: from -1(down) to 1(up) 0 being the center
  • joystickMagnitude: from 0(untouched) to 1(completely pushed)
  • zoomButton+: pressed(zoomValue = 1) or not
  • zoomButton-: pressed(zoomValue = -1) or not

Right now, every time the joystick values are updated, a message to the camera is sent, so it's kinda spamming the camera every ~0.0001 sec with PTZ messages.

Ex:

  • Joystick input value update
  • PTZ(joystickX*joystickMagnitude, joystickY*joystickMagnitude, zoomValue) message sent
  • Repeat in ~0.0001 sec

Question:

What would be the best approach to be able to control the camera with the joystick without spamming PTZ messages?

Here's what I have so far:

/// <summary>
/// Bridge between the _form and the actual ConnectXboxController function.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ConnectXboxController(object sender, EventArgs e)
{
    ConnectXboxController();
}

/// <summary>
/// Looks for any xbox controller connected to the client pc and launch a loop to get inputs from it.
/// </summary>
private void ConnectXboxController()
{
    _xboxController = new XInputController();
    if (_xboxController.Connected)
    {
        //set the update/render loop
        Application.Idle += HandleApplicationIdle;
        MessageBox.Show("The controller has been connected.");
    }
    else
    {
        MessageBox.Show("The controller could not be connected.");
    }
}

/// <summary>
/// Closes the connection to the xbox controller and stops the input loop.
/// </summary>
private void DisconnectXboxController()
{
    _xboxController = null;
    Application.Idle -= HandleApplicationIdle;
    MessageBox.Show("The controller has been disconnected.");
}

/// <summary>
/// Updates the input values.
/// </summary>
private void Update()
{
    //Update xbox controller properties

    if (!_xboxController.Update())
    {
        //Stop the loop
        DisconnectXboxController();
    }
}

/// <summary>
/// Apply wanted movement to the camera.
/// </summary>
private void Render()
{
    //Render changes made to the xbox controller properties
    try
    {
        if (_xboxController.LeftThumb.Magnitude != 0)
        {
            _moving = true;
            _camera.PostPTZContinuous(
                _xboxController.LeftThumb.Direction.X * _xboxController.LeftThumb.Magnitude * _camera.Speed,
                _xboxController.LeftThumb.Direction.Y * _xboxController.LeftThumb.Magnitude * _camera.Speed,
                0);
        }
        else
        {
            if (_moving == true)
            {
                _camera.PostPTZContinuous(0, 0, 0);
                _moving = false;
                UpdateCurrentStatus();
            }
        }
    }
    catch (Exception) { }


}

/// <summary>
/// Looks if the application is in Idle state.
/// </summary>
/// <returns></returns>
private bool IsApplicationIdle()
{
    NativeMessage result;
    return PeekMessage(out result, IntPtr.Zero, (uint)0, (uint)0, (uint)0) == 0;
}

/// <summary>
/// Loop to handle the input and the camera movement.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void HandleApplicationIdle(object sender, EventArgs e)
{
    //Stops when the xbox controller is set to null
    while (IsApplicationIdle() && _xboxController != null)
    {
        Update();
        Render();
    }
}

[StructLayout(LayoutKind.Sequential)]
public struct NativeMessage
{
    public IntPtr Handle;
    public uint Message;
    public IntPtr WParameter;
    public IntPtr LParameter;
    public uint Time;
    public Point Location;
}

[DllImport("user32.dll")]
private static extern int PeekMessage(out NativeMessage message, IntPtr window, uint filterMin, uint filterMax, uint remove);

Aucun commentaire:

Enregistrer un commentaire