This article may contain URLs that were valid when originally published, but now link to sites or pages that no longer exist. To maintain the flow of the article, we've left these URLs in the text, but disabled the links.


MIND


This article assumes you're familiar with C++, MFC, DirectX 5.0, and COM.
Download the code (124KB)

Push All the Right Buttons with the Force Feedback Pro
Elaine Chen and Beth Marcus
     
Advanced input devices require advanced programming. When it's a device as cool as the force feedback joystick, the rewards are worth the effort.
If you've been to a video game arcade recently, you've already seen force feedback in action. Many of the latest games have been enhanced with force feedback: racing games with action seats that tilt, rock, and vibrate as you traverse different terrain and steering that responds to driving conditions; skiing games where your body twists and turns as you glide down a snowy virtual slope; even shoot-em-up games now have active recoil features. Activating seats, handles, and steering wheels adds a whole new dimension to the gaming experience. When properly coordinated with synthesized visuals and sound, control feedback can go a long way toward creating a compelling, interactive virtual experience. Instead of interfacing with a slavish computer, the user is drawn into the simulation and becomes part of the virtual world.
      Until recently, force feedback was an esoteric area of academic and military research with applications in virtual reality, space teleoperation, and medical simulation. The mechanical gadgets interacting with the user to provide feedback were dominated by expensive high-performance systems. However, the needs of the entertainment industry are quite different from these high-end applications. What adds realism to a game is not an ability to feel the fine textures on a multifaceted polygonal object, but the ability to feel pulses, vibrations, resistance, and other simple effects. These effects can be provided by lower-end systems with mass-produceable components, and such systems are beginning to appear in the home PC market as force feedback joysticks, steering wheels, and other gaming peripherals.
      The Microsoft® SideWinder® Force Feedback Pro joystick is one of several force feedback peripherals currently on the market. It has two motorized directions of movement, and can provide force feedback through DirectX® 5.0 calls. The SideWinder Force (SWForce) SDK contains lots of information and many code samples showing you how to create and manipulate various force effects. Instead of presenting a comprehensive tutorial of how to use the SDK, we'll provide a brief overview of important force feedback concepts and walk you through the quickest way to get force effects working on your SideWinder Force Feedback Pro. We will also share some insights on joystick performance, force effect interaction issues, and programming with either DirectX calls or the wrapper functions provided in the SDK.

Force Effects for Games
      What force effects are appropriate for a home PC game? Taking combat-type games as an example, it would be appropriate to feel each jolt as your character kickboxes an opponent, violent shivers as you get struck by lightning or an ice ball, and hard impact as you run into a wall. For driving games, you should feel the force of a strong gust resisting the forward movement of your car and vibration as you veer off-track and onto grass or dirt. You would also expect to feel some resistance against steering, just like you would experience when driving an actual car.
      These effects can be loosely grouped into three types of building blocks. First, there are time-based effects such as jolts and vibrations. These are not really related to the orientation of the joystick handle, but instead depend on the temporal profile of the force. Second, there are space-based effects like springs, dampers, and walls. These present a changing force depending on the orientation of the joystick handle and how fast it is moving. Finally, there's invariant effects—constant forces like wind or gravity.

Time-based Effects
Figure 1 shows some representative time-based effects. The simplest one is the jolt or pulse. It is simply a constant force that turns itself off after a given period of time. A reasonably strong jolt might be about a pound-force (lbf) in magnitude and might last half a second or less. If it lasts much longer than that, the jolt starts to feel sluggish and does not produce the proper illusion of impact. A ramp is a force that increases in strength over time. For the ramp to be noticeable, you might want it to last more than a second, although we have found that it feels weak most of the time and aren't sure what real-life event it simulates.

Figure 1: Time-based Effects
Figure 1: Time-based Effects


      Vibrations can have all kinds of different waveforms, from sine waves (very smooth from one end to the other) to triangular waves (similar to sine waves, but with sharper directional changes) to square waves (sharp transitions from one end to another, creating a feedback effect like a machine gun firing) to sawtooth (very jagged). 5 to 10Hz is a good starting point for the waveform frequency. Since people are much better at feeling changes in forces rather than exact magnitudes of a constant force, the same peak force will feel much stronger when applied to a periodic waveform like a sine wave. Therefore using these vibrations really adds a lot of impact to the game.

Space-based and Invariant Effects
Figure 2 shows some representative space-based effects. These effects provide forces that are not a function of time but are updated depending on where the joystick handle is pointing or how it is being moved.

Figure 2: Space-based Effects
Figure 2: Space-based Effects


      A spring effect is simulated by providing force that restores the joystick's position when its handle departs from a given "spring center." For instance, if the middle of the workspace is the spring center, as the handle is pushed to the right, there will be an increasing force pushing it back to the left. The governing equation is F=Kx, where F is the restoring force, x is the distance of the handle from the spring center, and K is the spring constant. A good physical value for K is 50 ounces per inch in the Cartesian (3D) domain. You can convert your own units when working with joysticks (like the SideWinder Force Feedback Pro) that only allow you to work in percentages, or you can tweak the percentages until it feels right.
      A damper (or viscous friction) effect is simulated by providing a resisting force that increases as the speed of handle movement increases. The governing equation is F=Bv, where v is the speed of the joystick and B is the coefficient of viscous friction. If you try to move under water, the resistance you feel is due to this physical phenomenon of viscous friction. A good value for B is something like 2 ounce-seconds per inch.
      A friction effect is simulated by providing a constant resisting force exerted by a surface on a moving object, opposing the direction of movement. The governing equation is F=µN, where µ is the coefficient of friction and N is the contact force between the object and the surface. If you try to push a box full of copier paper down a carpeted corridor, that's the effect you feel.
      An inertial (gravity or acceleration) effect is simulated by providing a force that goes up as a function of acceleration. This is governed by F=ma, where m is the mass and a is the acceleration. If you are swinging a lasso in a circle, the force that the rope exerts on your hand is due in part to an inertial effect. The feelings of gravity and acceleration are not easily presented by a joystick, since acceleration is really sensed in your inner ear and not as a force on your skin. However, if the joystick presents an inertial effect based on acceleration or deceleration in a racing game, your brain makes the connection and provides an illusion of moving with the car.
      A wall effect is very much like the spring effect with a twist: you feel nothing until you impinge on the wall. As you penetrate into the virtual wall, a force pushes you out of the wall along a direction perpendicular to the wall and the force increases as a function of increasing penetration into the wall. This approach models a wall as a very stiff sponge: it gives a little as you push in, but it attempts to push you out nonetheless. This is a standard trick commonly employed in virtual reality applications to simulate the behavior of rigid objects bouncing off each other. The governing equation is F=Kd, where d is the perpendicular penetration of the joystick handle into the virtual wall, and F is the force pushing the stick back out along the perpendicular. K describes the wall constant. On high-end systems you can push K as high as 200 ounce-inches. This is difficult to achieve in home PC joysticks, so to get a crisp hard wall you typically would want to maximize K.
      An invariant effect is independent of time and space. It is simply a constant force which has a given magnitude and direction.
      Space-based, time-based, and invariant effects form the basic building blocks upon which more complicated force effects can be built. For instance, if one vibration of a given frequency is applied on top of a second vibration with a different frequency, the resulting vibration will feel very random. If a wall and a damper are added together, you get the feeling of tapping a wall under water. Depending on when you turn on different effects, you could even concatenate effects so that they happen one after another. For instance, if your flight simulation ended up in an emergency crash landing, you could have a huge impact effect followed by an uneven vibration as the plane skids to a stop—and you could even have a fast and violent vibration as the plane explodes. You could also merge an effect with a temporal envelope. For instance, a sine wave could have a rise time, a starting magnitude, a fade time, and an ending magnitude.

SideWinder Force Feedback Pro
      With this basic understanding of force effects, we can start programming force effects into applications. But first, let's take a look at the physical object that will generate all of these effects.
Figure 3: SideWinder Force Feedback Pro
Figure 3: SideWinder
Force Feedback Pro
Figure 3 shows the SideWinder Force Feedback Joystick. It has a cable that plugs into the game port on a supported soundcard, and—unlike most joysticks—a power supply that plugs into the wall. The left-right and forward-backward movements of the handle are motorized. There is also a third passive twist movement in the joystick that's standard in the SideWinder 3D product line.
       Figure 4 illustrates the system architecture of the force feedback joystick. Computing forces as a function of time or handle position takes a lot of processor power. To achieve smooth, stable, closed-loop control of the motors, a minimum update rate of 500Hz is required. This is achieved in the SideWinder joystick by means of an onboard microprocessor, which communicates with the PC (acting as a host processor) in a bidirectional communication link via a high-level command language. By taking care of the low-level force calculations, the onboard microprocessor ensures smooth and stable closed-loop control of the motors and lets the host processor devote its time to computations related to the game itself. This distributed computation architecture is a good choice for force feedback game peripherals.
Figure 4: Force Feedback System Architecture
Figure 4: Force Feedback System Architecture

      To use the joystick, you need to have the newest version of DirectX 5.0 installed on your computer. Once the system is set up, you can go to the Control Panel, select SideWinder Force Feedback Pro as your joystick device, and test out the functionality of the stick. To program the joystick, you need to install the SWForce SDK as well. (A copy of the SDK can be obtained by request from swinddev@microsoft.com.)

Creating Force Effects
      The newest version of DirectX 5.0 has many features that specifically cater to force feedback devices. DirectX supports four basic classes of standard force effects: periodic effects, which include time-based effects like square and sine waves; condition effects, which include space-based effects like spring and damper; ramp effects, which we described as a special time-based effect; and constant force effects, which we described as invariant effects.
      In addition, DirectX supports OEM-specific effects. In the case of the SideWinder Force Feedback joystick, there are 32 essential effects with suggestive names like random noise, chainsaw idle, chainsaw in action, rocket launch, and wind gust. You could produce a rich gaming experience using just these 32 effects, although understanding the basic building blocks is necessary for creating an optimal force feedback backdrop for your game. The SideWinder Force Feedback joystick also has a wall effect (currently only horizontal and vertical walls are supported) and an ability to download files from a force effect creation utility called Visual Force Factory supplied in the SDK. Currently, the Visual Force Factory only works with the SideWinder joystick, but in future releases it is expected to become DirectX-compatible so it can drive any force feedback peripheral.
      DirectX allows you to create standard or OEM-specific effects with your desired parameters and download them to the joystick. The effects are not activated until you explicitly instruct the joystick to start playing back your desired effect. Each effect is associated with a software handle so you can keep track of your effects and be able to start, stop, modify, or destroy them individually.
      While you can use raw DirectX calls to handle force effects, dealing with DirectX COM interfaces can be cumbersome. Swff_lib.cpp, included in the SideWinder SDK, provides handy wrapper functions that hide a lot of the low-level bookkeeping and allow you to create force effects rapidly. We will first show you how to get an effect to play back on the joystick, then repeat the exercise with DirectX calls so that you can see the difference.

Using Wrapper Functions
      Let's create and play back a square wave effect using SideWinder SDK wrapper functions. Make sure you have DirectX 5.0 and the SideWinder Force SDK installed. You must also link with the files dinput.h, sw_force.h, sw_guid.h, sw_error.h, swff_lib.cpp, and dinput.lib. The first step is to initialize or open the force feedback joystick in Windows:


 // Declare pointers to direct input objects/interfaces/effects
 LPDIRECTINPUT pDI = NULL;             // Direct input object
 static LPDIRECTINPUTDEVICE2 pDIDevice = NULL; // Ptr to DIInputDevice2 interface
                                               // with the Force feedback stuff
 // Open the joystick using SWFF wrapper function: HWND is in m_hWnd in 
 // this application
     HRESULT Hr;
 Hr = SWFF_OpenDefaultFFJoystick(m_hWnd,&pDI,&pDIDevice);
If the operation is successful, you can move on to creating a square wave.
      You need to supply the address of a pointer to a direct input effect. This is the handle with which you can control your new square wave effect. As you can see, you need to supply a lot of parameters. The square wave can be oriented in any direction; 0 degrees results in a square wave that goes in and out, and 90 degrees results in a square wave that goes left and right. The magnitude is expressed as a percentage, where 10000 equals 100 percent, the peak force that can be exerted by the joystick. The offset shifts the waveform up and down. The envelope governs the rise time, the starting magnitude, the fade time, and the ending magnitude. For simplicity, the following code demonstrates a simple centered square wave that turns on and stays on. It moves in and out at 50 percent maximum force (5000) at a frequency of 10Hz (100000):

 // Declare a pointer to the square wave effect
 LPDIRECTINPUTEFFECT pSquareWaveEffect;
 
 // Create an effect in memory
 hresult = SWFF_CreatePeriodicEffect(pDIDevice,
     &(pEffects[FFB_TEST_SQUARE_WAVE]),
     SQUARE_HIGH,    // square waveform
     INFINITE,       // duration in ms: INFINITE lets it run forever
     100000,         // period in ms(.1s=10Hz)
     0,              // orientation(1/100th degrees)
     5000,           // magnitude: 50.00%
     0,              // offset
     0,0,0,0,        // envelope
     -1);            // button: don't tie to anything
      Now the effect is created and downloaded to the joystick, where it is stored in RAM and will not execute until you explicitly start it. This is because you may want to define a lot of effects and set them up as part of your game initialization routine. You can then have software handles to all the effects that are already set up in the joystick, and you can start them inside the game without having to wait for the parameters to be downloaded.

 // Start the effect
 pSquareWaveEffect->Start(1,0);
You can stop the effect at any time; the effect still resides in memory in the joystick, and can be started again at will.

 // Stop the effect
 pSquareWaveEffect->Stop(1,0);
 // Restart the effect
 pSquareWaveEffect->Start(1,0);
      This effect hogs joystick memory (all 2KB of it) until you explicitly destroy it either by using its handle or by destroying everything that you have downloaded to the stick. After an effect has been destroyed, you must go through the creation and download procedure to start it again.

 // Destroy this effect
 SWFF_DestroyEffect(pDIDevice, pSquareWaveEffect);
 PSquareWaveEffect = NULL;
 // Destroy everything: this enumerates all effects and destroys them one by one
 SWFF_DestroyAllEffects(pDIDevice);
Since the joystick can only hold a finite number of force effects in memory, you may need to do a little memory management and cache your effects for different sections of the game. In other words, you may download a lot of effects, then destroy them to make room for new effects appropriate for a new page in your game.

Creating Effects With DirectX
      While the wrapper approach works well for many applications, sometimes it makes sense to use DirectX calls. First, you have much better control over everything, and you impose a lot less function calling overhead. Second, there are some things that just cannot be achieved when using the SWForce wrapper functions (also known as SWFF). For instance, the SideWinder joystick itself supports dynamic modifications of the parameters in an effect after it has been downloaded to memory, but the wrapper functions do not allow you to do that. Once you become familiar with the full capacity of the joystick and the DirectX interface, you'll probably end up writing a wrapper layer that suits your particular needs. Finally, while part of the SWFF wrapper functions is universal, the part of it that deals with OEM-specific effects can only work with the SideWinder joystick. On the other hand, the DirectX interface works with every joystick that supports force feedback. If your applications are created using DirectX, you may be able to reuse more of your code when you want to support more than one force feedback joystick.
      While using DirectX can give you more versatility, you should not assume that all joysticks will behave in the same way with the same DirectX force effect calls. First, the peak force on each joystick is different, so an effect with 100 percent magnitude could feel much weaker on one stick than on another. For this reason, the DirectX interface supplies a SetGain option to scale your forces according to the device. Second, the update rate and inherent dynamic system stability can vary widely from joystick to joystick. Effects that can execute nicely on one joystick can be unstable on another, perhaps because of different transmission dynamics on update rates in the servo control loop. Our advice is to thoroughly retest everything and use caution when supporting multiple force feedback devices.
      Before initializing the joystick with DirectX calls, you must provide a callback function that will be used by the initialization procedure later on. This function tells DirectX to look for the first attached force feedback joystick:


 // Callback for EnumDevices()
 static BOOL CALLBACK EnumCallback(LPCDIDEVICEINSTANCE lpddi,LPVOID lpvContext)
 {
     LPDIDEVICEINSTANCE pInstance = (LPDIDEVICEINSTANCE)lpvContext;
     if(pInstance == NULL) //shouldn't happen
         return DIENUM_STOP;
     if(GET_DIDEVICE_TYPE(lpddi->dwDevType) == DIDEVTYPE_JOYSTICK)
     {
         memcpy((void*)pInstance, (void*)lpddi, sizeof(*pInstance));
         return DIENUM_STOP;
     }
     return DIENUM_CONTINUE;
 }
      To initialize, you need to create a direct input object, enumerate the force feedback joystick (with your callback), and obtain a pointer to the DirectInputDevice interface. Next, obtain a pointer to the DirectInputDevice2 interface (which contains the force feedback features), get rid of the now superfluous DirectInputDevice interface, and use the DirectInputDevice2 interface to continue the initialization. (This interface stepping is, of course, standard in COM.) It takes a few more lines of code than using the wrapper functions (see Figure 5).
      Now you need to set up the square wave effect and start it. Note that this effect is identical to the one we created with the wrapper functions (see Figure 6).
      Once you have created the effect using DirectX, you can try to modify the parameters directly, which is one of the things not supported by the wrapper functions. The code in Figure 7 will change the current 50 percent, 10Hz square wave to 100 percent strength running at 5Hz.
      To destroy all effects, you need to supply a callback function that will dump them as they are enumerated by the device interface.

 // Kill off all existing effects in the joystick
 static BOOL CALLBACK DestroyAllCreatedEffects(LPDIRECTINPUTEFFECT pEffect,
                                               LPVOID lpvRef)
 {
        RELEASE(pEffect);
        return DIENUM_CONTINUE;
 }
After all the downloaded effects are found and destroyed automatically, the joystick is unacquired and the DirectInput object and device interface are released.

 // Find and destroy all downloaded effects in the stick
 if (pDIDevice->EnumCreatedEffectObjects(DestroyAllDownloadedEffects, 
        NULL, 0) != SUCCESS)
        return FFBE_JOYSTICK_SHUTDOWN_FAILED;
 // unacquire joystick and release DI and DI Device
 pDIDevice->Unacquire();
 RELEASE(pDIDevice);
 RELEASE(pDI);
Demo Program
       Figure 8 shows a program that demonstrates how you might create, keep track of, and manipulate force feedback effects. Both the SWFF wrapper and DirectX approaches are shown. Representative members of each type of force feedback effect (standard spatial, standard temporal, and OEM-specific canned, walled, and file download effects) are included.
      Most of the effects turn on when the corresponding buttons are pressed, with one exception: we set up the sawtooth demo to fire when the trigger button is depressed. This is a nice feature in DirectX that allows you to tie a given effect with a given button state. The response is much more immediate; it almost feels like a reflex action, and would be appropriate in situations like administering a vibration whenever a machine gun is in action.
      The code shows how simple it is to create force effects using the SideWinder wrapper functions. It also shows how lengthy the code can get when using the DirectX interface. Again, the choice is up to you. This demo program exercises many of the joystick capabilities and showcases the ability of the joystick to add effects on top of each other.
      One important observation is the effect of saturation. When many effects are on at the same time, they start to drown each other out. The forces are added according to currently running effects, but there is a peak force dictated by the specifications of the joystick, and the output force is truncated to that force. It is therefore possible to add vibrations to springs with various offsets and end up with something that feels like a constant force in parts of the workspace.
      The joystick also has a natural bandwidth. We noted that 10Hz is a comfortable frequency for vibrations—that is approximately the bandwidth for voluntary movement of our hands (people really can't move much faster than that). Higher frequencies can simulate different effects like the vibration in an idling chainsaw, but after a point the force magnitude starts to become seriously attenuated. This is simply because the joystick, being a physical device, has a dynamic response that cannot follow very high-frequency motions. We have found that at 50Hz the handle hums rather than moves around as it would at 10Hz. The joystick would not even perform correctly when commanded to vibrate at 100Hz. Therefore, 50Hz seems to be a good ballpark cut-off point for vibration frequency.
      The SideWinder Force Feedback Joystick has relatively low friction, and the peak force is adequate for most purposes. It does feel a little weak at a 1 pound (16 ounce) peak when operated in constant force mode, but the vibration and spring effects all feel decent. There is no doubt that it adds a lot of spice to any home PC game.

Conclusion
      The SWFF library functions make cool effects very easy to program even for someone with little or no background in force feedback. All the complicated interface methods in DirectX are hidden and most of the functionality can be accessed through simple, understandable calls to wrapper functions. The DirectX interface is a bit cumbersome, but once you figure it out, you can access more functions than are available through the wrapper functions. Force feedback adds a lot of value to a game application and is certainly worth the effort to implement it. The synergistic effects of coordinated visual, audio, and touch feedback create a realistic gaming experience that will be as addictive as it is novel.

From the June 1998 issue of Microsoft Interactive Developer.