- To implement an object-oriented program using C++.
- To make proper use of an industry standard 3D graphics library (OpenGL).
- To interface with a live stream of data to control a graphical object and display it in its environment.
Modelling of custom mechanical, electrical and autonomous systems can be a beneficial step to understanding a system. While CAD software provides a good design tool, modelling of live systems specifically for control and status monitoring can be more efficient under purpose built software rather than modifying existing software to meet the system’s requirements. This assignment will require you to extend the given 3D world modelling software to model the motion of two or more ground vehicles. You will then be required to read data streams or an input device in real-time, use the data to control the graphical ground vehicles and display them in their environments.
You should begin this assignment by downloading the base code ZIP file from Moodle. A number of files have been provided to allow you to view and navigate a simple 3D world so you can test your code. See Section 4 for details on downloading and setting up the given base code.
Once the downloaded code is up and running the list of controls in Table 1 will allow you control the vehicle and to move the virtual camera.
|Arrow keys||Drive vehicle forward/left/backwards/right.|
|W,A,S,D||Move camera forward/left/backward/right.|
|C||Descend camera vertically.|
|(space)||Ascend camera vertically.|
|Mouse drag||Rotate the camera’s viewing direction.|
|0 (zero)||Move the camera to the origin.|
|P||Move the camera to vehicle pursuit position.|
Additionally, you can exit the program by pressing Escape. See the use of the “KeyManager” class in the main source file for more information on how keyboard events are linked to the virtual OpenGL Camera. In short, keys that are pressed once (such as getting the virtual camera to move to the origin) are handled the normal way via GLUT (OpenGL Utility Toolkit). To handle multiple keys being held down at the same time, the additional functionality of the custom “KeyManager” class is used.
Usually when modelling a vehicle’s pose and motion from live sensor data you would acquire the data from a suite of on board sensors, a centralised database or a network socket. For this assignment, you will be reading data from a data server.
The “Shape” class provided should be used as the parent or base class for all shapes outlined in Section 5.1. For simplicity, all shapes you create will have a 3D position using (x, y, z) coordinates and a yaw angle in degrees. Yaw is the rotation in the horizontal plane, which in this case is the XZ-plane. Zero degrees of rotation means you are facing a direction parallel to the positive x-axis. The vertical axis is the y-axis and we are using a right hand coordinate system.
The “Vehicle” class should be used as the parent or base class for designing vehicles as outlined in Section 5.2. The base vehicle object uses a basic mathematical model to translate speed and steering values from input devices such as the keyboard or an Xbox controller to motion. Your initial task is to practice writing derived classes that represent different vehicle designs. See Section 5.2 for further details.
After you have defined a custom class deriving from the Vehicle class you can test it by finding the following section of code in the main() function in the file main.cpp:
// vehicle = new MyVehicle();
You should replace “MyVehicle” with the name of your custom vehicle class and uncomment the line of code. This will enable the rest of the keyboard and drawing functions to be linked with your custom vehicle class.
The following steps will get you up to compiling and running the base source code provided on Moodle. There is a separate section for each of Windows, Linux and Mac OS X. Although there are different steps for each operating system, all of the base assignment code can be found in the AssignmentGL-Base.zip file on Moodle. All supporting headers, libs and dlls can be found in the AssignmentGL-Support.zip file on Moodle.
These steps are based on Visual Studio 2010, but should also work for later Visual Studio versions. As a student of the University of New South Wales, you are eligible to download a free student-licensed version of Visual Studio Professional by visiting Microsoft Dreamspark (www.dreamspark.com) online.
- Open Visual Studio and create a new project.
- From the Templates panel on the left select Visual C++ and then Win32.
- Select Win32 Console Application.
- Enter a project Name. (For example “Assign2 “).
- Choose a Location to place the project.
- Leave the Solution Name the same as the project Name.
- Click OK.
- Click Next to go to the “Application Settings” page.
- Make sure Application Type is “Console Application”. Make sure Additional options has “Empty project” checked and “Precompiled header” and everything else unchecked. Make sure Add common header files for has every option unchecked.
- Click Finish to finish setting up the project.
- Download the Assignment ZIP (AssignmentGL-Base.zip) file and extract to somewhere easy to find.
- Back in the new project you’ve just created find the Solution Explorer. If you cannot find the Solution Explorer go to the View menu then click Solution Explorer.
- A cpp file will have been created with the same name as the project, for example Assign2.cpp. Open this file and delete the contents (we will be using our own pre-defined main function).
- In the Solution Explorer right-click “Header Files”, select “Add” and then “Existing Item”.
- Locate the folder where you extracted the Assignment ZIP files. Highlight all the hpp files and click “Add”. (You can select a group of files by holding Control and clicking on each file).
- In the Solution Explorer right-click “Source Files”, select “Add” and then “Existing Item”.
- Locate the folder where you extracted the Assignment ZIP files. Highlight all the cpp files and click “Add”.
All the given header and source files are now set up and included correctly.
- Download the AssignmentGL-Support.zip file from Moodle and extract the files to an easy to find location. In the Win32 folder there should be three folders: dlls, include and lib.
- Copy the include and lib folders to an easy to find location, for example C:\include and C:\lib.
- Open the dlls folder and copy the contents to C:\Windows\System32. Alternatively you can place the dll files in the same directory that the compiled exe file will eventually be compiled to. If you keep Visual Studio in “Debug” mode (this is the default mode), the exe will eventually be compiled to a “Debug” folder in your project files.
- Back in the Visual Studio project open project properties (either via Alt+F7 or via the “Project” menu then “Assign2 Properties”).
- Navigate to the Configuration Properties, C/C++, General section.
- Set “Additional Include Directories” to the location where you placed the GL files include directory, for example C:\include.
- Navigate to the Configuration Properties, Linker, General section.
- Set “Additional Library Directories” to the location where you placed the GL files lib directory, for example C:\lib.
- Navigate to the Configuration Properties, Linker, Input section.
- On “Additional Dependencies” click the down arrow and the “Edit”.
- Add to the textbox, one per line: opengl32.lib, glu32.lib, and glut32.lib
- Click OK.
- Click OK.
Everything should be properly set up and ready to compile and run. Press F5. This should compile and then run the program. If a window appears then it worked. Try and move around the basic 3D world using the controls outlined earlier in Table 1 of this document.
If it didn’t work look at the Output window, usually at the bottom of Visual Studio. If the Output window is not visible you can select it from the “View” menu. If you can self diagnose the problem that is great, but you are also encouraged to post a topic on the Assignment Two Discussion Board in Moodle.
These steps are based on using the g++ compiler.
Linux and Mac OS X are relatively the same, except on most Linux distros the compiler and libraries are installed by default. In Linux, if you try to run the command g++ and the shell complains that it cannot find the command, you should install the compiler by running the following command:
Ubuntu/Debian: apt-get install build-essential RedHat: rpm install build-essential
On Mac OS X you will need to install Xcode. Xcode is available via the App Store for free, but a link can also be found on http://developer.apple.com if you have a free Apple developer licence. Xcode is something like 3 or 4 GB, so be warned.
Create a new directory called, for example, assign2.
Download the AssignmentGL-Base.zip file and extract the hpp and cpp files to the newly created directory.
On Mac OS X, downloading Xcode will automatically set up OpenGL, GLU and GLUT in the correct place. On Linux you should be able to apt-get install (Debian/Ubuntu) or rpm install (RedHat) the correct packages. If on Linux and you can’t install the headers and libs using a packing service, use the following backup steps:
Download the AssignmentGL-Support.zip file from Moodle and extract the files to an easy to find temporary location. In the Linux folder there should be two folders: include and lib.
Copy the include folder to a location that’s easy to find (for example: /include).
Copy the lib folder to a location that’s easy to find (for example: /lib).
Please ask for assistance in the Assignment Two Discussion Board on Moodle if you run into problems.
It is recommended to put the following text in a Makefile file in the assignment code directory.
LIBS = -lGL -lGLU -lGLUT
SRC = <list all your cpp files>
LIBDIR = -L/lib
INCDIR = -I/include
<tab> g++ -o run $(SRC) $(LIBS) $(LIBDIR) $(INCDIR) -g
On Mac OS X you may not need to specify the LIBDIR or INCDIR for OpenGL support files as Xcode might have set them up properly for you. Also, Mac OS X users might find it easier developing directly in Xcode instead of using g++ directly. There are plenty of tutorials online for setting up an OpenGL/GLUT project with Xcode, but if you need further assistance, please ask in the Assignment Two Discussion Board on Moodle.
By creating a Makefile you can simply type make at the command line in the assignment directory and it will compile and link your code to from an executable. Remember, when you add more cpp files make sure you make the necessary changes to the Makefile as well.
You can then run the program by typing:
Your first task is to extend the Shape class to implement a set of basic 3D shapes. When we say extend we mean the object oriented programming term - class derivation - rather than adding a large chunk of code to the Shape class itself. The Shape class contains position and orientation attributes, which are common to every 3D object. You need to implement classes at least for the following shapes outlined in this document. For simplicity, each object can be assigned one colour using three floats to specify the red, green and blue components of the colour. Look at the “Shape.hpp” file for more details on how to interface with and extend the Shape object.
This shape should make use of three additional member attributes concerning the length of the shape in the three spatial dimensions (for example, x length, y length and z length). You should also devise how the volume of the prism is positioned relative to it’s internal x, y and z attributes and how the rotation variable rotates the object in the horizontal plane. One suggestion could be to define the (x, y, z) location as the center of the object and the object’s rotation is applied about the origin of the object.
This shape should make use of additional member attributes to specify the dimensions of the triangular prism, the choice of which is left up to you. The length of the prism is an obvious choice for one of these attributes, but you should determine a method for specifying the shape of the triangular dimensions of the object. For example, two different approaches, among others, are to store:
the three side lengths of the triangle, or
two side lengths and an angle.
You should also remember to intelligently decide on a center for your object and how this relates to object rotation.
You should decide on additional member attributes to specify the shape of this object. In particular you need to decide on a way of specifying the dimensions of the trapezium at the end of the prism in an efficient way.
You can use additional member attributes such as length or height along with radius to specify the dimensions of a cylinder. You may make use of the inbuilt “gluCylinder” or “glutCylinder” functions. A cylinder for this project must be a solid cylinder. That is, it should consist of a curved surface together with two circles on each end of the cylinder. The center of a cylinder might be defined as the point half way along the central axis of the cylinder for rotation purposes.
Using the collection of basic 3D shapes we have defined in the previous section, you should implement some models of different types of vehicles. When implementing a model of a vehicle you should extend from the base “Vehicle” class provided with the initial collection of files. When constructing the model from basic shapes you should position shapes in the vehicle’s local frame of reference. As a result, the “draw” function in your custom vehicle class should contain the following general structure:
// move to the vehicle's local frame of reference
// all the local drawing code
// move back to global frame of reference
The base “Vehicle” class contains an “update” function which handles interpreting control input into vehicle motion using a basic mathematical model. Although it is not required, you may modify or improve this mathematical model in the “Vehicle” class. The “update” function, combined with the drawing structure above will position and orient the vehicle’s model correctly in 3D space. You need to make sure you position shapes so that the vehicle is facing the positive x-axis in it’s local frame of reference. For best results make your vehicles not longer than 4 units and not wider than 3 units.
However, if your vehicle has wheels (which it probably will), you must make the wheels rotate at a rate that approximately resembles the vehicle’s speed. Additionally, if your vehicle has wheels that can steer when steering then you also should make the models wheel’s steer proportional to the steering angle. When your work is being assessed, we will give you a model of vehicle (hereafter called the local vehicle) that contain both wheels that rotate and wheels that steer. In addition you will also receive one or more vehicle models (here after called remote vehicles) from a data server. You need to display all these vehicles on the screen. See Section 8 for more details.
As good preparation, you could implement some prefabricated vehicle parts to make constructing vehicle models quicker. For example, a “Wheel” class could be created that contains a cylinder wheel with either cylindrical or prism based spokes for the wheels to tell they are turning when the vehicle is in motion. The more prepared you are beforehand, the easier the assessment process will be.
- Create a RectangularPrism class extended from Shape class.
- Create a TriangularPrism class extended from Shape class.
- Create a TrapezodialPrism class extended from Shape class.
- Create a Cylinder class extended from Shape class.
Get your first progress check done by any demonstrator before 5.00 pm of Friday week 7 showing above four items in the form of source code or on screen functionality.
- Instantiate local/remote vehicles extended from Vehicle class.
- Vehicles should have wheels that roll when driving forward/backward.
- Vehicles should have front wheels that steer when steering.
Get your second progress check done by any demonstrator before 5.00 pm Friday of week 8 showing above three items in the form of on screen functionality.
This part deals with dynamically adding vehicles into your program using a server, and making these remote vehicles move. (See Section 7 to see how to make the local vehicle move). In order to do this you will need to interface with a data source over an Ethernet/Wi-fi connection. We have provided a class (called RemoteDataManager) and a set of functions (declared in Messages.hpp) that hides away most of the low-level implementation detail for you. The RemoteDataManager class will connect over the internet to the UNSW robotics server www.robotics.unsw.edu.au. Communication with the server is bidirectional, and is used to synchronise your environment with the server’s. To enable communication with the data server, uncomment the relevant line of code in the idle() function in the main.cpp file near this line.
Most of the messages received from the data server will be handled by the provided code, with the exception of the “M”-vehicle model message. The “M” message contains one or more VehicleModel objects represented according to the data structures given in Table 2, where each VehicleModel has a vector of shapes. You will need to process each model object to instantiate the remote vehicles correctly, and in each model object, you will need to process the shape information. The relevant section of code can be found in the main() function in the file main.cpp near this line:
//otherVehicles[vm.remoteID] = new MyVehicle();
You should replace “MyVehicle” with the name of your custom vehicle class and uncomment the line of code. This will enable remote vehicles to be added to the map of other vehicles to be drawn and updated.
As can be seen, the information here is not any different to the information you used to draw the local vehicle. Hence, you can use the parts of software you used to draw the local vehicle to draw these remote vehicles in an identical manner provided you match up the data received from the data server to your own vehicle data representation. As soon as you have drawn your remote vehicles, they will begin to move according to the state data streaming from the data server. The part that moves the remote vehicles has already been completed for you and you therefore do not have to do this part. However, on connection you will need to tell the remote server what your vehicle looks like. The functionality to package and send the data has been provided by the RemoteDataManager networking software. You need to provide the code to fill in the outgoing data structure, given in Table 2. If the data you provide is beyond nominal range, the server may respond with an error message and terminate your connection.
float xlen; // length along x-axis
float ylen; // length along y-axis
float zlen; // length along z-axis
float alen; // length of side A (bottom)
float blen; // length of side B (left)
float angle; // angle (degrees) between side A and B
float depth; // length along z-axis
float alen; // length of side A (bottom)
float blen; // length of side B (top)
float height; // distance between side A and B
float aoff; // distance A is shifted from B by, from the left
float depth; // length along z-axis
float depth; // length along z-axis
bool isRolling; // needs to roll with vehicle?
bool isSteering;// needs to steer with vehicle?
int remoteID; // this should be 0 for local vehicles
Implement code in your graphical application to receive data server message “M” and display one or more vehicles accordingly with the correct shapes.
Implement code in your graphical application to report your local vehicle status to the server.
This part requires preparation before you come to the assessment. Learn to draw additional graphical objects around your graphical vehicle. This could be to draw in 3-D a line loop forming an arrow pointing at your vehicle from its front, rear, left or right and moving with the vehicle as you move the vehicle using a game controller or the keyboard. It could also be a circle drawn in 3D space around your vehicle and the circle should move with the vehicle. Other examples are drawing an arrow of a shape specified by your assessor to indicate the direction of travel as determined by steering. Above mentioned examples do not form the full list of potential tasks you may get on the day of the assessment. However, it is prudent to prepare for rendering graphical objects that could move with the vehicle, its wheels or its steering.
Vehicle speeds will range from 0 to 10 ms and steering angles will range between 15 and +15 degrees.
Practice coding to incorporate additional graphical objects in 3D (which are not part of the vehicle body) that move with the vehicle.
Additional graphical objects drawn around your vehicle must appear when the key ‘Z’ is pressed.
You are required to prepare a set of 3D objects and practice constructing vehicles from the objects in your own time.
Complete first progress check by Friday 5 pm of week 7. First progress check does not earn you any marks. However, if late, you will lose one mark per calendar day. Unavailability of demonstrators closer to the deadline is not considered as an excuse. Please make sure you sign the demonstrator’s name sheet after a successful progress check.
Complete second progress check by Friday 5 pm of week 8. You must have completed the first progress check to be able to complete the second progress check. Second progress check does not earn you any marks. However, if late, you will lose one mark per calendar day. Unavailability of demonstrators closer to the deadline is not considered as an excuse. Please make sure you sign the demonstrator’s name sheet after a successful progress check.
You must make an appointment with the demonstrator assigned to you by Friday 5 pm of Week 8. If you miss this deadline, the penalty is one mark per calendar day. DO THIS WELL AHEAD OF TIME.
You must get your work marked by a demonstrator during Week 10. You must have completed the second progress check to be able to get your work assessed. The penalty for late assessment is as per the School policy.
During assessment you will be required to bring in all of your source code.
At the time of assessment your assessor will give you the specifications for the local vehicle which you will then need to model using your developed classes. You will be given 20 minutes to prepare this model, complete any other assigned tasks and test them in your program. You will have incorporated all other functionality required before arriving at the assessment. As such when you connect to the data server, we should see the remote vehicles on the screen and they should begin to move automatically.
After such time your demonstrator will check the model you created to see if it appears to be correct to specification and any moving parts properly animate under vehicle motion.
Your demonstrator will also check the reporting of your local vehicle status to the data server.
You will then be asked to demonstrate your program by driving your graphical around on the screen.
Your demonstrator will then ask you to explain your code and class structure. Marks will be awarded out of 20 according to the following scheme:
- (a) Making the program compile and be fully operational on the day of assessment.
- (b) Whether the model looks and animates correctly.
- (c) The vehicle motion is demonstrated using an XBox 360 game controller.
- (d) Whether the live feed of data from the data server is correctly read and used.
- (e) Whether the local vehicle’s status is correctly reported to the data server.
- (f) Modularity: is the program broken up into well defined files, classes, functions?
- (g) Structure: Is the code efficient and logical?.
- (h) Did you clearly explain the program to your demonstrator by clearly answering the five questions he or she will ask you?
- (i) If you are up for a challenge, demonstrate to your demonstrator how you could give chase to vehicle with vehicle ID 1, when you press ‘L’. You will get an additional 10% of your mark, however, the total bonus marks for all assignments may not exceed 3.
Below is a sample specification for a simple vehicle.
- The x-axis, y-axis and z-axis are shown by the red, green and blue vectors respectively.
- The small front wheels should be turned to reflect the vehicle’s steering angle.
- All four wheels should rotate relative to vehicle speed.
- The main body should be coloured with the RGB values (0.0, 0.6, 0.0).
- The front (small) wheels should be coloured with the RGB values (1.0, 0.0, 0.0).
- The back wheels should be coloured with the RGB values (0.0, 0.0, 1.0).