Off The Rails
  • Home
  • Project
  • Blog
  • Docs
  • About the Author
  • Resume

Project Blog

This page contains updates on the state of the project.  Check back regularly to see if anything has changed!

Communication Is Key

4/17/2019

0 Comments

 
Over the past two days, I have put a lot of effort towards defining the protocol by which all of the pieces of my application communicate.  
0 Comments

File Format

4/16/2019

0 Comments

 
 tI've added the ability to read in a railyard layout from a file!  The file format is relatively simple right now, and some of the functionality for the view portion of my project is not yet present, but the implementation for reading the file is extensible and it will be able to handle the additional features when the time comes.  With that being said, take a look at this example of a .rail file that can be read into my simulation:
Example file denoting a section each for rails, turnouts, and trains
Example .rail file
The file is split into three sections, separated by "#" marks.  The three sections are the rails section, the turnouts section, and the trains section.  Let's go through some examples of a line in each of these sections.

The "Rails" Section

As of right now, lines in the "rails" section follow the format 'rail_id;connectionA;connectionB;orientation;x;y'.  Currently, the orientation, x, and y fields are unused, but they will be implemented later alongside the view component.  Look at the first line in the "rails" section of the file:  R0;-;R1;0;0;0.  This means that Rail #0 has a connection with Rail #1. ('-' means that the rail does not have a connection on that side.)  This section ends upon reading the first '#'.

The "Turnouts" Section

The "turnouts" section follows a similar but different format from that of the "rails" section.  Each line here has the format 'turnout_id;baseRail;straightRail;curvedRail;orientation;x;y', where the turnout_id is the ID of the current turnout, baseRail is the id of the rail connected to the 'input' portion of the turnout, straightRail is the rail connected to the 'straight' portion of the turnout', and curvedRail is the rail connected to the 'curved' portion of the turnout.  So, in the above file, Turnout #0 has Rail #1 as its base rail, Rail #2 as its straight rail, and Rail #15 as its curved rail.  This section ends upon reading the second '#'.

The "Trains" Section

The "trains" section has a relatively simple format compared to the other two.  Each line consists of the trainID (E is for 'engine'), the ID of the rail the train is on, and the train's speed (trainID;railID;trainSpeed).  This will likely be extended to include things like whether the train's horns and lights are enabled in the future.  The '#' at the end of this section also denotes the end of the file.

Reading In The File

To actually read in the information from the file, my program does the following:
  • Iterate through the Rails section, creating each rail & adding it to a list of rails and storing the connection IDs in a string array for later
  • Iterate through the Turnouts section, creating each turnout & connecting it to its three corresponding rails
  • Connect the remaining rails together based on the connection IDs that were read in
  • Create the trains listed in the Trains section & place them on their respective rails

Conclusion

Anyway, that is a little bit of information on what a .rail file is and how my program reads them in.  I hope that this was a clear explanation.  See you next time for the next update!
0 Comments

Quick Update - Turnouts

4/15/2019

0 Comments

 
Hello again!  Just a quick update here:  I got turnouts to work with my new rail system!  They do not function exactly the same as the rails do, but with them working my rail model now functions as expected!  I was able to recreate the layout that I was having trouble with in one of my more recent blog posts and it works as expected now.

The next thing on the list is to create and load rail layouts from a file and to send information back and forth between a client and the simulator server.  Stay tuned for updates on that!
0 Comments

Getting Slightly Derailed & the Importance of Little Victories

4/12/2019

0 Comments

 

Getting Slightly Derailed

First of all, I would like to apologize for the late blog post this week. I spent some time last week redefining my rail, turnout, and train data models and, right when I was ready write up a post about how they worked, I found out that they didn't work. Well, that isn't completely true; they DID work, but they were missing some important functionality, so I had to go back to the drawing board.

As I mentioned in this blog post way back when, the main core of the railway data model is a doubly-linked list.  Each rail segment (henceforth known as just 'rail') knows what rail comes 'before' and 'after' it, turnouts are special rails that have three connections to other rails and a handful of special properties regarding their state, and trains move along these rails by following the references between them.  The problem that I encountered with my data model last week is that 'before' and 'after' were a little too strong of words.

In the real world, of course, your average rail has no care for direction. If the train comes in from the left side, it goes out the right, and vice versa. In my old data model, the next pointer of one rail segment would connect to the rail ahead of it and its previous pointer would connect to the rail behind it:
A diagram showing how rail segments connect to each other.
Directed Rails Example
This system works great, but only if your rails read left to right. Making the train drive backwards is even easy, since you can just make it follow the 'previous' pointer instead of the 'next' one!  However, if the meaning of 'forward' to a train ever changes, you are out of luck if you go this route.  

I was testing the following layout when I discovered this problem:
Picture
See the problem here? Maybe it will help if I add the direction of the 'next' pointers to the next rail in the layout (denoted by the orange arrows).
Picture

​As you can see, when a train goes around the curve, it's concept of 'forward' changes, but the rail layout has an intrinsic sense of what 'forward' should be. Therefore, if the curve is attached the way it is to the rails, the train will get stuck on the boundary between the curve and the bottom straightaway. Uh oh!

What Now?
At first I was dumbfounded at how to fix this problem.  Other people suggested that I just flip all of the pointers on the bottom straightaway so that it is one continuous segment, but what if there is another train on it whose concept of 'forward' is left-to-right?  So, I decided that the best way to solve this was to make the rails directionally agnostic, and to move the burden of motion onto the train, like in real life.

After a few re-works, I decided on a pretty solid system.  The rails still have two pointers to their neighbors, but now they have no semantics of direction attached to them.  They are simply connected to each other with up to two connections, and they will accept no more than that.  (Turnouts are an exception to this rule, of course, as they need three different connections, but I am still working on those.)  To compensate for this, trains now keep track of the rail that they are currently on AND the last rail that they were on.  That way, when a train queries the rail it is currently on for where to go next, the rail checks its connections to see which of them is the last rail, and it returns the opposite.  In simple terms, if the train came in from the left, it is sent out to the right!

This complicates making a train go in reverse, but all you really have to do is send it back to the last rail it was on and use the current rail as the last rail when determining where to go from there.  It's a pretty slick system, if I do say so myself.  With these modifications, the "curve" problem from above is solved.
​

The Importance of Little Victories

To be honest, it really got to me for a while when my direction-based rail model didn't work.  For a while, I considered completely throwing away my rail-linking model and starting over using a two-dimensional array.  I'm glad I didn't do that, as I'm sure it would have introduced many more unforeseen problems, but I was very close to scraping a lot of work, which would not be good what with how little time there is left until capstone presentations.

That being said, it feels so good now that I have solved the directional problem by going back and iterating on my previous solution.  I will need to be doing a lot of that over the next few days in order to get this project done on time.  I think I also learned a valuable lesson to not be as discouraged or to panic the next time I run into a similar problem.  If I overcame this one, I can overcome the next one, too.

With that said, stay tuned for the next update.  There should be a lot coming in the next two weeks!
0 Comments

Connecting The Dots

3/31/2019

0 Comments

 
Today, I figured that I would take a break from working on the desktop-application portion of my capstone and decided to take a crack at the API portion of my project before it gets too late.  Truth be told, I have been a little jealous of my peers lately who have tasks like "get x login service to work" because they have very tangible results and it is always fun to get things to work together.  So, I thought that working on my API would give me a taste of that feeling, and I set to work on it.

The goal for today was to decide on a protocol for communication between the various pieces of my project (i.e., TCP/IP, web server that communicates via http requests, etc.), and to get a test connection set up and working between two different machines.  I decided that I would like to make a REST API between my client applications and my simulation server.  That way, I can pass JSON objects containing the state of the simulation back and forth via http requests.  This decision was also made in an effort to homogenize my methods of communicating between applications.  I am worried about using TCP/IP with Javascript, which will be important when I work on the mobile cabs for the simulator.  But, I know that http requests are easy to do in Javascript and I know that they are possible in C# with similar structure, so that is why I decided on using that method for communication.

So, in order to facilitate this REST API, I wrote a very simple web server using Node.js with the Express module by following this guide.  I have a long way to go to refine it and develop my API in full force, but right now I have set up some logic that returns a JSON object containing info for a sample train when you make a GET request to http://johnmcgorey.com:3000/sample_train.
Sample Get Request returning sample train JSON object
Sample GET Request
The biggest challenge of today wasn't creating this web server.  It was making the web server available over the internet so that I could access it from anywhere.  Luckily, I have had some experience with configuring networks in the past, so I knew generally what I had to do, but it took some floundering through some port forwarding and some Windows firewall rules before I was able to access the web server (shoutout to Josh Lamack and Luke Van Vonderen for helping me through this process).  It was all worth it, though, because I have a working connection now!  

From here, the next steps are to flesh out the API/web server and to integrate that connection with my main desktop application and a mobile cab.  One thing I would like to do is make a change in some data on the desktop that is then reflected on the mobile cab.  Something I am concerned about is making the server send data to the client apps without it being requested, which might violate the principles of a REST API, but I will tackle that when I run into the issue.  I might be able to find a creative way around that issue.  

As always, stay tuned for more updates to come!
0 Comments

Beginnings of a Level Editor

3/27/2019

0 Comments

 
I took some time today to lay down some of the groundwork for the CCR simulator's level editor, and I just wanted to share some of the progress that I made.  Most of my efforts today went towards the user interface of the level editor, but I did do a bit of preparation for allowing the user to place objects and to draw said objects (more on that later).

For a brief recap, this level editor is what is going to allow a user to sketch out a "railyard" to run the trains in.  It will let them place down rails, sensors, trains, and maybe more wherever they want.  After everything is placed the way they like, the user can then save this "layout" and run the simulation on it.  So, that's the goal.

As of right now, I have a form that presents a user with five "tools" that they may use to interact with the simulator layout:
  1. Place Rail (This allows a user to place a rail down on the map)
  2. Place Sensor (This allows them to place a sensor on top of an already-placed rail)
  3. Place Train (This lets them place a train's starting position on an existing rail)
  4. Selector Tool (This lets them select one or more placed objects for manipulation or deletion)
  5. Eraser Tool (This deletes any object the mouse passes over when the user clicks and drags)

The user can select these tools by clicking on the icon for the tool on the toolbar or by pressing the corresponding key on the keyboard (i.e., 1-5).  The user can deselect  a tool by clicking on the icon again or by hitting the 'q' key (for quit!).  When a tool is selected, a semi-transparent "ghost" image corresponding to what it does shows up under the mouse cursor.  This is to give some feedback to the user about what will happen when they click the mouse.  Let's look at a couple of these ghosts:
GIF of Ghost Images Changing
Different Ghosts appear based on which tool is selected
In the above GIF, I am cycling through the different options by pushing the number keys 1-5 (notice how the currently selected tool is highlighted).  Each ghost that you see is trying to express what will happen when the user clicks the mouse. The rail tool currently has a thin line as ghost to show that it will place a rail, the sensor tool has a circle, the train a square, and the eraser has an empty square.  The select tool probably won't end up having a ghost because it is not placing/removing anything, but it will have graphical effects to illustrate the area it is affecting, and the selected objects will be highlighted in some way.  

Now, just placing horizontal lines for rails isn't going to get you very far in designing a railyard, so I also allow the user to rotate the object they are going to placed by pressing the 'r' key.  The ghost also rotates accordingly.  In an effort to keep things simple, I am constraining rotation to 45 degree increments, so there are eight orientations that an object can be in, although only four are really useful in most cases.  The result looks like this:
Rotating an Object
Rotating an Object
Realistically, this eight-directional rotation might only apply to rails, as everything else sort of snaps to the rails, but we will see.  

One final note:  the details of a lot of things that I mentioned above are likely going to change.  The shape of the ghosts will probably change, I may add more tools as I think of them, and the location of the user controls on the form may change.  However, there are a lot of good ideas here that I am excited about, and I'm pretty happy with what I have accomplished with this editor so far.

Anyway, that is what I have accomplished today.  Here are the next steps that I have in mind:
  • Allow the User to Place and Delete Objects.  Ghosts are all well and good, but this editor isn't useful unless the user can actually, you know, edit.
  • Create Better Tool Icons.  If you have a keen eye, you may have noticed that the icons for the tools are rather hastily drawn and there are a few repeats.  I'll come back to these down the road and create some proper icons to represent the tools, but I just needed some placeholders for now.
  • Create an Undo/Redo Stack.  This one is pretty self explanatory.  I want users to be able to undo and redo their actions using the ctrl + z, ctrl + y method (and maybe some buttons).  I just think that this is a nice quality of life feature to have, and it should not be too hard to implement.
  • Make the Editor Scrollable/Pannable/Zoomable.  I want the user to be able to move around the "canvas" I set out for them.  This is not a priority, though, so I will try to implement it if I have time.  Plus, I can use what I learned at my last draft for the view component to help me do this.
I have my concerns about some of these tasks, namely allowing a user to place objects, but I'll figure it out with time.  Stay tuned for further progress updates!
0 Comments

Spring Break Update

3/24/2019

0 Comments

 
Hello!  I just wanted to give a quick update on the state of the project after this past week.  Unfortunately, I was in Utah on spring break for most of the week and did not make much progress as a result.  However, I did tweak my major view component a little bit and I ported it over to my main working project instead of keeping it in the prototype project.  I believe that it is ready for the next phase, which will be creating the level-editor for the train simulation.  Stay tuned for updates on that!

This upcoming week is relatively open for me, so I will hopefully be able to make a lot of progress on the project.  I am getting nervous about the quickly-approaching deadline, so I will be making better efforts over these next few weeks to really get things done.  See you next time! 
0 Comments

Creating The View

3/6/2019

0 Comments

 
Over this past week, I spent a lot of time trying to create a panel for my train-rail-yard view.  The goal was to create a panel where I could scale the drawings to "zoom in and out" on the view and where I could pan the image around to see different parts of the track.  I thought that this would be a fun and interactive way to control the train simulator, but so far it has proven itself as quite the challenge to pull off.

I started working on this view component by creating a new C# project to work in.  After a few false starts, I came pretty close to my goal, but I am not quite there yet.  Basically, the view works by drawing all of the graphics to a bitmap object, using the center of the bitmap as the origin point for graphical coordinates.  From there, that bitmap is scaled according to a designated scale factor and drawn to the screen using a graphics object.  An offset on where to place the image (which is set by a handful of mouse click & drag events) creates the panning effect.  

For the most part, this works how I want it to, and I think the core principles of what I have are solid, but there are a few tweaks that need to be made before I consider this component usable.  For example, when you scroll the mouse wheel to increase the scale factor and "zoom in", it moves the picture relative to the top left corner rather than where you scroll.  Also, I have yet to find a way to prevent the user from scrolling off of the side of the image.  I tried to put limits on the image offsets so that it would not move past the sides, but this didn't work how I wanted it to.  So, there is still some work yet to do on this part!  

Anyway, here a couple screenshots showcasing my testing project in its current state:
Picture
No Pan - Scale Factor 1
Picture
No Pan - Scale Factor 0.5
Picture
Panned up and to the left - Scale Factor 0.5
I know these pictures aren't incredibly helpful, but I hope they help give an idea of what's going on here.  I tried to make some GIFs to show off the functionality, but they were moving very fast and honestly gave me motion sickness, so I chose to omit them here. 

Some Other Thoughts

I was looking at my Gantt chart today, and I noticed that I am behind schedule for my project.  This is partially because I shifted gears to work on the view first in order to properly test the other aspects of the program, but I also poorly estimated the kind of time that I would need to accomplish some of the tasks.  I will need to re-evaluate this chart and figure out how to balance my time better.  

As always, stay posted for more updates!
0 Comments

Something To Work With

3/3/2019

0 Comments

 
Over the course of this past week, I spent some time creating a project where I could test out my ideas for the data structures behind the simulator.  Something that has been really holding me back is that I am intimidated of connecting the various pieces of my project, so I started this test off by strongly coupling two of the parts together with the intention of splitting them apart later.  So, here is what I came up with this week:
Picture
Visual Demo of the Train System
To offer a brief explanation of what you are seeing above, there are three trains (Thomas, Henry, and Oliver) going around a circular track consisting of 20 rails.  Notice how the colored squares loop around when they reach the end of the screen.  Of course, this interface is specifically tailored to this scenario, and a lot of work will need to be done to make a useful interface going forward, but this serves as a good sketch of what's going on right now.

Also important is the log at the bottom of the image.  For each train in each update, the update number, train name, train number, train status, and rail is logged.  This will give me an idea of what the status of the track is while I am working towards a more robust rail layout.

Anyway, that is all for this update.  The tasks ahead of me are to start developing a more robust layout and adding more functionality to the simulator data model.  Stay tuned to see what comes next!
0 Comments

The Way Forward

2/21/2019

0 Comments

 
After  last week, one of my main concerns was to define the direction that I am heading in with this project.  The poster sessions that we had last week made me realize that I did not have as solid of an idea of the components of the project as I thought.  So, I spent some time thinking about it, and this is where I am at right now:
Data Flow for the project
Data Flow for Off the Rails (2/19/19)
Above, you see a data flow diagram for my Off the Rails project as of 2/19/19.   Drawing this out really helped me to consolidate my ideas for the project, and I think I can now head in a good direction.  Of course, this data flow is subject to change in the future.  In fact, it may have already, but more on that later.

In any case, let me offer a brief explanation of the diagram above.  Essentially, the program will be split into five parts
  1. The main simulator core, which will handle the data, perform the logic, and act as sort of a "server" for the other parts.
  2. The API layer that allows for communication between the simulator core and its various extensions.
  3. The admin desktop application, which will let a user define a rail layout and place trains in its edit mode, and which will let the user run the simulation in its view mode.  From here, they may drive the trains.
  4. The "remote cab" web client, which will just offer the view portion from the admin client, but it will be available from a web browser.  These users will also be able to drive the trains.  Specifics on both of these view clients will be covered later in the development timeline.
  5. The meta language listed in the requirements.  This part is not very fleshed out yet, but it will have to be able to send back instructions/information to the core simulator at the very least.

For the most part, these various pieces will be passing train and track info back and forth.  I am concerned on how they will all stay synced up, but I will worry about that later.  That's a problem I will have to solve when the various pieces actually exist.  I'll see you next time with more updates!
0 Comments
<<Previous

    Author

    Hi, my name's John!  To get to know more about me, check out the About The Author page.

    Archives

    April 2019
    March 2019
    February 2019

    Categories

    All

Create a free web site with Weebly
  • Home
  • Project
  • Blog
  • Docs
  • About the Author
  • Resume