Stratus3 and open GDL

Stratus3 ADSB-in receivers are marketed as having “open-GDL” mode, meaning they can be used with any EFB app. While that is technically correct, Appareo (the manufacturer) is not being entirely honest in this claim. If anyone in the vicinity of the Stratus3 attempts to connect to its wifi signal using Foreflight, then it will automatically switch to “Foreflight-only” mode. You can’t undo this even with a reboot. You have to install the Stratus Horizon Pro software to re-enable the open-GDL mode. Unfortunately, the Stratus Horizon Pro app will only run on Apple iOS. So if the reason you don’t use Foreflight is because you are not a fan of Apple, this turns the $700 Stratus3 into an expensive paperweight. All of this can only be interpreted as Appareo implicitly forcing their customer towards Apple and Foreflight.

It also seems Appareo has shared information with some other commercial EFB developers how to switch the Stratus3 back to open GDL. But they appear to be guarding this information closely. The truly open source EFBs like Avare are left without any help, even though Appareo continues to market its product as compatible with open-GDL.

Avare users are not “customers”. They are a community. They are also not afraid to try something new. As a community member, I wanted to find a solution to this problem. After all I believed Appareo’s claims and paid good money to buy their Stratus3. With a borrowed iPAD, I was able to run a wifi snoop to detect the command strings that were being exchanged. If you need that information, please contact me directly, or look in the Avare forum on googlegroups.

The long and short of it is, I was able to write a small Android app that can toggle the Stratus3. It is a pretty basic app that sends the command strings and then looks for the ADSB data packets. You can find this app on Google Play.

Modifying Xplane cockpits using Blender/Gimp

For pilots using Xplane for maintaining proficiency or for flight training, it is important to have a cockpit layout similar to their real airplane. Unfortunately, Xplane does not make this process simple. Creating the same look and feel of your own airplane requires building new instruments and applying custom textures. Documentation on how to do this is sparse, and in many cases they simply don’t exist. It took me quite a while to figure this out. You have to get into the nuts and bolts of how Xplane runs. In this post I will attempt to summarize my experiences in the hope that it can alleviate some frustration for those in a similar situation.

Software

For 3D modeling I use Blender (version 2.82), and for editing 2D images I use Gimp (version 2.10). Of course there are other options, such as AC3D and Photoshop, but Blender and Gimp are free. These are powerful tools to have in your back pocket, regardless of Xplane. A forewarning, though: they are not easy to learn. It is strongly recommended you first follow one of the many comprehensive tutorials available for Blender and Gimp. Trying to figure out Xplane without a good knowledge of Blender is guaranteed to be a frustrating experience.

Xplane’s file structure

The nice thing about Xplane is that all of the aircraft-related files are in plain text form. They can be opened with an editor like notepad or vim. The root file of each airplane has the extension .acf. This file contains all of the aerodynamic definitions as well as the names of the 3D objects that make up the visuals. One important thing to realize is that the flight model and the visual model are completely decoupled from each other. The 3D objects are for visual effects only, and have no impact on the flying characteristics. In other words, you can make the airplane look like an elephant, and still make it fly like a glider.

Even though .acf is a text file, it is meant to be opened only with Xplane’s Plane Maker. When you open this file in Plane Maker, you will be presented with an external view of the airplane. You can go into the Object menu on the left panel and check all of the various objects that make up the airplane’s visual models. To see the cockpit panel, you will have to uncheck the fuselage, seats and other objects that are in the way, and zoom up real close (use “=” for zooming in).

The flight model is in separate menus on Plane Maker. This is where you can set engine and propeller information, wing dimensions, fuselage cross sections and a whole lot of information that determine the flying characteristics. Changing these parameters will have no effect on the visual representation. Modifying the flight parameters is relatively easy, so I won’t discuss it here.

The acf file references a bunch of other files, but the 3D objects are the ones I will discuss here. These files are under the directory objects/. There will be sub-directories as well, and each panel instrument is likely to be in its own directory. Each 3D object has an extension .obj. Examples of 3D objects include altimeter, radios, GPS, yoke, etc..

Xplane2Blender

This is a plugin for Blender that allows one to export from Blender to Xplane’s obj format. Here is a snapshot of my plugin panel.

Xplane2Blender plugin

Unfortunately, despite what its name might suggest, this plugin does not import Xplane’s objects into Blender. It is strictly a Blender-to-Xplane exporter only. If you are looking to modify an existing airplane in Xplane, this is where you will hit the first major obstacle.

However, not all is lost. If you google obj file format, the first ones that come up are the wavefront obj. Wavefront is also a 3D file format, and is surprisingly similar to Xplane’s obj file structure. It is relatively easy to write a script to convert Xplane’s obj into wavefront obj, and then read it into Blender. However, all of the Xplane animations and commands will be lost during this translation.

There are other 3D programs like AC3D and Sketchup that have import modules for Xplane objects. As far as I know, none of them will preserve the animations and manipulations. In my case, I decided it is best to start by learning Xplane’s obj file format and see if it can be manually imported.

Xplane’s obj file format

As mentioned earlier, this is a plain text file. The first block contains the name of the texture files used to wrap the object. If you don’t know what a texture file is, you should review the concept elsewhere. It is widely used in Blender as well as in any 3D modeling software. Texture files are typically in PNG or DDS format. Three texture files are used in Xplane: a default texture, a lighted texture (parts that glow in the dark) and a normal map texture. The default texture is sufficient for now. I’ll say more about the others later.

Preamble and texture files in Xplane’s obj file

The next block is a large table of vertices. Each line is a vertex, and begins with the prefix “VT”. It contains the x,y,z co-ordinates of the vertex , its vertex normal (which is also x,y,z) and the u,v texture co-ordinates for that vertex. So there is a total of 8 numbers for each vertex.

Vertex array in Xplane’s obj file

The astute reader might question why we need a normal texture file when there is a normal attached to each vertex. It is a good question. I don’t know the exact answer, but it apparently has something to do with better surface rendering.

The next block references the vertices that form the individual triangles of a mesh structure. Each line begins with a prefix “IDX”. This is basically the position of each vertex in the previous vertex table. So “0” refers to the first item in the vertex table, “1” refers to the second item and so on. For brevity, these are arranged in blocks of 10, using the prefix “IDX10”. In the example below, the first triangle is created by the 0th, 1st and 2nd vertices in the vertex table.

Index array in Xplane’s obj file

The next block is where the mesh structure is created. The prefix is “TRIS”, and it has the starting IDX number and the number of vertices that form that mesh. Since a mesh is created from triangles, the number of vertices here must be a multiple of 3. Prior to the TRIS command, a number of Xplane-specific attributes are specified. Manipulators specify an action, such as a push button, a throttle lever, or flip switch, etc.. They will also include the Xplane’s internal variables connected to that manipulation. Animation specify how the part moves in response to an internal variable of Xplane. It is not important to understand the exact format of these attributes since Xplane2Blender will take care of this for the most part.

Animation attributes in Xplane’s obj file

Wavefront obj file format

This is also a text file. Although conceptually very similar to Xplane’s obj, it is not exactly the same. In this case, the first block contains the x,y,z co-ordinates of the vertices using the prefix “v”. The vertex normals are listed in the next block with the prefix “vn”. The next block contains the u,v texture co-ordinates, using the prefix “vt”. So, instead of listing everything in one block, they are presented in three separate blocks of data. Then the “o” prefix is used to name the mesh, followed by all the triangle faces that make up that mesh. The triangles are specified with the prefix “f” (for face) followed by three groups of numbers “a/b/c”, where “a” is the vertex index, “b” is the normal index and “c” is the texture co-ordinate index. The texture file is specified in a separate file, which is referenced in the obj file with the command mtllib (for material library). Wavefront obj is an open format, and further details can be looked up from Wikipedia.

Converting Xplane obj to Wavefront obj

My first task was to write a python script to convert Xplane’s obj to wavefront obj. This was surprisingly easy, and it worked within a few tries. However, as mentioned earlier, the manipulators and animations cannot be converted because wavefront has no concept of these. So you will basically end up with a 3D structure without any of its manipulators or animations. They would had to be added later by hand in Blender. As far as I know, there is currently no way to import these functions into Blender. But in principle, this should be doable (because once you add these functions by hand, they are preserved within Blender, so there is no reason why they cannot be imported). In any case, I am not familiar with Blender’s file format to attempt this task. Hopefully someone else will.

My python code for converting Xplane’s obj to wavefront is here. This code was thrown together with just a basic knowledge of python. I am not a computer programmer, and my code by no means is complete or complies with standard coding techniques.

To run the code, invoke the script with the obj filename as the first argument. This is going to depend on your operating system, so I can’t provide exact directions. On linux, this is how you would run it. First, download and save the python file as xplane2obj.py. Make it executable with chmod +x xplane2obj.py. Then in the command prompt window type ./xplane2obj.py myfile.obj where myfile.obj is the filename of the Xplane object. It should run with no screen output. If there are any printed messages, chances are something is wrong. Upon completion, there will be two other files created in the same directory. The first is myfile_WF.obj. This is the wavefront object. The second is myfile.mtl. This file contains the reference to the texture file. It is assumed the texture file has the same name as the obj file, in a DDS or PNG format (i.e., myfile.DDS or myfile.PNG). If the name of the image file is different, or its format is different, just edit the mtl file and insert the correct names.

Running the python script on a linux console

Next, open up Blender and import the wavefront obj file. If the texture file is in the same directory, you should be rewarded with the 3D object exactly as in Xplane.

Shown here is the airspeed indicator from the Xplane’s default C-172 aircraft, loaded into Blender.

Airspeed indicator from Xplane’s C172 imported into Blender

Understanding Datarefs and Commands

A dataref is an internal variable of Xplane. For example, sim/cockpit2/gauges/indicators/airspeed_kts_pilot is the variable for the indicated airspeed. A complete list of datarefs can be found in the Resources/plugins directory of Xplane. There is also a searchable website, but I have found that the information there is sometimes different from what is in my Xplane. In any case, there is very little documentation on what each variable does. You have to guess based on its name. You can also use a dataref monitoring plugin (DataRefTool is a good one) while running Xplane, and see what values are contained in each dataref and then make an educated guess from there. Some variables are writeable, meaning you can use it to send information to Xplane. Some are read-only. Even the writeable ones don’t always stick. They may get overwritten by Xplane.

Commands are supposedly different than datarefs. They are meant to perform an action in Xplane. For example, sim/engines/throttle_up will increase the throttle up a bit. But you can also write a value to the dataref sim/cockpit2/engine/actuators/throttle_ratio[0] to do the same thing. The difference between writeable datarefs and commands is still unclear to me. The recommendation seems to be to use a command whenever possible instead of writing to a dataref. The complete list of commands can be found in Resources\plugins directory, but also on a searchable website (again, I have seen difference between what’s on that website and my Xplane).

Animating an object

Once the object is in Blender, animation is easy. For example, if you want to make the airspeed needle move, you need to allow it to rotate based on a dataref value. Here is how to do it:

First, you need to separate the airspeed indicator into two different mesh structures – the body and the pointer. Then, place the origin of the pointer at the pivot point of the required rotation (you need to look up how to do that). On the animation tab, select an animation keyframe number (we typically select 1 for the first keyframe, but it really doesn’t matter which number you select). Rotate the needle and place it where it should point when the airspeed is zero. Then save this keyframe position.

Find the Object Properties tab, and expand the Xplane properties. Click on Add Dataref. Then put in the dataref for airspeed. In this case, it is sim/cockpit2/gauges/indicators/airspeed_kts_pilot. Next we need to select the type of animation. There are three types of animations: Transformation (which is a movement), Show (which makes the object appear) and Hide (which makes the object disappear). Here we want Transformation because rotation is a transformation. Making sure the keyframe is in the first position, type in 0.0 in the Value box. Then click on the Add Dataref Keyframe button (just hitting return is not enough). The color of the value box should change as soon as it is accepted. Now we have assigned 0.0 knots to the first keyframe. Then add a second keyframe, rotate the needle to a different airspeed value, and type in the appropriate airspeed for that keyframe. Two keyframes should be sufficient for objects that behave linearly. For nonlinear motions, or for a more accurate representation, more keyframes are better.

Animating the airspeed pointer

That’s pretty much it. We now have animated the airspeed indicator. When this object is exported, the obj file will contain the appropriate ANIM attributes to correctly display the airspeed.

Exportable Collections

Ideally, we should have a single .blend file for the entire airplane. This way everything can be lined up and visualized prior to exporting it to Xplane. To keep each object distinct, they should be placed in a different collection. A collection is a concept unique to Blender. Think of it as a folder within the blender file. Each collection will produce a separate obj file when exported.

Not all objects need to be exported. Some might be there just for your own reference when designing in Blender. There is an option in the Scene Properties tab to specify which collections should be exported. So check the boxes next to all the objects you want exported. Regardless of what you specify here, only the visible collections will be exported. That means you can always hide a collection (by clicking on the “eye” icon next to the collection) and that collection won’t be exported.

Specifying exportable collections

Under the Exportable Collection box, there is a separate pull-down menu to specify if this object is an Aircraft Part, Cockpit Object or Scenery Object. An airplane can have many Aircraft Parts, but can have only one Cockpit Object. Obviously, Scenery is not relevant for our discussion. Manipulators (clickable objects) can only exist in a Cockpit Object. Assigning a manipulator to an Aircraft Part will produce an error during export from Blender. Additionally, even though Blender will allow you to tag multiple objects as Cockpit Objects, only one will be eventually designated as Cockpit Object in Plane Maker. This is a potential area of confusion. I’ll say more about this later.

Specifying the collection type as Aircraft Part or Cockpit Object.

Replacing textures or redesigning an object

After importing the airspeed indicator into Blender, you may want to replace its texture image, or scrap the whole object and redesign from scratch. In either case, take an actual photograph of the airspeed indicator, and UV wrap that onto the object. This is where having experience in Blender comes in helpful. I am not going to describe how to do all that. It is standard fare in Blender.

The image files should be in PNG or DDS form. Supposedly, DDS format renders faster. Both formats work with Xplane, and both can be edited with Gimp. The width and height of the image must be scaled to a power of 2, such as 512 x 512, or 512 x 1024 etc.. Of course, smaller images are better for speed. A lot of work is needed at this stage. For the example with the airspeed indicator, the pointer needs to be inconspicuously erased. We can place the erased portion in a separate location to texture the new pointer, or simply create a white rectangle as the new texture. It depends on how fancy you want to get.

Modifying a photograph to create the texture for airspeed indicator

Also worth mentioning is that each object does not need to have a separate texture file. The same texture file can be shared across different objects. For example, the body of the airspeed indicator and the pointer (which are different objects within the same collection) can share the same texture file. It is common practice to assemble multiple images together, like a collage, into a single texture file.

UV wrapping the texture to an airspeed indicator

As mentioned earlier, Xplane uses three separate texture files. These should be put in the Scene Properties tab (this item is under the same place where you check the Exportable Collection box). This value has no impact on how Blender displays the objects. This is strictly for inserting the appropriate file names when Blender exports these objects.

Assigning Xplane texture files

Manipulators and the Cockpit Object

Manipulators are objects in the cockpit that you click, drag or rotate with a mouse. Examples are throttle control, yoke, switches, etc… If you have joystick controls for all functions and don’t intend on using a mouse at all, then these manipulators may not be necessary. However, even with an external yoke/rudder/throttle quadrant, we may still need to push buttons to program the GPS, or autopilot etc..

Since all of the manipulators were lost in the Xplane-to-wavefront conversion, we need to recreate them. The default Cessna 172 has hundreds of manipulators, and recreating them in Blender would take a lot of time. But as a pilot, I don’t really care if the simulator has every little switch and control knob. Light switches, door knobs and even master switches are not necessary for my purpose. This eliminates nearly 80% of the manipulators from the default Cessna 172.

A manipulator is assigned in Blender the same way as an animated dataref. As stated earlier, only the Cockpit Object is allowed to have manipulators, and there can be only one Cockpit Object. As a result, all of the manipulators are combined into a single object. On the default Cessna 172, this file is Cessna_172SP_cockpit.obj, which can be found in the root directory of the aircraft folder. Every push button, lever, knob etc.. has an associated clickable object in this file. They are rendered with an invisible material, so they won’t appear on Xplane.

If you open the file Cessna_172SP_cockpit.obj with a text editor you will see that it has no associated texture file. That’s because nearly nearly everything in it is a hidden object. (Actually, there can be a few visible objects in this file, which will be wrapped with an internal texture file cockpit_3d\-PANELS-\panel.png. I’ll discuss this in detail later). If you convert this obj file to Blender, it will show a 3D cockpit layout, but it will look a bit weird. Most objects here have simple shapes – circles, rectangles, cubes etc.. Every object here exists only for the purpose of capturing the mouse clicks. The Blender view of this file is shown below.

All of the clickable objects in the cockpit object

Let’s consider the throttle lever. If you display it along with the actual throttle lever (which is part of the cockpit_panel.obj), it will look like shown below.

Animated clickable object for the throttle

In this example, the grey cube overlaying the throttle lever is the clickable object for the throttle. It is set as a Drag Axis (push-pull) manipulator. The Hand setting tells it to display a hand icon (in Xplane) when the cursor is over it. The dataref for this manipulator is sim/cockpit2/engine/actuators/throttle_ratio[0], which is a writeable dataref. The other values in the manipulator setting specify the range of values to assign to this dataref when the throttle is moved. The clickable object has to be animated as well (using the same dataref), because it needs to move as the throttle is pushed in. The actual throttle should also have the same animation using the same dataref, so both the clickable object and the real throttle always stay together.

Not all clickable objects need to be animated. The clickable object for a push button, as shown on the autopilot below, is a simple rectangle sitting over the actual button. The button itself is animated (to show a pressed state), but the clickable object does not need to be animated because the button does not move very far when pushed.

Assigning a manipulator to the clickable object

All of the manipulation objects in the Cockpit Object collection should be drawn with a single material type that should be designated as invisible. This is done in the Materials Properties panel by unchecking the “Draw Objects with this Material” as shown below. If it is checked, then all these grey objects will show up in Xplane, making a very ugly panel.

Making the cockpit objects (clickable objects) invisible

In Xplane, all of the clickable objects should show up in green if the View->Show Instrument Click Regions is enabled. This is shown below.

Viewing clickable objects on Xplane

Cockpit Display Screens

Cockpit instruments that contain a screen, like the GNS430 or the G1000 are a different object type. Their screens should be drawn as rectangles in the same Cockpit Object collection, but using a different material that is not hidden. This material should also be designated as “Part of a Cockpit Panel”. These objects will ultimately get textured in Xplane by an image file located in cockpit_3d\-PANELS-\panel.png. We don’t need to specify this texture file in the export collection parameter list. Xplane will automatically do that.

GNS 430 screen placement

When Xplane runs, it will draw the various screens to panel.png during every frame cycle. Actually, the panel.png file is just a template. It doesn’t actually get overwritten during every frame cycle. Instead, the file contents are held in memory and updated during every frame cycle to show the screens.

The code for producing the displays such as GNS430, GNS530, G1000, and a large number of other instrument displays are in the Xplane’s main engine. But a custom display can also be written with an external plugin. For example, in my cockpit, I have two G5 screens (purchased from AFM), GNS 430 (purchased from RealityXP), and Avitab for the iPAD tablet. I opted for RealityXP’s GNS430 because it more closely resembles the real thing than Xplane’s internal GNS430. The default Cessna 172’s panel.png size is 1024 x 1024. This was too small to fit all of the above screens. So I increased it to 2048 x 1024. All you have to do is to create a new blank panel.png file of the size you want. But like any other texture file, the size must conform to the power-of-2 rule.

We can get the contents of the panel.png memory by executing the command sim/operation/make_panel_previews (using the DataRefTool plugin). This will write the image to a file named Panel_Preview.png in the cockpit_3d\-PANELS-\ directory. Every cockpit screen should write to a different area of the image. Overlapping images will obviously screw up all the display screens. Avitab has an option to specify the pixel location of its image within the panel.png file. RealityXP also has an option to specify its image location. The snapshot image is shown below. For some reason, the G5 screens were not showing, but I had to do some trial and error and figured out it was actually being written to the lower left corner.

Panel_Prview.png image showing various screen displays

In the C172’s acf file, we also need to disable Xplane’s own GNS430 screen as well as the GNS530 screen. Even though I had deleted the GNS530 object from the Cessna 172’s avionics stack, Xplane will continue to write its screen output in panel.png. This is obviously unnecessary and will only slow down Xplane. This can be easily removed from the acf file with a text editor. In fact there is another group of objects labelled RUBBISHNUTNECESSARY, which as far as I could tell, is a bunch of annunciators that serve no purpose, so I removed all of them as well.

The acf file can be edited to delete the screen displays not being used in the aircraft.

The Panel_Preview.png file can be used to UV map the displays to the correct areas of the file (panel.png file cannot be used because it is a blank file). Even though we are using Panel_Preview.png, Xplane will actually use its internal panel.png to texture the object during runtime.

UV mapping the GNS430 screen to the correct portion of the panel.png file

Using Planemaker to add screens to panel.png

Planemaker has built-in instruments that can be placed on the panel.png texture, and then UV mapped to an object. This menu is under Standard-> Panel: 3D. There are a large number of these instruments, ranging from simple light indicators to EFIS panels. Below is an example of placing an EFIS on to panel.png in Planemaker.

Example of adding an Xplane’s internal EFIS into the panel.png texture
This is the Panel_Preview.png snapshot with the EFIS

In the above example, we could map the image of the EFIS to a cockpit panel.

Designing the GFC-500 Autopilot

In this section, I will describe the steps for designing the GFC-500 autopilot. This autopilot does not come with Xplane, so it is a useful learning exercise.

Using the cockpit panel in Blender as the backdrop (which is cockpit_panel.obj), use a primitive cube to create a box of the correct size and and place it in the desired location in the avionics stack. Place this cube in a new collection called GFC500. One could also create the bezel around the front face to give it a more realistic look, but I didn’t. The best time to make such modifications on the cube is now, before UV unwrapping it. Its hard to make structural changes later.

Blank cube for the autopilot in Blender

The next step is to take an actual photograph of the unit and use it to UV wrap onto this cube. A texture is needed for the side faces as well, which can be a simple patch of black on the image. At this point, all the buttons and knobs are just images, not actual objects.

UV wrapping the photograph to the unit

Then create a few primitive cubes and place them over the buttons, making them project slightly outwards like a real push button. Make sure these cubes are all in the same GFC500 collection.

Creating buttons with primitive cubes

The next step is to apply textures to the small cubes. The same texture file as the body can be used for this. Repeat this for all of the buttons on the panel.

Applying the texture to the buttons

The next step is to create a clickable object for each button to serve as manipulators. You can simply duplicate the cubes, or draw clickable rectangles on the faces of the buttons. Make sure to move these clickable objects to the Cockpit Object collection. These clickable objects should be assigned the same invisible material as the other manipulators.

Creating click regions for the buttons

Next we need to assign commands to the clickable objects. For example, the ON button on the autopilot should engage the servo motors. The command for this function is sim/autopilot/servos_toggle.

Assigning manipulators and commands to the click regions

Next, the button (not the clickable object) should be animated to show the pushing action. Hide the cockpit object collection out of the work space, and create two keyframes for the button. The first keyframe will be the normal state (sticking out a bit), and the second keyframe should be in the pushed state (flat with the panel face).

Animating the button

Then a dataref has to be attached to this manipulator. We could use the dataref sim/cockpit2/autopilot/servos_on but we can also do it differently. We can use a temporary dataref derived from the command. This can be done with CMND=sim/autopilot/servos_toggle. This dataref will produce a value of 1 when the command is being invoked (button pushed) and 0 when the button is not being pushed.

The above steps should be adequate to make the push button work, but we should also create the annunciator corresponding to that button. On the GFC500, a white triangle pointer lights up when a button is pushed, and it extinguishes when the button is pressed again.

Draw a simple triangle above the button, and use the same texture file used for the autopilot with a small white patch to color it.

Creating the annunciator

This triangle has to be animated, but it does not need keyframes because it does not move. It simply appears and disappears. This can be done in the Object Properties tab – the same place where we assign dataref values for animated objects – except this time choose Show as the animation type. Then select sim/cockpit2/autopilot/servos_on as the dataref and assign the conditions when it should be shown and when it should be hidden. Some of these values are not clearly documented, so you would have to run DataRefTool inside Xplane to find out.

Animating the annunciator

We have to repeat this for all buttons on the panel. We also have two rotating knobs for changing altitude and headings, push buttons to synchronizing current altitude and heading, and a wheel for changing vertical speed. All of these need appropriate manipulators, animations, and keyframes.

Various knob controls

I also chose to add a tiny LED screen on the GFC500 to show the requested vertical speed. This display does not exist on the real GFC500. In Planemaker (under Panel: 3D), I placed an object named EFIS_disp_VVI.png in an unused parts of the panel.png. In Xplane, I took a snapshot of Panel_Preview.png. Then in Blender, I created a tiny display screen on the face of the GFC500 (in the cockpit objects collection) and used the Panel_Preview.png to UV wrap this screen.

Here is how the finished product looks

You can download my fully completed GFC500 autopilot object file for Xplane here, and the blend file.

Exporting objects from Blender

Click on File->Export->Xplane (obj). The file name is not relevant. Blender will export all visible exportable collections using the names of the respective collections. Alternate names can be specified for each collection in the Exportable Collections panel. If there are any errors, it will be in an internal log file named xplane2blender.log. Blender uses internal files (i.e these are not written to disk). You can access this with the Blender’s text editor.

Next, copy the obj files and their texture files into the Xplane aircraft directory. You could create a separate directory named objects/custom to keep your objects separate. Then fire up Plane Maker.

Importing objects into Plane Maker

Make a copy of the acf file you are modifying, and open that file. Under Standard->Author, write the appropriate description of this airplane so that it is recognizable in Xplane.

Next, go into Standard->Misc Objects. This is where all the 3D objects are assembled. If the object was placed in the desired location in Blender, there is no need to adjust the X,Y,Z position or rotations here. They could all be set to zero, and the objects should be in their correct positions.

Placing 3D objects into Plane Maker

The Int Cockpit is the radio button that indicates it is a Cockpit Object (the one that contains manipulators). Hi-res should be checked for instruments that require higher resolution rendering. The Inside/Outside/Glass Inside/Glass Outside control how these items are displayed, and there is a pop-up help available for these options.

Once all the objects are added to the list, go to the front page of Plane Maker, hide all the items except the ones related to the panel. Zoom in close using the “=” key. It should look something like the figure below. If it does, then the next step is to open it in Xplane.

Plane Maker view of the panel

Check it out in Xplane

The last step is to open the airplane in Xplane and check for the expected look and functionality.

The image below shows a new airplane I created to mimic my club’s Cessna 182R, starting from Xplane’s default Cessna 172. In addition to the instruments, I had to add a landing gear switch, fuel pressure, manifold pressure, cylinder head temperature and a bunch of other things. I tried texturing the panel based on an actual photo. The propeller and engine specifications were changed to match the 182. Overall, it flies nearly identical to the real 182, and it will serve as a great training tool for maintaining proficiency.

The real Cessna 182R
Xplane (modified from default Cessna 172)

Lighted Textures and Normal Textures

Objects are displayed using the default texture whenever there is ambient light. As the ambient light declines (at dusk or at night), the default texture slowly disappears and is replaced by the lighted texture. The lighted texture is basically the portions that should glow in the dark.

A lighted texture can be created by modifying the default texture in gimp. It is important to start from the same texture file because the same UV co-ordinates are used for both textures, so every pixel’s position should remain at the same location. There is also a nifty light filter tool in gimp that can be used to create the illusion of a light bulb. The layering concept in gimp is a great way to cut different parts of the image and modify them separately.

Default texture
Lighted texture

While the default texture is allowed to have an alpha channel (transparency setting), the lighted texture should be opaque. In other words, all non-emissive areas should be drawn in black. This can be easily created in gimp by creating a layer with a black fill, and then laying the portions that should be emissive on top of it.

The real Cessna 182R
Xplane (modified from default Cessna 172)

Normal maps allow surfaces to be rendered with fine structural details without adding extra vertices. These can be created in Blender by first creating a high-resolution object with lots of features, and then mapping those features to a low-resolution object using a process known as baking. Among other things, baking can be used to create a normal texture file. When applied to a low resolution object this will make it look similar to the high-resolution object.

CNC hot wire foam cutter

This CNC foam cutter was built from a kit by https://rcfoamcutter.com. It basically consists of two carriages for the horizontal translations and two towers for the vertical translations. I’ve built two prior CNC foam cutters (not using this kit), and the main challenges with those DIY designs were uneven sliding friction and wobble. These problems have been mostly solved in this kit by using plastic bearing sleeves for friction reduction and two linear shafts per axis to reduce wobble. However, it became clear later that the wobble is primarily due to lack of straightness in the acme lead screws. Any small bends in the screws will producing a rocking motion of the carriages, which will show up as ripples in the foam edges.

The stepper motors are 6-wire NEMA 23 motors with 2A drive current. The driver board was built from a kit by Hobbycnc (Model #4AUPCWHC). This board includes PWM control of the cutting wire temperature . Unfortunately it appears that they don’t make this board any more. 

The control signals are sent via a parallel port connector. The motors need a hefty power supply (up to 8A max), and the hot wire (30-gauge NiCr) also needs a separate power supply.

Most computers nowadays do not come with a parallel port. Although there are USB-to-Parallel converters, they will not work for CNC control because it is impossible to deliver accurate timing signals through the USB port. The solution is to get the UC100 CNC motion controller. It looks like an ordinary USB-to-parallel converter, but it is not. It has embedded circuitry and software drivers to produce the precise signals required for CNC motion control. This allows any laptop with a USB port to be used to drive the CNC. The UC100 is best used with the Mach3 software, which is one of the most widely used CNC software. However, it is a generic CNC software, so some customization (known as “screens”) is necessary. The screens for foam cutting setups can be found in many online forums. I bought mine through Ebay from http://www.foamwings.ru/f-scr_eng.php.

The input commands for the Mach3 software are written in G-codes. These are ascii commands that tell the motors how far to move, and how fast. Some drawing packages such as Inkscape allow saving the vectors as G-codes, but none of them work straight out of the box because the foam cutter drivse two pairs of axes – two left axes (X & Y) and two right axes (A&B). Most conventional CNC systems use a single pair of X & Y axes with a Z axis for the height of the cutting tool. There are several software specifically made for foam cutting that can produce four axes G-codes (such as devFoam, Foamworks, Jedicut). However, G-codes for simple non-tapered designs can be easily created from Inkscape, or even from an Excel spreadsheet. The codes can be viewed using a variety of software, such as Camotics.

The moving hot wire melts the foam by convective and radiative heat transfer. Therefore, the width of the cut will be larger than the wire diameter. This is known as Kerf, and must be compensated in the design. Kerf is a function of wire diameter, wire temperature, cutting speed and foam type. The best way to determine wire temperature is by using an ammeter to measure the current through the wire. For a given foam type and foam thickness, the temperature is directly related to the current. Low density foam will cut easily and will produce a larger kerf. Slower cut speed will result in a larger kerf. Therefore, the optimum cut speed and temperature has to be determined for each foam type. The thickness of the foam also matters. A thicker foam will draw more heat away the wire, and will require a higher current to maintain the same temperature.

A short tutorial on creating G-codes using Inkscape

This example uses characters, but the same procedure can be used to create cuts from line drawings as well.

  • Using inkscape, write the text. A thicker font will be better to give the foam more meat.
The word FOAM written using the Ravie font
  • The letters have to be connected, otherwise they will not stay together after the cut. In this example, we can place thin rectangles (bars) between the letters to connect them.
Letters with connecting bars
  • Then switch to outline view. This will show the connecting rectangles as outlines, but the fonts will stay solid. This is because the fonts are lines, not shapes.
Switch to outline view
  • The next step is to convert the letters to shapes, and also combine the letters with the rectangles to create a single structure. This is done by the Union function. Select everything and then click Union. This will produce an outline of the entire object.
Connecting rectangles combined with the Union function
  • We also need to make access points for the internal holes in the letters O and A. Place small rectangles to make these access cuts.
Small rectangles for accessing the internal cuts in O and A.
  • Unlike the connecting rectangles, these rectangles need to be subtracted from the main object. Select one rectangle, then the main object (with shift-select), and click Difference. Then repeat for the next rectangle.
Small rectangle Differenced with the main object
  • There is still one more thing to do. The entry point for the wire has to be defined. By default, the wire will enter from the topmost point in the trace, which right now is the top of the letter “A”. We want the wire to enter from the top left corner of the letter “F”. To make this happen, draw a very thin rectangle above F to make it the highest point in the structure. Then combine it with the trace using Union. If this rectangle is very skinny, it won’t show up in actual final cut.
Final trace with the small stub at the starting point
  • Next, select Tools library under the Gcodetools extension. Select the default tool and click Apply.
Setting the default tool library for G-code generation
  • This will create a table of parameters for the Gcode generation. We don’t need to modify anything here because none of the settings are relevant for a four-axis foam cutter. We will have to manually edit the gcode file afterwards.
Gcode Tool library settings
  • Move the parameter box out of the way. The (0,0) point is on the lower left corner of the page. I typically like the cut to start from the top left of the shape, so I move the shape below the bottom left corner of the origin as shown below.
Shape is placed below the bottom left corner of the page.
  • Under the Gcodetools menu, select Path to Gcode. Accept all the default values except the directory where you want the file to be written, and the file extension (change the .ngc to .gcode). Remain on the Path to Gcode tab and select Apply.
Path to Gcode creation menu
  • After the Gcode is created, the trace will change to include small arrows to show the direction of the cutting tool along the trace. The file will have the extention .ngc
After Gcode creation
  • The file will have to be edited with a text editor and modified to match the foam cutter requirements. I usually delete all the preamble and add the following lines:
G17    ( PLANE SELECTION = XY )
G21    ( UNITS = MM )
G90    ( DISTANCE MODE = ABSOLUTE )
M3     ( HOT WIRE = ON )
S30    ( HOT WIRE POWER = 30% )
G4 P5  ( DWELL TIME = 5 SEC )
F150   ( CUTTING SPEED = 150MM/MIN) 
  • The main section will begin with G00 (rapid movement) in the Z axis to feed the cutter into the work piece, and then another G00 along XY to the first point on the trace. I delete all Z axis movements, and replace the G00 with G01 for a slower translation.
  • The main section of the cut trace contains the X, Y and Z axes for linear translations and two additional I and J fields for arcs. On the foam cutter, we have two towers with X, Y, A and B, with the A and B slaved to the X and Y. Therefore, the Z axis is not relevant.
G01 X1.232711 Y-4.768690
G01 X1.232711 Y-7.792300 Z-0.125000 F400.000000
G01 X0.786227 Y-13.993470 Z-0.125000
G03 X1.843255 Y-14.379883 Z-0.125000 I1.879872 J3.503417
G03 X3.365914 Y-14.539170 Z-0.125000 I1.522659 J7.198067
G03 X4.855470 Y-14.401778 Z-0.125000 I-0.000000 J8.143328
  • The end of the file must contain the following lines:
G01 X0.0000 Y0.0000
M5    ( TURN OFF WIRE HEAT)
M2    ( END OF FILE )
  • Open the gcode file using CAMotics. This will show an animation of the cutting process.
Viewing the result in Camotics
  • Load this file into the Mach3 software and execute the cut.

Dayton Daily New Article

This is an article I wrote to the Dayton Daily News, which appeared on Saturday May 5 2012.


Tom Hausfeld, the pilot of the ill-fated flight on April 1, might be alive today if not for the poor decisions to erect buildings on the approach path of incoming airplanes. While fear is being raised about the possibility of airplanes falling off the sky on innocent people, the true hazard is actually the other way around. When Tom lost engine power, he was required by the Federal aviation regulations to maneuver the airplane away from persons or property on the ground. This is exactly what he did. Not a single piece of metal fell on anyone outside the airport fence. It is also evident that he struggled to hold the airplane high enough to clear the roofs of the buildings that were on the approach path, which robbed him of the precious last few knots of airspeed that is so essential for staying airborne.

The foremost tragedy in this story is that we lost a fine citizen and a fine aviator of our community. The second tragedy is how this is being spun to advance the interests of businesses and other groups. The pilot and his passenger were the victims here. The hazard was the building. How anyone can turn that story around is amazing to me. Munroe Muffler built a shop at the very edge of the runway, and then goes on the news media complaining about low flying airplanes.

The fact that airplanes fly low just prior to landing is not a new phenomenon. This is how airplanes were flown since Orville and Wilbur. The FAA and the laws of physics require airplanes to fly in a shallow 3-5 degree glide angle during approach. At Wright Brothers airport, this means the airplanes have been crossing the fence at roughly 75 ft altitude for nearly half a century. Several years back I recall looking down during a final approach, at the construction site where the gas station and the Munroe shop now sits, wondering why in the world anyone would choose to build there knowing the risk it poses to aircraft. That choice ended up costing the lives of two innocent people.

Residents are understandably concerned about the possibility of airplanes crashing into their homes. However, it can be verified from the NTSB records that statistically this is an extremely unlikely event. Nevertheless, public perception is still important, and communities and airports need to work together to create a mutually safe environment. But that is a two-way street. Erecting buildings with no regard to aircraft safety, and then accusing pilots of flying too close to those buildings is not an environment that creates mutual trust. Communities such as Settler’s Walk can write their own rules on how airplanes should fly, but unless such rules are incorporated into the Federal registry they will have little or no effect. Airport operations are not regulated by city, state or residential communities. Airports are part of a vast national network, and operate under federal regulations. Airplanes flying here from Florida or Texas or even just from Cincinnati cannot be expected to know about the covenants of Settler’s Walk or the opinions of Munroe Muffler.

 

Andrew Sarangan

Professor

University of Dayton

Flying to Canada

PDF file of this article

Let me start with a disclaimer that I am not the expert on international flying. My experience comes solely from having made several trips between Ohio and southern Ontario to visit friends and family. When I first checked into this, I received all kinds of totally irrelevant information, such as international flight plans, radio licenses, HF radios and wilderness survival gears. Even AOPA’s write-up did not help much.

This article is written in the hope that it might be of some use to pilots looking for first-hand information about flying to Canada. This is probably the easiest international flight any pilot could make. Canadian aviation is almost identical to ours, except for a few minor differences.

The first airport of landing in Canada must be a designated airport of entry, and you must arrive during their normal operating hours. Most Canadian airports near the U.S. border as well as larger ones further north are most likely to be designated airports of entry. Canada Customs operating hours varies from one airport to another. Smaller airports might only offer weekday service, but busier airports will have customs service at all hours including weekends. A complete listing can be found in the Canada Border Services Agency website. There is also a special program called CANPASS which allows pilots to land at additional airports outside normal operating hours, but that requires a special application and an annual fee, and is really only intended for frequent travelers.

Flight plans are mandatory and the aircraft must remain in contact with ATC with a discrete squawk code while crossing the border. Filing IFR is the best way to go. IFR flight plans are handled seamlessly across the two countries regardless of where you file. I am told that VFR flight plans are not handled the same way, and may require two separate flight plans to be filed with each country, with separate activation and termination as you cross the border.

Detroit, Lake Huron, Montreal and Halifax Sectional charts cover large parts of Canada

Obtaining aeronautical charts is the most frustrating part. Canadian charts are not available on the internet due to copyright rules. I am not even aware of any paid service where you can download their charts. It is a major pain in the neck. If you are planning the flight the night before, as I often tend to do, you will be out of luck. But you can get away without buying Canadian charts if you are willing to take the unofficial route. All areas of Canada below the 49th parallel are covered by U.S. charts. That includes Toronto, Ottawa, Montreal, Quebec City, and the entire provinces of New Brunswick and Prince Edward Island. What a deal! The FAA has a disclaimer that the information outside the U.S. may be unreliable, but that is up to you. However, if you insist on buying Canadian charts, it is cheaper to get them mailed from a Canadian store. In addition, U.S. FBO’s near the border might also be a potential source for Canadian charts.

Before departing from your home airport, call Canada Customs on their toll-free number 1-888-CANPASS. You will be asked for an ETA, passenger names, citizenship and dates of birth. Once you depart, it works just like any other domestic flight. The Canadian and U.S systems are virtually transparent under IFR. You won’t even know which country’s airspace you are in. It was interesting that most of southwestern Ontario is under Cleveland Center’s airspace. You will be flying in Canadian airspace talking to a U.S. controller. Go figure. Handoffs were a nonevent. Cleveland hands you off to Toronto Center somewhere near London, Ontario.  Toronto Center might hand you off to Montreal Center if you are going further east. There are some minor differences in the ATC language. They say “radar identified” instead of “radar contact”. They call “Terminal” instead of “Approach”. Canadian aircraft identifiers begin with a “C” followed by four letters and contain no numbers.

Upon landing, you call the same 1-888 number to report your arrival. It is best to do this from the aircraft with a cell phone. They will give you an arrival record number which you should keep in a safe place. I’ve been told that customs agents make random inspections and may show up to check your documents. However, of all the times I have landed in Canada, I have never seen a customs officer.

Canadian rules require VFR flight plans for all flights greater than 25 NM. The format is quite different from ours and it could be very confusing. The best thing to do is confess to FSS that you are not familiar with the format. They were more than happy to talk me through the flight plan. There are other differences. Tower will automatically open and close VFR flight plans. At non-towered airports, unless you tell the briefer otherwise, the flight plan will be activated at the proposed time. If you do not depart as planned, it is important to call FSS and amend or cancel the flight plan. They are very serious about search and rescue up there.

Airspace designations are somewhat different too. Class C airspace is treated like our class B. Class D looks much like our class C. They also have a class F. It can get pretty confusing. On the plus side, they don’t appear to be as rigid about the airspace rules as we are here. It was a more relaxed atmosphere. We filed IFR as much as possible, so this was not an issue for us. An interesting observation is that I was able to file using DUATS and still get my clearance from the local ATC.

If you are flying in the Toronto area, a visit to the City Center airport is highly recommended. It is a magnificent airport on an island just walking distance from downtown. It has a landing fee, but it is cheaper than parking a car in downtown. The view of the downtown area with its famous CN tower is breathtaking, and you can circle over the city without being pursued by fighter jets.

 

Coming back into the U.S is a much more serious affair. Similar rules apply, such as having to land at designated airports of entry during their business hours. There is no central toll-free number for U.S customs. You have to contact the individual customs office listed in the CBP website. There are two kinds of airports: international airport of entry, and customs landing rights airport. I am still unclear on the practical difference between these; they both seem to be the same. To avoid complications in case of a diversion, delay or emergency landing, it is important to clear customs as soon after entering U.S airspace as possible. We normally land at Sandusky, OH for two reasons: it was very close to the Canadian border, and it has an on-site customs office. We were told that on-site officers are more relaxed and less cranky than off-site officers who would have to drive to meet us. Upon landing, it is imperative that you stay in the airplane until the officer comes to meet you. There is a customs declaration form, and is best to have this form filled out ahead of time. The officer will ask for passports, aircraft registration, pilot certificate and medical. We found the officers at Sandusky to be friendly and courteous, but I have heard horror stories about other locations.

There is a $25 per calendar year fee for U.S customs services. You can pay this online, and you will receive a decal in the mail which should be attached to the aircraft door. If you don’t have time to wait for the decal to arrive in the mail, you can bring the printout of the online receipt as proof. In some cases, you can purchase the decal directly from the customs inspector, so it is best to check all of this ahead of time. If you are paying the inspector, it is best to have the application form filled out and have exact change before you arrive.

One last thing. NavCanada will send you a bill for ATC services. It is about $12, and is good for three months.

VOR as a course Instrument

By: Dr. Andrew Sarangan (October 2003)

PDF file of this article

The vast majority of pilots use the VOR as a command instrument – turn left when the needle deflects left, and turn right when the needle deflects right. Then they learn about reverse sensing. If the OBS is set to the reciprocal course, the commands become reversed – turn right when the needle deflects left, and turn left when the needle deflects right. Naturally, most prefer to stay away from reverse sensing. As a result, they do a lot of knob twisting to keep the desired number at the top of the OBS. Those who use the five-T’s mantra would recall that one of the T’s stands for twisting the OBS knob. This technique works fine for the most part, but there is a simpler and more elegant way.

It is a less known fact that the original VOR receiver was designed as a course instrument. It was not designed as a “fly left” “fly right” indicator. This is why the needle was called a Course Deviation Indicator. This is also why there is a full circle of numbers on the face of the VOR. The needle points to the hemisphere where the selected course lies. The triangle pointer (also called the TO/FROM flag) points to the hemisphere where the station lies. Together, they point to a quadrant of headings that will intercept the desired course. Perhaps this is best illustrated through a few examples.

Let’s say we are flying a VOR approach, and the final approach course is 210. And let’s also assume that the VOR station is on the field. You want to intercept the 210 radial and fly inbound towards the station. When we select 210 on the OBS, the needle deflects as shown. Which heading should we fly? Pause for a moment and think about how we normally do this. Most pilots would turn the OBS until the needle centers, get their current radial position, form a mental image of their relative position to the station, and then determine which heading to fly. This works fine, but it is a lengthy process and takes too much mental effort. The alternative method is a lot simpler, and requires less handwork and brainwork. Look at all the numbers along the needle-side (left-side) of the VOR face. The needle is pointing to a hemisphere of headings between 030 and 210. Turn to any one of those headings, and the needle will eventually center. Yes, it is really that simple! The fastest way to get there of course is to fly 120, which is directly against the needle. This will make a 90-degree intercept to the desired course. All other headings will intercept the course at a shallower angle. Now look at the triangle pointer. It points to a hemisphere of headings between 300 and 120. This is where the station lies. In order to fly towards the station and intercept the selected course, we need to pick a heading from the bottom left quadrant of the VOR. For example, 080 would be a good heading to fly. Once the needle centers, its hemisphere collapses to just two numbers – 030 and 210. Of these two numbers, only 030 lies in the direction of the station. This is the heading we need to fly to track the course towards the station.

Let’s look at a second example: We want to intercept the selected course and track outbound from the station. This time we have to look at the needle and the tail of the arrow. They point to a quadrant of headings between 280 and 010. Pick one and fly it. Whether we turn left or right is immaterial. What matters is that we turn to the desired heading. When the needle centers, fly 280 to track outbound.

Notice that it doesn’t matter which number we put at the top of the OBS. We could put the desired course, or its reciprocal, and the indications will not change. There is no reverse sensing.

Here is another scenario. We are cruising along an airway. VOR1 is set to the airway radial, and VOR2 is set to an intersecting radial from another VOR. We want to know whether we have passed that intersection or still headed towards it. Here is how to do this in less than 5 seconds. Take a look at the panel. Our present heading is 060. That number is on the needle-side of VOR2. Therefore, we are still flying towards the intersection. Bingo. There is no need to twist any knobs, do any math or visualize our position. Why work hard to find the answer that is already written on the instrument?

The next example highlights the most valuable use of this method. Let’s say we want to fly to an intersection of two VOR radials as shown below. We tune both NAV radios and set the OBS to the required radials. Both CDI needles hit the stop. What heading should we fly to get to the intersection? Using the conventional method, this would take several minutes of OBS-twisting and mind-bending visualizations.

Here is how to do this in less than five seconds. Look at all the numbers on the needle-side (left-half) of VOR1. Then look at all the numbers on the needle-side (right-half) of VOR2. Find a number that is common to both. How about 360? Fly that heading. No mind-bending visualizations are necessary. If VOR1 centers before the VOR2, we are left with only two choices – 330 or 150. Only one of these is still on the needle-side of VOR2. That would be 330. Fly that heading, and eventually both needles will center. Like before, it doesn’t matter whether we put the radials at the top of the OBS or at the bottom. The results will be the same.

The same technique works on a localizer. Put the localizer front course at the top of the OBS and fly it like a course instrument. Interpret the top numbers for the front course and the bottom numbers for the back course. There is no reverse sensing. Our brain will be free to attend to more important matters. The same technique works on CDI’s driven by a GPS. On the Garmin 430/530 unless you set the OBS to the selected track, it will keep popping up a reminder message.

Notice that we did not have to figure out our current position in any of these examples. We instantly knew where to point the airplane without twisting any knobs or doing any math. Once the airplane is headed in the right direction, we can leisurely attend to the task of locating our current position. This embodies the true utility of the VOR receiver. It presents the information in the order of their importance – heading first, position later.

Given the simplicity of this technique, it is somewhat mysterious why this is seldom taught during flight training. Most pilots are taught to turn towards the needle and ignore its numeric indications. This method works only when the heading indicator is aligned with the OBS. If they are different, the indications will produce meaningless commands. Additionally, turning towards the needle is more likely to promote needle chasing, especially when the pilot is under pressure. When the VOR is used a course indicator, the pilot must read the numbers and respond with an appropriate heading. It reinforces the importance of finding and holding a constant heading. Pilots trained under this system are more likely to be disciplined about their headings.

It is unfortunate that some avionics manufacturers have failed to recognize this important VOR feature. Some have dropped the station arrow and replaced it with the TO/FROM flag. Some displays have all the numbers tucked behind a plastic sleeve except the top and bottom numbers. The worst ones are the digital VOR displays. They have an LCD bar scale to simulate the needle deflection. There is no compass rose on the face of the instrument. It is interesting to note that technological improvements have actually made the VOR more difficult to use. There might be a lesson in this. Some things are better left the way they are. The VOR system might be a 50-year old technology, but it is one of the greatest inventions in aeronautical navigation. It is really too bad that we won’t have them for much longer.

Reference

The VOR” by Joe Campbell, December 1995. Unpublished article available from http://www.campbells.org/Airplanes/VOR/vor.html