Wednesday, May 7, 2008

Reflections on Project

Overview:

This was a very interesting project and I learned a lot from it. It turned into a bit of a nightmare for me in terms of the amount of time I needed to put in, but I enjoyed doing it and it was very satisfying to get it to work in the end, at least in the limited fashion that it did. The main issue was that there weren’t enough computer scientists on the team to handle the amount of serious development that was required. Courtland and Juno were both very helpful with the tasks that fell into their skill set (building things for Courtland, more basic programming for Juno), but this project required a lot of difficult programming (graphics, advanced object-oriented programming with complicated interaction between objects, etc.) that only someone whose discipline was computer science would be able to do effectively. Again, I enjoyed the project a lot, but having to put several hundred hours of work into a project is a bit too much.


Development Challenges:

The main development challenges, in order from most difficult to least difficult, are as follows:

1. Implementing the network of roadway objects and car objects with all the necessary interaction between various roadways, cars, connectors, etc. This required a lot of advanced programming time.
2. Hard-coding the graphics for the cars. This was tedious work that was also not easy to do because graphics are tricky and without taking a course in it, concepts like Affine Transformations are hard to grasp. This also required a lot of programming and caused us to scale back the number of roadway types we would support.
3. Getting the cars to drive in the right direction and on the right side of the road in all possible configurations. This required a bunch of additional testing and debugging to get right.
4. Basic mapping of physical tokens to exact digital replicas of them in the system. It wasn’t too hard to draw the tokens’ shapes, but getting them all to appear in world space with the correct position, orientation, and size took some thought.
5. Getting Mike’s custom webcam driver to work with our system. This was important for getting better results from the topcode reading, and required some time to get to run on the computer we were using and integrate into our code.
6. Dealing with lighting and glare with the webcam to get the topcodes reading consistently, even when the projector was running. This got a boost from using Mike’s webcam driver, and the projector issue was solved by placing window tinting film on the underside of the glass and directly lighting the topcodes from below.
7. Calibrating the output image of the program to the physical tokens on the table. This was tedious work – viewing the image and making small changes to the global position and zoom values to move the image closer to where it needed to be on the table. This was also dependent on the positioning of the projector and the camera.


Things that would have helped:

Really there is only one here – more computer scientists. The skill set of the group was nice and diverse, and I felt we were prepared for everything involved except pure software development. The project required too much advanced programming to have only one person with a software background.


Team Work Process:

a. The main tasks were:
-Building the table (not sure, Courtland knows)
-Building the start tokens (not sure, Courtland knows)
-Putting the labels and topcodes on the roadway tokens (10 hours)
-Coding the topcode reading (5 hours)
-Coding the graphics (150 hours)
-Coding the system’s interaction and the cars (150 hours)
b. Work was divided based on what people were capable of doing. We divided everything as evenly as possible, but there were certain tasks that some of us knew how to do and others didn’t, and that pretty much dictated who did what.
c. The creation of tokens with fixed positioned topcodes was done first, because it was necessary to have a permanent topcode position and orientation to work with on each token. Then we coded the topcode reading and basic graphics followed by integrating those two parts together. After that we started developing the system-wide interaction and the cars. The building of the table and the start tokens was done towards the end.
d. The integration wasn’t really an issue. The only two times we needed to integrate separate components were integrating the topcode reading with the basic graphics, in which case the two components were designed to work well together, and integrating the final software component with the table and physical objects, which wasn’t too difficult outside of some last-minute calibration.
e. Testing was done within each task to confirm that that component worked as it should before integration. Once everything was put together, more testing was done to work out issues such as cars driving in the wrong direction and on the wrong side of the road. Testing of the camera to deal with lighting and glare was also done.
f. We had to scale back the project quite a bit. In order to save time, we didn’t implement functionality for 3 types of tokens that we had originally planned to support. We also didn’t get the cars to work to the point we had hoped to. We got single cars to move through any system that the user created, but we didn’t get to making the cars aware of each other and having their speeds be affected by the tokens they are traveling through so that traffic can jam up in the system. The useful traffic modeling was too much to implement in the time frame we were working with.
g. Our team dynamics were quite good. Even though Juno and Courtland didn’t have the programming experience to help with much of the development, they contributed where they could and tried to help me as much as possible. I understood that it wasn’t their fault that they didn’t have a programming background. So even though there were difficulties with breaking up the work, I thought the team dynamics were good.

Summary of Development Process

Here is a summary of the development process for the Traffic Sim project:

I started by learning the basic drawing capabilities of Java2D, like how to draw a rectangle with certain dimensions in a certain location, etc. Once I got that stuff down, I created exact to-scale replicas of each road piece using these basic shapes, with their centers at 0,0. Eventually I was able to draw each piece to scale.

Once the basic graphics was implemented, I needed a way to put it all together. Therefore, I made java classes for each type of road, each with a draw function that would do the graphics stuff I had previously developed for that piece. Each class also had a way to internally store that piece's position, orientation, and size.

I also created a thing called an interface that acts like a generic roadway which each of the other classes implement. This allowed me to have the global system accept any type of roadway without having to specify a specific class.

After all of the pieces had classes, I needed a global picture that could draw many pieces in their correct position, orientation, and size. For this, I used things called Affine Transformations, one of which each piece's class contained. To draw a piece, I would first remember the original transformation of the global picture, then transform into the space of the piece I wanted to draw. Once the drawing was done, I would return to the original global space, which resulted in the piece being in its correct position, orientation, and size.

At this point, I could have a list of tokens and iterate through the list, drawing each token in its correct position on the global image. I then integrated the Webcam code into this, fetching the list of topcodes that the webcam read and transforming them into a list of token classes that could then be drawn. Each topcode had a position, orientation, and size that I used for the corresponding tokens.

Here I had a bit of an issue getting the webcam code and my code to work together, as the webcam code wasn't really designed to continuously give data to another part of the program. I got past this by having the webcam code run continuously in a different thread, and periodically asking it for its current topcode list.

Now the system could run continuously and keep an updated digital representation of a traffic system that the user had placed on the table. It was time to turn my attention to the cars. For this, I came up with a scheme where a car would have a set number of possible locations on each token, each with a hard-coded red rectangle that would be drawn at that location. Since the locations were relative to the tokens, the hard-coded values would move with the tokens as they were rotated and shifted around the table. The car would know which location it was at, and when it was time to move to the next location, it would simply update its current position variable and draw the rectangle for the new location.

Juno and I then started the incredibly tedious process of hard-coding graphics code for a rectangle at each possible position on each type of token. This took quite a while, but we got it done for nearly every token type. I now needed to implement the cars moving along the positions and drawing the rectangles as they went.

The first tricky part was handling when the car got to the end of a token and had to move to the next token. I had to create a network of connections, so that the connector of one token could tell the car what token it was connected to. I had the webcam read the locations of the connection points of each token, and if one was close enough to another, it would connect them. This meant creating a pointer from one to the other and back. Now, once a car got to the end of a token, it could ask the connector for the next token, set that to its current token, and set its position to 0. It would then move along in the next token until it got to the end, where it would repeat the process until it reached a connector which wasn't connected to another token.

The next tricky part was handling different possibilities for a car on a certain type of token. Depending on how a token was oriented and which direction the car or cars were coming from, the cars would have to go through the positions in different orders and be on different sides of the road. Fixing this was quite difficult and required some tricky math with various multiplication by -1 and different position offsets in each possible situation. Eventually I got it so the tokens could be placed in every possible way and the cars would drive in the correct direction and on the correct side of the road.

The final major programming tasks were making the system work with multiple cars at once (which created a whole additional bag of headaches) and getting the cars to move automatically with a timer, so that the user could press a button once and the cars would run through the system. Previously the user had to press a button for each car movement.

In addition to all the programming outlined above, Juno and I spent quite a bit of time trying to optimize the performance of the topcode reading, counter the interference the projector was causing, and align the projection with the physical objects. The performance of the topcode reading got a big boost by Mike and I putting a couple of hours into getting his custom webcam driver to work with our system, giving us full 2 megapixel resolution. I was able to solve the projector interference pretty well by using window tint film on the bottom of the glass and directly lighting the topcodes from below.

There were also countless smaller issues that would sidetrack me for a few hours here and there, but that was the major stuff. Hopefully this gives you a basic idea of my process throughout the extensive development that went into this project.