Bridge Command Forum

Development => Development => Topic started by: huckleberry on January 21, 2014, 11:11:12 PM

Title: Creating a controller program
Post by: huckleberry on January 21, 2014, 11:11:12 PM
I am working with my kids on a science project that requires us to write a program (most likely in python) that would control and track a boat, among other things.  I think BridgeCommander would be a great simulator for us to use to test our programming before putting it on the boat itself.  I am going through the documentation now to see how I could model our boat, but I am not exactly sure where to start as far as controlling the boat from an external program (instead of the built-in UI).  Could you point me in the right direction on how I could go about it?

Thanks.
Title: Re: Creating a controller program
Post by: forum_admin on January 23, 2014, 06:32:37 PM
That sounds an interesting project. Will your controller give the speed and heading of the boat, or the rudder and engine settings? Both approaches should be possible, using the UDP networking messages.

These are defined in http://bridgecommand.co.uk/Doc/networkprotocol.php

If you are controlling the engine and rudder settings, the boat's dynamics will be simulated in Bridge Command. For this approach, you'd run Bridge Command in 'Networked (Main)' mode, but instead of connecting to the 'Map Controller', you would connect to your own controller program, which would send 'MC' messages to Bridge Command via UDP. In particular, you would use the 'Engine and rudder failure record', using this to set the engine and rudder parameters.

Instead, if you are simulating the boat's dynamics yourself, giving speed and heading, you will need to use these to generate a current position in metres (relative to the South West corner of the sea area). You would then run Bridge Command in Secondary (3d) mode, and update its position by sending 'BC' messages to Bridge Command. You would also need to send at least one 'SC' message as well to set up the scenario.

Hopefully this and the documentation in http://bridgecommand.co.uk/Doc/networkprotocol.php should help you get this set up, but please ask if you have any questions.
Title: Re: Creating a controller program
Post by: huckleberry on January 23, 2014, 06:55:13 PM
Thanks for the reply.  I think this is going to work really well.  The MC engine and rudder failure record will be precisely what we need as that is the level of control we will have on the actual boat.

As far as tracking the boat it looks like BC record will have the info I need.  Can you confirm the following statements relative to the position data that is in the BC record:
1.  If I was in the most southern and most western position, it would be reporting 0,0
2.  BridgeCommander would never send negative numbers for position.
3.  In order to translate to a latitude, longitude, I will need to take the latitude, longitude of the most south-western position and calculate it based on the meters from south and west points.

That should be a good start.  I am sure I will have some more questions as I start to create my world and boat.  Very excited about using this tool.  Thanks for building it and helping.
Title: Re: Creating a controller program
Post by: huckleberry on January 24, 2014, 03:52:19 AM
Making progress...I am reading the BC records just fine.  Getting a memory access violation and crashing BridgeCommander when I try to send the MC record.  It is likely something I will figure out, but if you have any thoughts on what might be the issue, I would appreciate.

Thanks again for your help.
Ken
Title: Re: Creating a controller program
Post by: huckleberry on January 24, 2014, 08:41:11 AM
I have my prototype working!!  So excited for how this is going to work out.

My MC issue was due to not putting the length integer at the beginning of the string.
Title: Re: Creating a controller program
Post by: huckleberry on January 31, 2014, 03:20:00 AM
Is this true?
In order to translate to a latitude, longitude, I will need to take the latitude, longitude of the most south-western position of the scenario and calculate it based on the meters from south and west points that is returned in BC record.
Title: Re: Creating a controller program
Post by: forum_admin on January 31, 2014, 08:26:16 AM
Sorry for missing this part of the question.

Bridge Command uses a very simple projection, and this means that the translation from the position in metres sent over UDP to lat/long is:

Longitude[Degrees] = (X[Metres]  * TerrainLongExtent / terrain_x_width) + TerrainLong
Latitude[Degrees] = (Z[Metres] * TerrainLatExtent *  / terrain_z_width) + TerrainLat

In this, X and Z are the position from the South West corner in metres (the values sent over UDP), TerrainLat, TerrainLong, TerrainLongExtent and TerrainLatExtent are all set in the world model terrain.ini file.

Terrain_x_width is the world model width in metres, and is calculated:
terrain_x_width = TerrainLongExtent * 2 * Pi * EarthRadius * Cos(TerrainLat + (TerrainLatExtent/2)) / 360

similarly for terrain_z_width:
terrain_z_width = TerrainLatExtent * 2 * Pi * EarthRadius / 360

(EarthRadius is defined as 6.371e6 metres, and this assumes that your calculations are all in degrees.)

As Bridge Command does not stop you at the limits of the world model, it may return a negative X and Z value.

I hope that this helps!
Title: Re: Creating a controller program
Post by: huckleberry on February 02, 2014, 05:11:33 AM
Thanks a ton for continuing to help.  My formulas aren't returning the same as on the display of BC though.

Here is the code
Code: [Select]
     
      private const double EARTH_RADIUS = 6371000; //in meters
      double dTerrainXWidth = dTerrainLongExtent * 2 * Math.PI * EARTH_RADIUS * Math.Cos(dTerrainLat + (dTerrainLatExtent / 2)) / 360;
      double dTerrainZWidth = dTerrainLatExtent * 2 * Math.PI * EARTH_RADIUS / 360;

      double Longitude = (dXPosition * dTerrainLongExtent / dTerrainXWidth) + dTerrainLong;
      double Latitude = (dZPosition * dTerrainLatExtent / dTerrainZWidth) + dTerrainLat;

Here is the lat/longs I used in my calc from Santa Catalina:
Lat "32.58333"
Long "-119.0"
Lat Extent "1.0"
Long Extent  "1.0"

dXPosition is the first value of the Own ship location data from BC row.  dZPosition is second value.

See anything wrong here?

Title: Re: Creating a controller program
Post by: forum_admin on February 02, 2014, 09:39:02 AM
I think the only change required is to convert the angle used in the Cos() function into radians - you're currently giving it an input in degrees.
i.e.
Code: [Select]
Math.Cos(dTerrainLat + (dTerrainLatExtent / 2))becomes
Code: [Select]
Math.Cos((Math.PI/180)*(dTerrainLat + (dTerrainLatExtent / 2)))
Title: Re: Creating a controller program
Post by: huckleberry on February 02, 2014, 07:15:24 PM
Thanks again.  Getting closer...Latitude is on track, but still off a little on longitude.

I ran the boat aground so that I could play with it a bit.  With a X/Z position of 43944.3,94138.5 on the Santa Catalina map, the BC UI was showing long of 118 deg 31 min (and change).  My calc was showing 118.178848 which seems to come in at 118 deg 10 min (and change).
Title: Re: Creating a controller program
Post by: forum_admin on February 03, 2014, 10:10:09 PM
Hi,

It may be worth checking through each calculation step comparing the result to a manual calculation to check for any problems. The code I've tested, based on what you posted above, seems to give the correct result. This is in C++:

Code: [Select]
#include <iostream>
#include <cmath>

const double EARTH_RADIUS = 6371000; //in meters
const double PI = 3.141592653589793;

int main ()
{
    //Inputs (in metres)
    double dXPosition = 43944.3;
    double dZPosition = 94138.5;

    //Terrain parameters
    double dTerrainLongExtent = 1.0;
    double dTerrainLatExtent = 1.0;
    double dTerrainLong = -119.0;
    double dTerrainLat = 32.58333;

    //calculate width of terrain in metres
    double dTerrainXWidth = dTerrainLongExtent * 2 * PI * EARTH_RADIUS * cos( (2*PI/360)*(dTerrainLat + (dTerrainLatExtent / 2))) / 360;
    double dTerrainZWidth = dTerrainLatExtent * 2 * PI * EARTH_RADIUS / 360;

    //find lat & long
    double Longitude = (dXPosition * dTerrainLongExtent / dTerrainXWidth) + dTerrainLong;
    double Latitude = (dZPosition * dTerrainLatExtent / dTerrainZWidth) + dTerrainLat;

    //print out
    std::cout << "Long: " << Longitude << std::endl;
    std::cout << "Lat:  " << Latitude << std::endl;

    return 0;
}

Gives:

Code: [Select]
Long: -118.528
Lat:  33.4299

Which matches with the BC output.
Title: Re: Creating a controller program
Post by: huckleberry on February 04, 2014, 05:37:26 AM
Once again, big thanks.  found the issue and it was some misplaced parens. 

I really appreciate it and probably not the last time you hear from me, but hopefully, I can find someway to return the favor.
Title: Re: Creating a controller program
Post by: huckleberry on February 08, 2014, 02:18:06 PM
I was going to simulate a really long journey, not really caring about land features.  So, I created an empty world and off we went.  Things seem to be working fine for several hours (no we aren't just sitting there watching it), but eventually it reports "Aground" and becomes unresponsive.  Is there anyway around this?

Thanks in advance,
Ken
Title: Re: Creating a controller program
Post by: forum_admin on February 09, 2014, 09:23:45 PM
Hi, I haven't come across this before but can investigate more. When it became unresponsive, was the position displayed in Bridge Command reasonable, or did it go to Inf or NaN?
Title: Re: Creating a controller program
Post by: huckleberry on February 09, 2014, 09:32:34 PM
I haven't had a chance to fully see what all worked and didn't work.  The position seemed to be reporting correctly and I think the BC records were going to my listener just fine.  It just said "Aground" for speed in the UI, but pretty sure the BC record reported it fine.  It didn't respond to speed and rudder changes in the UI, but I didn't try via network communications.

I realize that I am using the tool for something outside its original intent, so no rush.  It still will have a lot of value for our project.  Thanks for all your work on it and your responsiveness to this thread.
Title: Re: Creating a controller program
Post by: forum_admin on February 10, 2014, 07:24:50 PM
Hi, I've looked into this a little more. If you start on the defined world area, and move off it, Bridge Command assumes that the seabed depth stays the same as the point just before you left the map, and if you start off the map, it will assume a depth of zero.

To find the depth under the keel, the tidal height is added, and the ship's draught taken away. Therefore if you have any tides configured, you may be 'running aground' when the tide falls. If this is the problem, starting on the defined world area, and making sure that it's deep enough to avoid any grounding should fix the problem.

Alternatively, there may be some sort of numerical jitter that's causing the maintained depth to reduce over time, but that seems quite unlikely.
Title: Re: Creating a controller program
Post by: huckleberry on February 12, 2014, 02:34:07 AM
I have decided it is something wrong with my world.  I am trying to use a file from the SRTM data.  The stats from it are:
Latitude min: 30 N      
             max: 35 N
    
Longitude min: 80 W      
                max: 75 W
    
Center point :
    Latitude 32.50 N
    Longitude 77.50 W

I have the boat start at the center point.  32.50,-77.50.

I noticed that it starts with depth under keel of 1.1

See anything wrong with the terrain.ini?  If I just wanted an empty map, would I just create an all-black bmp for height, texture and radar? 
I created a 2048x2048 bmp for the height map.

My terrain.ini looks like:
Number=1

RadarImage="radar.bmp"

HeightMap(1)="height.bmp"
Texture(1)="texture.bmp"
TerrainLong(1)=-80
TerrainLat(1)=35
TerrainLongExtent(1)=5.0
TerrainLatExtent(1)=5.0
TerrainMaxHeight(1)=633.0
SeaMaxDepth(1)=2063
TerrainHeightMapSize(1)=2048
Title: Re: Creating a controller program
Post by: huckleberry on February 12, 2014, 02:47:35 AM
changed TerrainLat(1) to 30 as I think I had that wrong but still same depth at the beginning.
Title: Re: Creating a controller program
Post by: forum_admin on February 16, 2014, 05:31:11 PM
Hi, that all looks reasonable. I've tried replicating your terrain.ini file (with TerrainLat(1)=30), using a plain black image for the heightmap, and it behaves as expected, with a large depth when the vessel starts at
Code: [Select]
InitialLong=-77.5
InitialLat=32.5
.
Is it possible that you may have switched the Lat and Long starting positions, so you're starting off the map?

Just one additional comment - because the height map is loaded from an image with only 256 grey shades, a terrain with such a large height range (-2063 to 633 metres) will load with large 'steps' visible in the land, as the height will only be resolved to the nearest ~10m. For very large depths (defaulting to 100m), the depth sounder will just read "-", so it may be best to truncate any depths below ~110 metres, which would increase the resolution of the heights that can be displayed.