Cosmik42

Control all your Powered Up & Power Function (SBrick) devices with a single software

Recommended Posts

That's clever!

The whining in low speeds is horrible...

I'm also using variables for the speed, was helpful during our last show - as the batteries grew weak I'd just bump the values up in one place.

Share this post


Link to post
Share on other sites

I'll offer up a BAP code snippet here too, to try to help reduce the effort someone might require to create their own code.

In my Globals, I have the following:

  // Enumeration to access individual operation configuration values.
public enum config
{
  initialised,
  cycle_timer_prefix,
  cycle_timer_suffix,
  inter_train_ms_delay,
  operate_using_timer,
  ramp_speed_from,
  ramp_speed_to,
  ramp_ms_duration,
  within_cycle,
  debug,
  eastbound_train,
  eastbound_train_active,
  westbound_train,
  westbound_train_active
};


// ------------------------------------------------------------------------
// Routine name  : configure
// Description   : Configure the operational parameters.
// Arguments     : hub_list_ao
//                   List of hubs defined for the program. The State
//                   property of the 0th list is used to hold configuration
//                   data. This approach is used due to not seeming to be
//                   be able to have objects defined within the globals
//                   persist beyond the life of the routine instantiating
//                   them.
// ------------------------------------------------------------------------
public static void configure
(
  List<LegoTrainProject.Hub> hub_list_ao
)
{
    // If initialisation has yet to occur ...
  if (hub_list_ao[0].State[(int)config.initialised] == 0)
  {
      // ... note that is is now initialised.
    hub_list_ao[0].State[(int)config.initialised] = 1;
    MainBoard.WriteLine("initialisation");
      // Set the initial values.
    hub_list_ao[0].State[(int)config.cycle_timer_prefix] = 3000;
    hub_list_ao[0].State[(int)config.cycle_timer_suffix] = 60000;
    hub_list_ao[0].State[(int)config.inter_train_ms_delay] = 7000;
    hub_list_ao[0].State[(int)config.operate_using_timer] = 0;
    hub_list_ao[0].State[(int)config.ramp_speed_from] = 70;
    hub_list_ao[0].State[(int)config.ramp_speed_to] = 85;
    hub_list_ao[0].State[(int)config.ramp_ms_duration] = 2000;
    hub_list_ao[0].State[(int)config.within_cycle] = 0;
    hub_list_ao[0].State[(int)config.debug] = 0;
    hub_list_ao[0].State[(int)config.eastbound_train] = 2;
    hub_list_ao[0].State[(int)config.eastbound_train_active] = 0;
    hub_list_ao[0].State[(int)config.westbound_train] = 3;
    hub_list_ao[0].State[(int)config.westbound_train_active] = 0;
  }
  configuration config_lo = new configuration();
  config_lo.show("Operation configuration", hub_list_ao);
}  // configure

    // ------------------------------------------------------------------------
public class configuration
{
  private int _cycle_timer_prefix;
  private int _cycle_timer_suffix;
  private bool _debug;
  private bool _initialised;
  private int _inter_train_ms_delay;
  private bool _operate_using_timer;
  private int _ramp_speed_from;
  private int _ramp_speed_to;
  private int _ramp_ms_duration;
  private int _eastbound_train;
  private bool _eastbound_train_active;
  private int _westbound_train;
  private bool _westbound_train_active;
  private bool _within_cycle;
    // Provide definitions for each property managed within a PropertyGrid
    // control.
  public int cycle_timer_prefix
  {
    get
    {
      return _cycle_timer_prefix;
    }
    set
    {
      _cycle_timer_prefix = value;
    }
  }
  public int cycle_timer_suffix
  {
    get
    {
      return _cycle_timer_suffix;
    }
    set
    {
      _cycle_timer_suffix = value;
    }
  }
  public bool initialised
  {
    get
    {
      return _initialised;
    }
    set
    {
      _initialised = value;
    }
  }
  public int inter_train_ms_delay
  {
    get
    {
      return _inter_train_ms_delay;
    }
    set
    {
      _inter_train_ms_delay = value;
    }
  }
  public bool operate_using_timer
  {
    get
    {
      return _operate_using_timer;
    }
    set
    {
      _operate_using_timer = value;
    }
  }
  public int ramp_speed_from
  {
    get
    {
      return _ramp_speed_from;
    }
    set
    {
      _ramp_speed_from = value;
    }
  }
  public int ramp_speed_to
  {
    get
    {
      return _ramp_speed_to;
    }
    set
    {
      _ramp_speed_to = value;
    }
  }
  public int ramp_ms_duration
  {
    get
    {
      return _ramp_ms_duration;
    }
    set
    {
      _ramp_ms_duration = value;
    }
  }
  public bool debug
  {
    get
    {
      return _debug;
    }
    set
    {
      _debug = value;
    }
  }
  public bool within_cycle
  {
    get
    {
      return _within_cycle;
    }
    set
    {
      _within_cycle = value;
    }
  }
  public bool eastbound_train_active
  {
    get
    {
      return _eastbound_train_active;
    }
    set
    {
      _eastbound_train_active = value;
    }
  }
  public bool westbound_train_active
  {
    get
    {
      return _westbound_train_active;
    }
    set
    {
      _westbound_train_active = value;
    }
  }

  // -------------------------------------------------------------------------
  public void show
  (
    string window_title_as,
    List<LegoTrainProject.Hub> hub_list_ao
  )
  {
    initialised        = (hub_list_ao[0].State[(int)config.initialised] == 1);
    cycle_timer_prefix = hub_list_ao[0].State[(int)config.cycle_timer_prefix];
    cycle_timer_suffix = hub_list_ao[0].State[(int)config.cycle_timer_suffix];
    inter_train_ms_delay = hub_list_ao[0].State[(int)config.
        inter_train_ms_delay];
    operate_using_timer = (hub_list_ao[0].State[(int)config.
        operate_using_timer] == 1);
    ramp_speed_from  = hub_list_ao[0].State[(int)config.ramp_speed_from];
    ramp_speed_to    = hub_list_ao[0].State[(int)config.ramp_speed_to];
    ramp_ms_duration = hub_list_ao[0].State[(int)config.ramp_ms_duration];
    within_cycle     = (hub_list_ao[0].State[(int)config.within_cycle] == 1);
    debug            = (hub_list_ao[0].State[(int)config.debug] == 1);
    eastbound_train_active = (hub_list_ao[0].State[(int)config.
        eastbound_train_active] == 1);
    westbound_train_active = (hub_list_ao[0].State[(int)config.
        westbound_train_active] == 1);
      // Create a form, setting the form's title.
    Form prompt_lo = new Form();
    prompt_lo.Width  = 500;
    prompt_lo.Height = 400;
    prompt_lo.Text   = window_title_as;
      // Create a propery grid in which to alter the public properties.
    PropertyGrid properties_lo = new PropertyGrid()
    {
      Size                       = new System.Drawing.Size(400, 220),
      Location                   = new Point(10, 80),
      CommandsVisibleIfAvailable = true,
      TabIndex                   = 1,
      Text                       = "Property Grid",
      HelpVisible                = false,
      ToolbarVisible             = false
    };
    properties_lo.SelectedObject = this;
    prompt_lo.Controls.Add(properties_lo);
    ComboBox eastbound_lo = new ComboBox();
    ComboBox westbound_lo = new ComboBox();
      // Add labels for the comboboxes.
    for (int i_li = 0; (i_li < 2); i_li++)
    {
      Label label_lo = new Label();
      label_lo.Text  = "Hub for " + ((i_li == 0) ? "eastbound" :
          "westbound") + " train";
      label_lo.Width = 110;
      label_lo.Left  = 10;
      label_lo.Top   = 12 + i_li * 30;
      prompt_lo.Controls.Add(label_lo);
      if (i_li == 0)
      {
          // Add a combo box for selecting the eastbound train hub.
        for (int j_li = 0; (j_li < hub_list_ao.Count); j_li++)
        {
          eastbound_lo.Items.Add(hub_list_ao[j_li].OfName.Substring(3));
        }
        eastbound_lo.SelectedItem = (hub_list_ao[hub_list_ao[0].State[
            (int)config.eastbound_train]]).OfName.Substring(3);
        eastbound_lo.DropDownStyle = ComboBoxStyle.DropDownList;
        eastbound_lo.Left = 120;
        eastbound_lo.Top  = label_lo.Top - 2;
        prompt_lo.Controls.Add(eastbound_lo);
      }
      else
      {
          // Add a combo box for selecting the westbound train hub.
        for (int j_li = 0; (j_li < hub_list_ao.Count); j_li++)
        {
          westbound_lo.Items.Add(hub_list_ao[j_li].OfName.Substring(3));
        }
        westbound_lo.SelectedItem = (hub_list_ao[hub_list_ao[0].State[
            (int)config.westbound_train]]).OfName.Substring(3);
        eastbound_lo.DropDownStyle = ComboBoxStyle.DropDownList;
        westbound_lo.Left = 120;
        westbound_lo.Top  = label_lo.Top - 2;
        prompt_lo.Controls.Add(westbound_lo);
      }
    }
      // Display the form.
    prompt_lo.ShowDialog();
      // Note the values entered within the property grid.
    hub_list_ao[0].State[(int)config.initialised] = initialised ? 1 : 0;
    hub_list_ao[0].State[(int)config.cycle_timer_prefix] = cycle_timer_prefix;
    hub_list_ao[0].State[(int)config.cycle_timer_suffix] = cycle_timer_suffix;
    hub_list_ao[0].State[(int)config.inter_train_ms_delay] =
        inter_train_ms_delay;
    hub_list_ao[0].State[(int)config.operate_using_timer] =
        operate_using_timer ? 1 : 0;
    hub_list_ao[0].State[(int)config.ramp_speed_from] = ramp_speed_from;
    hub_list_ao[0].State[(int)config.ramp_speed_to] = ramp_speed_to;
    hub_list_ao[0].State[(int)config.ramp_ms_duration] = ramp_ms_duration;
    hub_list_ao[0].State[(int)config.within_cycle] = within_cycle ? 1 : 0;
    hub_list_ao[0].State[(int)config.debug] = debug ? 1 : 0;
    hub_list_ao[0].State[(int)config.eastbound_train_active] =
        eastbound_train_active ? 1 : 0;
    hub_list_ao[0].State[(int)config.westbound_train_active] =
        westbound_train_active ? 1 : 0;
      // Use the combobox values to identify the eastbound and westbound
      // trains.
    hub_list_ao[0].State[(int)config.eastbound_train] = (int)eastbound_lo.
        SelectedIndex;
    hub_list_ao[0].State[(int)config.eastbound_train] = (int)eastbound_lo.
        SelectedIndex;
  }  // show
} // configuration

Using PropertyGrid allows me to try out different configuration values on the fly. I add a sequence with my which simply contains:

  // Operate the configuration window.
configure(Hub);

which will open a window, allow me to tutu with the values and see the impact.

Caveat: I've programmed in many languages but until now, not C#, so the code may be ugly.

Regards,

David

 

Share this post


Link to post
Share on other sites
On 10/27/2019 at 7:58 AM, Lok24 said:

I have only 6 tracks here to test, the tiles are only 2 Tracks apart

No, it doesn't anything, it waits for event.....

You should move the engine manually to one of the colored tiles in the track, that causes an event in BAP and starts the programm sequences.

Or you edit the event with


if (Hub[0].State[0] == 0)

(which is initialised to 0 during the code within BAP which you can't see)

and click on "run code"

 

I have it working now so many thanks for the assistance. Everything looked fine but the sensor wasn't detecting the coloured plates on the track until I lowered it by one brick.  My only disappointment now is how far the loco runs (about 12 studs) after the colour detection.

Share this post


Link to post
Share on other sites
16 minutes ago, Snapshot said:

I have it working now so many thanks for the assistance. Everything looked fine but the sensor wasn't detecting the coloured plates on the track until I lowered it by one brick.  My only disappointment now is how far the loco runs (about 12 studs) after the colour detection.

You could

1.) move the colored plates 12 studs

2.) add plates to slow down and then brake at desired place

Share this post


Link to post
Share on other sites
42 minutes ago, Lok24 said:

You could

1.) move the colored plates 12 studs

2.) add plates to slow down and then brake at desired place

The sensor in my 60197 is connected to the train baseplate with a single bracket, and the color markers are a plate+tile.

https://imgur.com/p4CRWCw (file upload limits are crazy here...)

Reducing the speed a little helps with detection and responsiveness.

Also note that some colors are detected more successfully than others and at greater distances - red is furthest, then yellow and finally white - from my experience, so it's worth experimenting with different colors.

In our last event I had a yellow marker to slow down the train and then a red to stop it.

Share this post


Link to post
Share on other sites
On 10/28/2019 at 5:23 PM, Lok24 said:

You could

1.) move the colored plates 12 studs

2.) add plates to slow down and then brake at desired place

1. Well, yes, obviously.

2. A better idea and one I was going to use with my NXT-controlled PF trains.

However, there is definitely a delay in BAP compared with the same function in the PoweredUp app. I went back to the app and found what I wanted was very simple:

Powered-up%20GBC1.jpg

And, at the same speed, this stops the loco within four or five studs. I wouldn't be at all surprised if it's Windows getting in the way and slowing everything down. Still, whichever device I use as the controller, I can now continue with the rest of the design of the GBC module.

Share this post


Link to post
Share on other sites
12 minutes ago, Snapshot said:

And, at the same speed, this stops the loco within four or five studs. I wouldn't be at all surprised if it's Windows getting in the way and slowing everything down. Still, whichever device I use as the controller, I can now continue with the rest of the design of the GBC module.

You can change the refresh rate of the sensor in BAP by editing the hub it's connected to.

Try out different numbers there.

Share this post


Link to post
Share on other sites

Unfortunately, that doesn't change the stopping distance as what it does affect is the time between detections. If it's more than the configured time since the last detection then the sensor responds immediately to the next. But if it's less than that, the sensor will miss a second coloured plate that's too close to the first. I've taken it down to 800mS to make the loco slow down on one plate and stop on the second as @Lok24 suggested. This works very well.

However, that throws up another problem of what colours the sensor will detect reliably. Red, white and yellow are fine but I need a fourth. Orange is detected as red. blue & green aren't detected at all and I haven't got any other colours without going out to the garage to hunt for something. Have you found any others that work?

 

Share this post


Link to post
Share on other sites

None of the other colors worked reliably for me.

I suggest using flags or hub states to allow for more complex situations, @Lok24 mentioned it in one of his previous snippets.

So the first yellow plate will slow the train and set up a flag so the next yellow is ignored.

Then the last color in the chain can reset the states for the next pass.

That's how I'm going to tackle my next layout - and how I've done it on the PoweredUp mobile app.

Share this post


Link to post
Share on other sites

Thanks, that's what I suspected about the colours. I was able to set up the code for a four-state hub state yellow this afternoon and it works. I had to do a bit of Googling to find the Return statement to stop the code dropping through the detected If statement and executing the one that the hub state had just changed to. I've never learned any version of C which is hampering me a bit.....

Share this post


Link to post
Share on other sites

Yeah, I'm not a developer either but have experience with scripting languages, fortunately, hacking and pasting works in this level of complexity 😅

Share this post


Link to post
Share on other sites

Oh, I used to be and most of it was real-time stuff to do with telephone exchanges and data comms so using flags to control things takes me right back thirty years and more. It's just that C has never been part of my life before.

Share this post


Link to post
Share on other sites

Hello,

I discover your program to pilot all my Powered Up Lego trains. Thanks a lot for your development, it works perfectly, and it is very easy to use ;-)

My Horizon Express has 2 motors (one in front locomotive and the other in back locomotive) and it was easy to synchronize 2 motors on only one slider with the programming tool.

// Horizon Express - 2 motors management
//=======================================

while(Hub[4].IsConnected)
{
    // Synchronize motor 2 on motor 1 speed
    Hub[5].SetMotorSpeed("A", Hub[4].GetSpeed("A")); 

    // wait 0,25 sec to update motor 2 speed on motor 1
    Wait(250);
}

 

Could it be possible to synchronize the color of the train icon (always green) with the color choosen in the hub configuration ?

Edited by RayZZoo28

Share this post


Link to post
Share on other sites

I'm new to Lego (but played plenty of Factorio) so used to dividing tracks into blocks to automate trains.

Are there any tutorials?

What hardware do I need?

Does this work with Bluetooth 5.0?

I understand how the PC would talk to powered up hubs as they're bluetooth, but aren't prior devices infrared? How would they communicate? eg. Powerfunctions, sbrick, wedo..

Can I increase the amount to junctions searched forward above 2 with code (for complex intersections), or is it a hard limit?

What are the best sensors/hubs/auto switches (or motors) to buy in bulk if I'm starting from scratch?

Currently looking at powered up trains as they can be stopped individually by Bluetooth and it's easier to cut plastic track than metal, but if there's a limit of 5 hubs can I only have 5 trains and no sensors/switches?

Share this post


Link to post
Share on other sites

Hi,

31 minutes ago, Stevepunk said:

What hardware do I need?

One ore more hubs, motors and depending on the Software to control a smart device or PC.

31 minutes ago, Stevepunk said:

I understand how the PC would talk to powered up hubs as they're bluetooth, but aren't prior devices infrared? How would they communicate? eg. Powerfunctions, sbrick, wedo..

Yes, the Powerfunction devices are infrared. Of course you can mix that with some own soft/hardware, but I would not recommend.
SBrick and WeDo are BT as well.

31 minutes ago, Stevepunk said:

Can I increase the amount to junctions searched forward above 2 with code (for complex intersections), or is it a hard limit?

 

The Smart Hubs (as in the trains) have two connectors, the technic Hub 4, but is to large for train.
You can't increase.

31 minutes ago, Stevepunk said:

What are the best sensors/hubs/auto switches (or motors) to buy in bulk if I'm starting from scratch?

That depends of what you want to do, I have good experience with motor 45303  and sensor 88007 , best offer for motors and sensors is the LEGO shop.
Best offer for Hubs is Bricklink.

 

31 minutes ago, Stevepunk said:

Currently looking at powered up trains as they can be stopped individually by Bluetooth and it's easier to cut plastic track than metal, but if there's a limit of 5 hubs can I only have 5 trains and no sensors/switches?

There is no limit of 5 hubs for controlling, there is a limit of 5(6) Hubs connecting them to a LEGO network.

All solutions and recommendations depend of what you want to do....

 

Edited by Lok24

Share this post


Link to post
Share on other sites
22 hours ago, Lok24 said:

All solutions and recommendations depend of what you want to do...

I'd like to have a complex intersection of 12+ blocks with at least 5 trains.

Share this post


Link to post
Share on other sites

Sure, but how do you want to control them?

Completed Automatic?

Simple plan or AI?

What are "blocks" when talking about an "intersection"?

How many trains will run simultaniously?

How many switches are planned?

Do they all need motors?

And so on..... too many questions :wink:

 

 

Share this post


Link to post
Share on other sites

Hello

I´d like some help with C++ variable assignment and reassignment.

In Global code I declare:

publ INT B_red=0;
 

In Sensor event code:

if(B_red==0); //its OK

B_red=1;    //gives an error

 

So I only want to be able to change the value of B_red in sensor event code, how do I achieve that?

 

 

Thanks

 

 

 

 

Edited by lego3057
Not completed

Share this post


Link to post
Share on other sites
On 11/21/2019 at 10:26 AM, lego3057 said:

Hello

I´d like some help with C++ variable assignment and reassignment.

In Global code I declare:


publ INT B_red=0;
 

In Sensor event code:


if(B_red==0); //its OK

B_red=1;    //gives an error

 

So I only want to be able to change the value of B_red in sensor event code, how do I achieve that?

is there a reason why you wrote int in caps and you wrote publ instead of public? Did you try it without the public?

Share this post


Link to post
Share on other sites

I think that won't work, the variables in global Code can not be reached?

Use Hub[x].status instead

 

 

 

Share this post


Link to post
Share on other sites

So there is no way you can change the value of a variable, that was declared in global code? Thanks.

 

Share this post


Link to post
Share on other sites

Hello everyone. Does anyone knows a comand to change LED color in the HUB? Not "configure" but a comand. Thanks.

Share this post


Link to post
Share on other sites

Change LED

char-write-cmd 0x0e 0800813200510004

The last two digits (04) are the desired color

 

Share this post


Link to post
Share on other sites
On 12/1/2019 at 8:59 AM, Lok24 said:

Change LED

char-write-cmd 0x0e 0800813200510004

The last two digits (04) are the desired color

 

Soory, i dont know where to put that. I was looking for something like:   Hub[0].setLED (2); but thanks anyway.

Share this post


Link to post
Share on other sites

Hi @nuno2500,

sorry, my fault....

use:

Hub[0].SetLEDColor(Port.Colors.BLUE);
Hub[1].SetLEDColor(Port.Colors.LBLUE);

And here are the colors:

 

Edited by Lok24

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.