Difference between revisions of "Vessel Tutorial 1"
Line 1: | Line 1: | ||
− | == Vessel Tutorial == | + | == Vessel Tutorial (Work in progress) == |
This article intends to guide you through the construction of a new Vessel DLL, by using the sample code from the OrbiterSDK. | This article intends to guide you through the construction of a new Vessel DLL, by using the sample code from the OrbiterSDK. | ||
Line 5: | Line 5: | ||
This documents my adventure transforming the stock ShuttlePB into a reasonably accurate model of the Surveyor lunar lander. There was a model on OrbitHangar, but it had wildly inaccurate mechanics, due partly to the fact that it was based on Vinka's Spacecraft.dll. | This documents my adventure transforming the stock ShuttlePB into a reasonably accurate model of the Surveyor lunar lander. There was a model on OrbitHangar, but it had wildly inaccurate mechanics, due partly to the fact that it was based on Vinka's Spacecraft.dll. | ||
− | This tutorial assumes you have a working compiler which you know creates valid working DLLs from the OrbiterSDK sample code. I happen to use the free Microsoft command-line compiler, together with an editor called TextPad. Setting up the free compiler and the editor is beyond the scope of this document. | + | This tutorial assumes you have a working compiler which you know creates valid working DLLs from the OrbiterSDK sample code. I happen to use the free Microsoft command-line compiler, together with an editor called TextPad. Setting up the free compiler and the editor is beyond the scope of this document. Check the rest of this Wiki, or the Orbiter forums. |
=== My goal spacecraft: Surveyor === | === My goal spacecraft: Surveyor === | ||
Line 11: | Line 11: | ||
Surveyor was a series of unmanned lunar landers launched by NASA in 1965-1967, before the first Apollo. It is a particularly simple, yet interesting and highly successful design. | Surveyor was a series of unmanned lunar landers launched by NASA in 1965-1967, before the first Apollo. It is a particularly simple, yet interesting and highly successful design. | ||
− | Functionally, Surveyor consists of a large solid-fueled main retro-rocket, three medium-sized throttleable liquid fueled vernier engines, and six cold-gas attitude control thrusters. | + | Functionally, Surveyor consists of a large solid-fueled main retro-rocket, three medium-sized throttleable liquid fueled vernier engines, and six cold-gas Reaction Control System (RCS) attitude control thrusters. |
− | Surveyor is launched on top of an Atlas-Centaur rocket, on a direct impact trajectory to the moon. Impact will occur after 66 hours. | + | Surveyor is launched on top of an Atlas-Centaur rocket, on a direct impact trajectory to the moon. Impact will occur after about 66 hours. About 16 hours after launch, it performs a single mid-course correction maneuver, which aims it to precisely impact at the desired landing point. |
Thirty minutes before impact, Surveyor maneuvers into a retrograde attitude. From here, its '''Altitude Marking Radar''' (AMR) will eventually be able to see the surface and measure the distance. The AMR locks on to the surface at about 200km, one minute before impact. Once the altitude reaches a pre-determined value called the '''Altitude Mark''', it starts a short timer. | Thirty minutes before impact, Surveyor maneuvers into a retrograde attitude. From here, its '''Altitude Marking Radar''' (AMR) will eventually be able to see the surface and measure the distance. The AMR locks on to the surface at about 200km, one minute before impact. Once the altitude reaches a pre-determined value called the '''Altitude Mark''', it starts a short timer. | ||
− | At the altitude mark, the spacecraft is hurtling towards the ground at over 2.5km/s and will impact within a minute. For Surveyor 1, the altitude mark was about 110km, and the timer was about 7 seconds. Once the timer expires, the vernier engines light up, then the main retro ignites for its 40 second burn. The main retro gets rid of 2.3km/s of speed, and leaves the spacecraft between 5km and 20km above the surface and travelling downwards at between zero and 230m/s. During this stage, the vernier engines are used to stabilize the spacecraft and compensate for any thrust misalignment in the main retro. | + | At the altitude mark, the spacecraft is hurtling towards the ground at over 2.5km/s and will impact within a minute. For Surveyor 1, the altitude mark was about 110km, and the timer was about 7 seconds. Once the timer expires, the vernier engines light up, then the main retro ignites for its 40 second burn. The main retro gets rid of 2.3km/s of speed, and leaves the spacecraft between 5km and 20km above the surface and travelling downwards at between zero and 230m/s. During this stage, the vernier engines are used to stabilize the spacecraft and compensate for any thrust misalignment in the main retro. The AMR is automatically jettisoned at main retro ignition, as it is no longer needed. In fact, it is stuffed into the nozzle of the main retro, and is blasted out by the retro ignition. |
The spacecraft then drops the spent retro motor and continues down on the vernier engines. Using a seperate four-beam Doppler radar and a simple analog computer, it throttles the engines such that it will reach a downward velocity of about 1.3m/s about 4m above the surface. It then cuts its engines and falls the rest of the way. | The spacecraft then drops the spent retro motor and continues down on the vernier engines. Using a seperate four-beam Doppler radar and a simple analog computer, it throttles the engines such that it will reach a downward velocity of about 1.3m/s about 4m above the surface. It then cuts its engines and falls the rest of the way. | ||
Line 32: | Line 32: | ||
# Start with something you know works | # Start with something you know works | ||
− | # Only make | + | # Only make one change at a time |
# '''''ALWAYS''''' '''''ALWAYS''''' '''''ALWAYS''''' test each change, no matter how small | # '''''ALWAYS''''' '''''ALWAYS''''' '''''ALWAYS''''' test each change, no matter how small | ||
# For historical or real vessels, get good reference material | # For historical or real vessels, get good reference material | ||
Line 44: | Line 44: | ||
Now, edit Surveyor.cpp. Do a global search-and-replace to change all references from ShuttlePB to Surveyor. Go ahead and modify the copyright message at the top, to say that this is a work derived from the original ShuttlePB. By the time we are done, almost all the old ShuttlePB code will be replaced. | Now, edit Surveyor.cpp. Do a global search-and-replace to change all references from ShuttlePB to Surveyor. Go ahead and modify the copyright message at the top, to say that this is a work derived from the original ShuttlePB. By the time we are done, almost all the old ShuttlePB code will be replaced. | ||
− | In keeping with Rule 3, compile this file, copy the resulting DLL to the Orbiter\Modules, and | + | In keeping with Rule 3, compile this file, copy the resulting DLL to the Orbiter\Modules, and use the following scenario. It should run perfectly, and look and fly exactly like the old ShuttlePB. If at any point in this tutorial, if it doesn't work |
+ | |||
+ | <pre><nowiki> | ||
+ | BEGIN_ENVIRONMENT | ||
+ | System Sol | ||
+ | Date MJD 51982.6685767396 | ||
+ | END_ENVIRONMENT | ||
+ | |||
+ | BEGIN_FOCUS | ||
+ | Ship Surveyor1 | ||
+ | END_FOCUS | ||
+ | |||
+ | BEGIN_CAMERA | ||
+ | TARGET Surveyor1 | ||
+ | FOV 50.00 | ||
+ | END_CAMERA | ||
+ | |||
+ | BEGIN_SHIPS | ||
+ | Surveyor1:Surveyor | ||
+ | STATUS Landed Moon | ||
+ | BASE Brighton Beach:1 | ||
+ | HEADING 90.00 | ||
+ | PRPLEVEL 0:1.000 | ||
+ | END | ||
+ | END_SHIPS | ||
+ | </nowiki></pre> | ||
=== Meshes === | === Meshes === | ||
Line 52: | Line 77: | ||
If you are following along, get that add-on, and get the meshes out of it. Rename Surveyor-deployed.msh as Surveyor-Lander.msh . Copy this mesh to Orbiter\Meshes , and copy all the .dds files to Orbiter\Textures . | If you are following along, get that add-on, and get the meshes out of it. Rename Surveyor-deployed.msh as Surveyor-Lander.msh . Copy this mesh to Orbiter\Meshes , and copy all the .dds files to Orbiter\Textures . | ||
− | Now, to use this mesh. In Surveyor.cpp, look for the method Surveyor::clbkSetClassCaps . Near the end, change the line | + | Now, to use this mesh. In Surveyor.cpp, look for the method Surveyor::clbkSetClassCaps . Near the end, change the line (Note that it doesn't say ShuttlePB, remember that you searched-and-replaced that out.) |
+ | |||
+ | <pre><nowiki> | ||
+ | // visual specs | ||
+ | AddMesh ("Surveyor"); | ||
+ | </nowiki></pre> | ||
+ | |||
+ | to | ||
+ | |||
+ | <pre><nowiki> | ||
+ | // visual specs | ||
+ | AddMesh("Surveyor-Lander"); | ||
+ | </nowiki></pre> | ||
+ | |||
+ | Compile and test it. Notice that the spacecraft now looks like Surveyor, but it flies like ShuttlePB. Also note that the legs are not on the surface. Go ahead and take Surveyor for a spin, and put it in orbit around the moon. It will be much easier to test the verner and RCS engines in space. | ||
+ | |||
+ | === Vehicle coordinate system === | ||
+ | |||
+ | As described in the Orbiter API guide, vessels use a left-handed coordinate system. Even though Surveyor looks nothing like and is flown nothing like an airplane, an airplane is still a useful model to describe the coordinate system. Imagine yourself sitting in the pilot's seat of an airplane. The X axis is the "left-to-right" axis. +X points out to the right wing, and -X points out to the left wing. The Y axis is the "up-to-down" axis. +Y points up, in the direction of the vertical tail fin, and -Y points down in the direction of the wheels. The Z axis is the "front-to-back" axis. +Z points to the nose, and -Z points back to the aft end of the plane. In an conventional airplane, the engines thrust towards +Z. | ||
+ | |||
+ | === Vernier Engines === | ||
+ | |||
+ | These will be the "main" engines controllable with the NumPad+ key. Even though these vernier engines are the very reason we are using a custom DLL rather than spacecraft.dll, we are not going to do anything fancy to them yet. | ||
+ | |||
+ | The three vernier engines are arranged symetrically in a triangle around the Z axis. Engine 1 is near leg 1, on the +Y axis. Engines 2 and 3 are out on legs 2 and 3. They are each mounted 0.86 meters from the Z axis, 0.5m behind the origin. | ||
+ | |||
+ | First, search-and-replace variable name th_main to th_vernier. | ||
+ | |||
+ | Find this code in Surveyor::clbkSetClassCaps . | ||
+ | |||
+ | <pre><nowiki> | ||
+ | void Surveyor::clbkSetClassCaps (FILEHANDLE cfg) | ||
+ | { | ||
+ | THRUSTER_HANDLE th_main, th_hover, th_rcs[14], th_group[4]; | ||
+ | </nowiki></pre> | ||
+ | |||
+ | Change it to | ||
+ | <pre><nowiki> | ||
+ | void Surveyor::clbkSetClassCaps (FILEHANDLE cfg) | ||
+ | { | ||
+ | THRUSTER_HANDLE th_main[3], th_hover, th_rcs[14], th_group[4]; | ||
+ | </nowiki></pre> | ||
+ | |||
+ | since there are 3 vernier engines, and we need to keep track of them all. | ||
+ | |||
+ | It is best to put as many vessel parameters into constants as possible, to keep them all in one place and easy to adjust. The parameters for the verniers are Maximum thrust, Isp (Fuel efficiency), and engine location. So, add the following constants near the top of the file. | ||
+ | |||
+ | <pre><nowiki> | ||
+ | const double VERNIER_PROP_MASS = 70.98; | ||
+ | const double VERNIER_ISP = 3200; | ||
+ | const double VERNIER_THRUST = 463; | ||
+ | const double VERNIER_RAD = 0.86; | ||
+ | const double VERNIER_STA = -0.5; | ||
+ | </nowiki></pre> | ||
+ | |||
+ | Find the line in Surveyor::clbkSetClassCaps which reads as follows: | ||
+ | |||
+ | <pre><nowiki> | ||
+ | th_vernier = CreateThruster (_V(0,0,-4.35), _V(0,0,1), PB_MAXMAINTH, ph_vernier, PB_ISP); | ||
+ | CreateThrusterGroup (&th_vernier, 1, THGROUP_MAIN); | ||
+ | AddExhaust (th_vernier, 8, 1, _V(0,0.3,-4.35), _V(0,0,-1)); | ||
+ | </nowiki></pre> | ||
+ | |||
+ | Change them to: | ||
+ | |||
+ | <pre><nowiki> | ||
+ | th_vernier[0] = CreateThruster(_V( 0.0*VERNIER_RAD, 1.0*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP); | ||
+ | th_vernier[1] = CreateThruster(_V( sqrt(3.0)/2*VERNIER_RAD,-0.5*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP); | ||
+ | th_vernier[2] = CreateThruster(_V(-sqrt(3.0)/2*VERNIER_RAD,-0.5*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP); | ||
+ | CreateThrusterGroup(th_vernier, 3, THGROUP_MAIN); | ||
+ | for(int i=0;i<3;i++) { | ||
+ | AddExhaust(th_vernier[i], 1, 0.1); | ||
+ | } | ||
+ | </nowiki></pre> | ||
+ | |||
+ | This creates the three vernier engines, arranges them in an equilateral triangle, groups them into the "main" thruster group, and adds an exhaust display. CreateThruster takes five parameters: | ||
+ | |||
+ | # The center of thrust in body coordinates | ||
+ | # A unit vector in the direction of thrust, in body coordinates (Note that the exhaust travels in the opposite direction) | ||
+ | # The maximum thrust of the engine, in Newtons | ||
+ | # The propellant resource (Fuel tank) this engine draws from | ||
+ | # The Isp (Fuel efficiency) of the thruster, in N*s/kg. In other words, how many Newtons does burning 1kg/s of propellant generate? |
Revision as of 04:15, 21 September 2005
Vessel Tutorial (Work in progress)
This article intends to guide you through the construction of a new Vessel DLL, by using the sample code from the OrbiterSDK.
This documents my adventure transforming the stock ShuttlePB into a reasonably accurate model of the Surveyor lunar lander. There was a model on OrbitHangar, but it had wildly inaccurate mechanics, due partly to the fact that it was based on Vinka's Spacecraft.dll.
This tutorial assumes you have a working compiler which you know creates valid working DLLs from the OrbiterSDK sample code. I happen to use the free Microsoft command-line compiler, together with an editor called TextPad. Setting up the free compiler and the editor is beyond the scope of this document. Check the rest of this Wiki, or the Orbiter forums.
My goal spacecraft: Surveyor
Surveyor was a series of unmanned lunar landers launched by NASA in 1965-1967, before the first Apollo. It is a particularly simple, yet interesting and highly successful design.
Functionally, Surveyor consists of a large solid-fueled main retro-rocket, three medium-sized throttleable liquid fueled vernier engines, and six cold-gas Reaction Control System (RCS) attitude control thrusters.
Surveyor is launched on top of an Atlas-Centaur rocket, on a direct impact trajectory to the moon. Impact will occur after about 66 hours. About 16 hours after launch, it performs a single mid-course correction maneuver, which aims it to precisely impact at the desired landing point.
Thirty minutes before impact, Surveyor maneuvers into a retrograde attitude. From here, its Altitude Marking Radar (AMR) will eventually be able to see the surface and measure the distance. The AMR locks on to the surface at about 200km, one minute before impact. Once the altitude reaches a pre-determined value called the Altitude Mark, it starts a short timer.
At the altitude mark, the spacecraft is hurtling towards the ground at over 2.5km/s and will impact within a minute. For Surveyor 1, the altitude mark was about 110km, and the timer was about 7 seconds. Once the timer expires, the vernier engines light up, then the main retro ignites for its 40 second burn. The main retro gets rid of 2.3km/s of speed, and leaves the spacecraft between 5km and 20km above the surface and travelling downwards at between zero and 230m/s. During this stage, the vernier engines are used to stabilize the spacecraft and compensate for any thrust misalignment in the main retro. The AMR is automatically jettisoned at main retro ignition, as it is no longer needed. In fact, it is stuffed into the nozzle of the main retro, and is blasted out by the retro ignition.
The spacecraft then drops the spent retro motor and continues down on the vernier engines. Using a seperate four-beam Doppler radar and a simple analog computer, it throttles the engines such that it will reach a downward velocity of about 1.3m/s about 4m above the surface. It then cuts its engines and falls the rest of the way.
Why a custom DLL
Many spacecraft can and in fact have been simulated with Vinka's spacecraft.dll. This method uses a text file to describe a spacecraft, and a general purpose DLL to interpret it.
The reason that this spacecraft must be written from scratch, and not use something like spacecraft.dll, is that when the vernier engines are on, they are used to control attitude as well as provide thrust. Two of the three engines use differential thrust to control pitch and yaw, and the third is mounted on a pivot to control roll. This effect cannot be done with spacecraft.dll, and therefore demands a custom DLL. Besides, I felt like writing a DLL, just to learn how to do it.
I hope that this article is useful to anyone trying to write a custom vessel DLL. I find it much easier to understand a concept when 1) I need to use it and 2) There is a well-documented example of using the concept. You have to provide the need. I provide the example.
The Rules
- Start with something you know works
- Only make one change at a time
- ALWAYS ALWAYS ALWAYS test each change, no matter how small
- For historical or real vessels, get good reference material
The Starting Point
So, how do you start with something that works, if you are creating a brand new vessel? Good question. The answer is to look through the samples in Orbiter\OrbiterSDK\Samples for the ship which is closest to the one you have in mind.
Sometimes nothing is particularly close. It was in my case. In this case, just start with the simplest possible ship, the ShuttlePB. Make a copy of this folder, then rename it to your new vessel name. If you are using Visual C++, you probably need to do some weird stuff to rename the project and all the files in it. I use the free compiler, so the project files are no good to me. If you use it also, feel free to just delete all the files except for ShuttlePB.cpp, and rename it to a new name, like Surveyor.cpp.
Now, edit Surveyor.cpp. Do a global search-and-replace to change all references from ShuttlePB to Surveyor. Go ahead and modify the copyright message at the top, to say that this is a work derived from the original ShuttlePB. By the time we are done, almost all the old ShuttlePB code will be replaced.
In keeping with Rule 3, compile this file, copy the resulting DLL to the Orbiter\Modules, and use the following scenario. It should run perfectly, and look and fly exactly like the old ShuttlePB. If at any point in this tutorial, if it doesn't work
BEGIN_ENVIRONMENT System Sol Date MJD 51982.6685767396 END_ENVIRONMENT BEGIN_FOCUS Ship Surveyor1 END_FOCUS BEGIN_CAMERA TARGET Surveyor1 FOV 50.00 END_CAMERA BEGIN_SHIPS Surveyor1:Surveyor STATUS Landed Moon BASE Brighton Beach:1 HEADING 90.00 PRPLEVEL 0:1.000 END END_SHIPS
Meshes
Creating meshes is beyond the scope of this document. Since I am in a hurry and not primarily interested in artwork, I borrowed the mesh from Surveyor1-1.zip by Jim Williams, posted on OrbitHangar.
If you are following along, get that add-on, and get the meshes out of it. Rename Surveyor-deployed.msh as Surveyor-Lander.msh . Copy this mesh to Orbiter\Meshes , and copy all the .dds files to Orbiter\Textures .
Now, to use this mesh. In Surveyor.cpp, look for the method Surveyor::clbkSetClassCaps . Near the end, change the line (Note that it doesn't say ShuttlePB, remember that you searched-and-replaced that out.)
// visual specs AddMesh ("Surveyor");
to
// visual specs AddMesh("Surveyor-Lander");
Compile and test it. Notice that the spacecraft now looks like Surveyor, but it flies like ShuttlePB. Also note that the legs are not on the surface. Go ahead and take Surveyor for a spin, and put it in orbit around the moon. It will be much easier to test the verner and RCS engines in space.
Vehicle coordinate system
As described in the Orbiter API guide, vessels use a left-handed coordinate system. Even though Surveyor looks nothing like and is flown nothing like an airplane, an airplane is still a useful model to describe the coordinate system. Imagine yourself sitting in the pilot's seat of an airplane. The X axis is the "left-to-right" axis. +X points out to the right wing, and -X points out to the left wing. The Y axis is the "up-to-down" axis. +Y points up, in the direction of the vertical tail fin, and -Y points down in the direction of the wheels. The Z axis is the "front-to-back" axis. +Z points to the nose, and -Z points back to the aft end of the plane. In an conventional airplane, the engines thrust towards +Z.
Vernier Engines
These will be the "main" engines controllable with the NumPad+ key. Even though these vernier engines are the very reason we are using a custom DLL rather than spacecraft.dll, we are not going to do anything fancy to them yet.
The three vernier engines are arranged symetrically in a triangle around the Z axis. Engine 1 is near leg 1, on the +Y axis. Engines 2 and 3 are out on legs 2 and 3. They are each mounted 0.86 meters from the Z axis, 0.5m behind the origin.
First, search-and-replace variable name th_main to th_vernier.
Find this code in Surveyor::clbkSetClassCaps .
void Surveyor::clbkSetClassCaps (FILEHANDLE cfg) { THRUSTER_HANDLE th_main, th_hover, th_rcs[14], th_group[4];
Change it to
void Surveyor::clbkSetClassCaps (FILEHANDLE cfg) { THRUSTER_HANDLE th_main[3], th_hover, th_rcs[14], th_group[4];
since there are 3 vernier engines, and we need to keep track of them all.
It is best to put as many vessel parameters into constants as possible, to keep them all in one place and easy to adjust. The parameters for the verniers are Maximum thrust, Isp (Fuel efficiency), and engine location. So, add the following constants near the top of the file.
const double VERNIER_PROP_MASS = 70.98; const double VERNIER_ISP = 3200; const double VERNIER_THRUST = 463; const double VERNIER_RAD = 0.86; const double VERNIER_STA = -0.5;
Find the line in Surveyor::clbkSetClassCaps which reads as follows:
th_vernier = CreateThruster (_V(0,0,-4.35), _V(0,0,1), PB_MAXMAINTH, ph_vernier, PB_ISP); CreateThrusterGroup (&th_vernier, 1, THGROUP_MAIN); AddExhaust (th_vernier, 8, 1, _V(0,0.3,-4.35), _V(0,0,-1));
Change them to:
th_vernier[0] = CreateThruster(_V( 0.0*VERNIER_RAD, 1.0*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP); th_vernier[1] = CreateThruster(_V( sqrt(3.0)/2*VERNIER_RAD,-0.5*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP); th_vernier[2] = CreateThruster(_V(-sqrt(3.0)/2*VERNIER_RAD,-0.5*VERNIER_RAD,VERNIER_STA), _V(0,0,1), VERNIER_THRUST, ph_vernier, VERNIER_ISP); CreateThrusterGroup(th_vernier, 3, THGROUP_MAIN); for(int i=0;i<3;i++) { AddExhaust(th_vernier[i], 1, 0.1); }
This creates the three vernier engines, arranges them in an equilateral triangle, groups them into the "main" thruster group, and adds an exhaust display. CreateThruster takes five parameters:
- The center of thrust in body coordinates
- A unit vector in the direction of thrust, in body coordinates (Note that the exhaust travels in the opposite direction)
- The maximum thrust of the engine, in Newtons
- The propellant resource (Fuel tank) this engine draws from
- The Isp (Fuel efficiency) of the thruster, in N*s/kg. In other words, how many Newtons does burning 1kg/s of propellant generate?