Velocity-Based Joystick Controller


Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame

Click here for a larger image.

Environment: VC6 SP4, NT4 SP3, Win2K

Currently, I am working towards building an omni-directional autonomous mobile robot. Omni-directional refers to a vehicle that could translate (or move) and spin (or rotate) simultaneouly. Just for an example, your car is not an omni-directional vehicle. As part of this ongoing project, I was assigned the job of building an application that could control the robot's motion from a desktop, remotely, rather than using a physical joystick as a child would normally drive his "Remote Toy Car." The application should be able to spit commands for both the modes of action (move and spin), simultaneouly. So, I did one and called it the Joystick Controller. Here is a part of it that is developed as the user interface.

The Joystick Controller is built as a stand-alone subclass that is derived from CStatic. To use this in your application, all that needs to be done is subclass a static control (the placeholder for the joystick control) in the dialog with the provided CJoystickCtrl class. For testing and demonstration purposes, the provided application shows a pie-shaped wedge that moves and rotates (with respect to the center) in the left half of the window. The different modes of action for the joystick are mapped to the various mouse events.


For a mouse click event in the Stick region (the gradient filled region of figure above):

  • Left Mouse Button Down: Increases the velocity of movement by a value equal to the distance between the mouse click point and the center of the joystick. For generalization purposes, the value is mapped between 0 and 10. The direction of the line from the center of the joystick to the mouse click provides the direction of the movement.
  • Left Mouse Button Up: Brings back the joystick's stick region to the stand-alone mode. In this mode, it spits only zeros.
  • Right Mouse Button Down: Same as that of left mouse button down except that it does not move to the stand-alone mode on the Right Mouse Button Up event.

For a mouse click event in the Spin region (the arced region of the figure above):

  • Left Mouse Button Down: Increates the velocity of rotation by a value equal to the distance between the mouse click point and the point of half the arc-length. Again, for generalization purposes the values are mapped between -10 to +10. The sign of the generated value gives the direction of rotation. Negative for anti-clockwise and positive for clockwise rotation.
  • Left Mouse Button Up: Brings back the joystick's spin region to the stand alone-mode—so spits only zero.
  • Right Mouse Button Down: Same as that of left mouse button down except that it does not move to the stand-alone mode on the Right Mouse Button Up event.

The basic idea of the implementation is that we should be able to issue a rotation command while something is already moving or vise-versa. Moreover, it should be able to issue variable commands based on the desired velocity; in other words, the farther you drive from the center, the faster the dependent object moves.

The demo application (previewed in the picture above) shows a pie-shaped structure (the dependent) in the left half of the window—moving and rotating simulataneously. The speed by which the pie moves or rotates is totally controllable by the joystick on the other half of the window.

Steps to Add This to Your Project

Say, m_Joystick is the object you make for the IDC_JOYSTICK static-object in the dialog box. Add the following line in the InitDialog for a dialog-based application (or in the equivalent funtion in a window-based application):

m_Joystick.SubclassDlgItem(IDC_JOYSTICK, this);

This is all is required to get the joystick to show up on your window. To get the direction of movement, the velocity of movement, and rotation, one can use the following public functions provided as members of the CJoystickCtrl class.

// To get the move direction.
// this is with respect to the center (0, 0) of the joystick
CPoint GetMoveDir();

// To get the rate at which to move
// Is mapped between 0 to 10
int GetMoveRate();

// To get the rate at which to move
// Is mapped between -10 to 10
// Negative value indicates anti-clockwise rotation and
// Positive value indicates clockwise rotation
int GetAngle();
This control can easily be used to control the movement and orientation of moving objects in the real world. At least, for now it is successfully being used to control my ROBOTS.


Download demo project - 29 Kb
Download source - 7 Kb


  • subclassing problem

    Posted by JTZ on 01/02/2007 08:25am

    hi when i use an object of CStatic i do not get any joystick control showing in the static text box container. When i use an object of CJoystickCtrl i get the joystick in the static text box but only the arrow key event handler functions are working - there never seems to be any trigger from the mouse - no mouse event handler functions operate. I am using visual studio .net 2005. thanks for your help regards james

  • To add this to a doc/view application

    Posted by Legacy on 11/15/2002 08:00am

    Originally posted by: Hitesh

    Here are the steps to add this to an doc/view application

    1. Declare a variable of type CJoystickCtrl, say m_JoystickCtrl, in your view class.

    2. For the CJoystickCtrl class implement the PreCreateWindow
    funtion and add lines for registering the window.
    The function would looks something like the following:

    BOOL CJoystickCtrl::PreCreateWindow(CREATESTRUCT& cs)
    // TODO: Add your specialized code here and/or call the base class

    if (!CStatic::PreCreateWindow(cs))
    return FALSE;

    cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS,
    ::LoadCursor(NULL, IDC_ARROW), (HBRUSH) GetSysColorBrush(NULL_BRUSH), NULL);

    return TRUE;

    3. Add a CRgn object, say m_JoyWndRgn, to the CJoystickCtrl
    class that holds the region of the complete window (and not
    just the window that is being drawn and updated). You can
    create this region when all other variables are intialized
    in the OnPaint function. This region would be required in
    the Erase background funtion so that the complete window
    can be redrawn everytime the size of the parent window

    4. Add the following lines to the OnEraseBkgnd function

    BOOL CJoystickCtrl::OnEraseBkgnd(CDC* pDC)
    // TODO: Add your message handler code here and/or call default
    pDC->SelectClipRgn(&joyWndRgn, RGN_COPY);
    return CStatic::OnEraseBkgnd(pDC);

    5. After the creating the parent view, create the joystickCtrl window.

    BOOL CJoyDocViewView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)
    // TODO: Add your specialized code here and/or call the base class

    if (!CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext))
    return FALSE;

    CRect joyRect(100, 100, 400, 400);
    if (! m_Joystick.Create(_T(""), WS_VISIBLE | WS_CHILD | SS_SIMPLE, joyRect, this, IDC_JOYSTICK))
    return FALSE;



    return TRUE;

    You should see the joystick working.

    You can change the color in the header file to suit your view background.

    Hope this is helpful.

  • Please give an example how to add this control to a doc-View instead of dialog

    Posted by Legacy on 11/14/2002 08:00am

    Originally posted by: wawa24

    works good in Dialog

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date