Live Communication with Vizard

../../_images/basiliskVizardLogo.png

BSK can link with Vizard live in three ways:

  • liveStream : The BSK sim runs in lockstep with Vizard. This supports user input handling and performs standard optical navigation if cameras are configured.

  • broadcastStream : The BSK sim broadcasts read-only messages in a publish/subscribe pattern, where many Vizards may subscribe simultaneously.

  • noDisplay : The BSK sim performs optical navigation headlessly through Vizard, only sending messages to Vizard when an image is requested. This is a more efficient OpNav mode, but shows no graphical display in Vizard.

Caution

Legacy opNavMode has been deprecated. For opNavMode = 1, use liveStream flag. For opNavMode = 2, use noDisplay flag.

liveStream Mode

During liveStream mode, BSK sends a message containing simulation state information to Vizard at every timestep. BSK then waits for an ‘OK’ response before proceeding. In this way, both BSK and Vizard operate in lockstep with each other. This is the best method for visualizing a scenario live on your local machine.

To enable livestreaming through vizSupport use the liveStream flag:

viz = vizSupport.enableUnityVisualization(scSim, dynTaskName, scObject
                                          , liveStream=True
                                          )

Or, to bypass the vizSupport module:

viz = vizInterface.VizInterface()
viz.liveStream = True

When the liveStream flag is set to True, BSK will also automatically obtain user inputs from Vizard at each timestep, as detailed in the accompanying section.

Note

BSK can only take advantage of 2-way communication during livestream mode, so liveStream must be set to True.

Attaching a “DirectComm” Vizard Instance

Once BSK is configured to livestream, an instance of Vizard can be attached by copying the port address into the “Socket Address” field. Make sure that the “DirectComm” option is selected.

The communication protocol and port number can be changed using:

viz.reqComProtocol = "xxx";
viz.reqComAddress  = "xxx";
viz.reqPortNumber  = "XXXX";

BSK assembles the full liveStream address as:

viz.reqComProtocol + "://" + viz.reqComAddress + ":" + viz.reqPortNumber
Vizard 2-way Communication Parameters

Variable

Type

Default

Description

reqComProtocol

string

tcp

Transport protocol to use for the 2-way connection. See all protocol options here.

reqComAddress

string

localhost

Network address to use for the connection. This can be either a host name or an IP address.

reqPortNumber

string

5556

Port number to use for the connection.

The default 2-way address is therefore tcp://localhost:5556.

Creating VizEventDialog Panels

VizEventDialog panels are displayed in Vizard, and contain choices for a user to select. These panels can be configured to have a prescribed duration and several options for a user to select. The following list shows all VizEventDialog structure variables.

VizEventDialog variables

Variable

Type

Units

Required

Description

eventHandlerID

string

Yes

Name of Vizard event handler to be returned with VizEventReply responses

displayString

string

Yes

Contains the information or choice that should be posed to the user.

userOptions

string[]

No

Array of display strings, one entry for each user choice that will be shown. If this is empty, the dialog is assumed to be informational only. Strings must be unique (cannot display the same option multiple times in a panel).

durationOfDisplay

double

nanoseconds

No

Determines when to close a panel. Default is 0, which leaves the panel on display until closed by user.

useSimElapsedTimeForDuration

bool

No

If true and durationOfDisplay is set, use the sim elapsed time to calculate when to hide window. If false, use real time (system clock). Default is false.

useConfirmationPanel

int

No

-1 to not show a confirmation panel, 0 to use viz default, 1 to require a user confirmation of their selection.

hideOnSelection

int

No

-1 to continue to show panel , 0 to use viz default, 1 to hide panel after user makes a selection, 2 to destroy panel after user makes a selection

dialogFormat

string

No

Select format for dialog box: “WARNING”, “CAUTION”, or none to use viz default format

Here is an example an VizEventDialog panel creation:

powerModePanel = vizInterface.VizEventDialog()
powerModePanel.eventHandlerID = "Power Mode Panel"
powerModePanel.displayString = "Set system power mode:"
powerModePanel.userOptions.append("Nominal")
powerModePanel.userOptions.append("Low-Power")
powerModePanel.useConfirmationPanel = True

viz.vizEventDialogs.append(powerModePanel)

See scenarioBasicOrbitStream for a Basilisk example script that uses Vizard event panels.

Note

The list viz.vizEventDialogs sends current panel requests to Vizard as part of the VizMessage, then clears itself before the next timestep. If information in a panel needs to be modified, the same VizEventDialog instance (with the same eventHandlerID) can be modified and re-appended to viz.vizEventDialogs. This will cause the panel to re-open if minimized, with updated information. If the panel list needs to be manually cleared, this can be done using viz.vizEventDialogs.clear().

Handling User Input

Responses from panels can be used as inputs back to BSK. The key is that the responses must be read from the VizUserInputMsgPayload message at the desired rate.

From Python, this can be achieved by calling scSim.ExecuteSimulation() at the desired input reception rate so that responses can be parsed and used to influence the simulation state.

The required structure resembles the following:

currentTime = 0
inputTimeStep = macros.sec2nano(5) # Read inputs every 5 seconds
...
scSim.InitializeSimulation()
for i in range(int(totalDuration/inputTimeStep)):
    currentTime += inputTimeStep
    scSim.ConfigureStopTime(currentTime)
    scSim.ExecuteSimulation()

    userInputs = viz.userInputMsg.read()
    keyInputs = userInputs.keyboardInput
    eventInputs = userInputs.vizEventReplies

    # Parse "keyInputs" and "eventInputs", modify sim state

The 2-way communication output message, viz.userInputMsg , is an instance of VizUserInputMsgPayload. This message fills like a queue: Vizard collects all inputs that were recorded over the last scSim.ExecuteSimulation call, and hands them all over together.

Caution

Setting a low input frequency (here, represented by inputTimeStep) could lead to build-up of responses, that could logically conflict with one another.

This behavior could also be built into a BSK module, in which case the above code structure would not be needed. However, this module would have to hard-code the mappings for different Vizard response types and their associated BSK actions.

Keyboard Parsing

There are two types of replies that Vizard can send in return. The keyboardInput field of the message contains a string of keyboard characters that have been pressed since the last timestep. Keys will only be recorded if pre-specified. In the example below, listeners are configured for the keys ‘a’, ‘b’, ‘c’, and ‘d’:

viz.settings.keyboardLiveInput = "abcd"

Caution

Note that Vizard has certain keys pre-programmed as hot-keys for menus and scene actions. If a hot-key is selected as a duplicate listener, Vizard will display a warning, and dual-actions may occur.

To parse keyInputs, search the string for characters of interest:

if 'a' in keyInputs:
    # 'a' key action
if 'b' in keyInputs:
    # 'b' key action
...

Panel Response Parsing

Vizard can also return VizEventReply structures, which contain information about selections made within VizEventDialog panels. The following list shows all VizEventReply structure variables.

VizEventReply variables

Variable

Type

Description

eventHandlerID

string

Name provided when setting up the VizEventDialog object

reply

string

Option selected by user

eventHandlerDestroyed

bool

Was the panel closed and destroyed?

To parse eventInputs , loop over the list:

for response in eventInputs:
    eventID = response.eventHandlerID
    eventOption = response.reply

    if eventID == "Power Mode Panel":
        if eventOption == "Low-Power":
            # change mode
    elif eventID == ...

See the scenario scenarioBasicOrbitStream for an implemented 2-way communication example.

broadcastStream Mode

In addition to livestreaming, BSK can broadcast its read-only messages to a secondary port using the broadcastStream flag. This follows a publish/subscribe architecture, which means many subscriber Vizards can hook up to a single BSK instance.

To enable broadcasting use the broadcastStream flag:

viz = vizSupport.enableUnityVisualization(scSim, dynTaskName, scObject
                                          , broadcastStream=True
                                          )

Note

BSK blindly broadcasts to a port, regardless of whether there are subscribers present or not. This means that unlike liveStream mode, BSK will not wait for a Vizard connection to begin executing.

Vizard can also run both liveStream and broadcastStream modes simultaneously:

viz = vizSupport.enableUnityVisualization(scSim, dynTaskName, scObject
                                          , liveStream=True
                                          , broadcastStream=True
                                          )

This configuration behaves the same as a normal livestream (BSK waits for connection to start), after which subscriber Vizards can connect. Subscriber Vizards cannot connect before the publisher Vizard.

Broadcast Synchronization

Using liveStream and broadcastStream modes simultaneously can be useful for teaching/training environments, where an instructor is running BSK locally and interacting with panels in a publisher Vizard, but broadcasting to separate subscriber Vizards run by students/trainees.

The trainer has the option to force certain visual settings to the broadcast:

broadcastStream synced settings

Variable

orbitLinesOn

trueTrajectoryLinesOn

spacecraftCSon

planetCSon

showHillFrame

See BSK Scripting Settings for types and descriptions of these variables.

This option is ON by default, but can be disabled within the menu of the trainer Vizard. Additionally, panel states (instantiation, selection, deletion) will be synchronized with the subscriber Vizard. Choices selected on panels are shown briefly in the subscriber Vizard before closure.

When disabled, the subscriber Vizard will be briefly notified that they have increased autonomy with visual settings. However, no interactions with panels will have any effect on the BSK sim.

Note

Subscriber Vizards are able to move the time slider at the bottom of the window, however panels will not replay.

Attaching a “Receive Only” Vizard Instance

Once BSK is configured to broadcast, an instance of Vizard can be attached by copying the port address into the “Socket Address” box. Make sure that the “Receive Only” option is selected.

The communication protocol and port number can be changed from Python using:

viz.pubComProtocol = "xxx";
viz.pubComAddress  = "xxx";
viz.pubPortNumber  = "XXXX";

BSK assembles the full broadcastStream address as:

viz.pubComProtocol + "://" + viz.pubComAddress + ":" + viz.pubPortNumber
Vizard Broadcast Communication Parameters

Variable

Type

Default

Description

pubComProtocol

string

tcp

Transport protocol to use for the 2-way connection. See all protocol options here.

pubComAddress

string

localhost

Network address to use for the connection. This can be either a host name or an IP address.

pubPortNumber

string

5570

Port number to use for the connection.

The default broadcast address is therefore tcp://localhost:5570.

Note

Although the default TCP ports seemed to be available across our development machines, specific firewall restrictions or other applications may restrict port use. If the port experiences trouble binding, a ZMQ error will be thrown to the terminal and a different port number should be chosen. (Error #19 if port is in use, Error #49 if address:port does not exist.)

In order to broadcast temporarily over a network, a dynamic IP address can be used. With both devices on the same network, set the broadcast address as:

viz.pubComAddress = "XX.XXX.XXX.XX"

Caution

Some networks may block broadcasting. If the broadcast has trouble connecting, check whether the two devices can ping each other across the network. The terminal command is ping XX.XXX.XXX.XX for Mac, or telnet XX.XXX.XXX.XX for Windows and Linux.

If you’re looking to broadcast for longer durations (i.e. more than a few hours), you may need to set up a static IP address. IP addresses are typically assigned dynamically, meaning that they can change unpredictably throughout the day. Setting up a static IP address ensures that the broadcast can be found at the same address consistently.

noDisplay Mode

Vizard can operate headless with a high-performance optical navigation mode, in which it only updates and renders the scene when an image is requested from BSK. This mode does not show a display to the user, which means that it cannot be used in conjunction with liveStream or broadcastStream modes.

To use the noDisplay flag:

viz = vizSupport.enableUnityVisualization(scSim, dynTaskName, scObject
                                      , noDisplay=True
                                      )

Pausing/Exiting a Scenario

In some instances, it is convenient to have the ability to pause a BSK scenario that is connected to Vizard in liveStream mode. We can take advantage of the existing Vizard key listener for this behavior.

It is important to still call the UpdateState() method for the vizInterface module while paused, which allows for the ‘unpause’ response to be acknowledged. Any panel responses or other Vizard inputs will still be received and processed, and will immediately take effect once unpaused.

Additionally, repeatedly resetting the clock_sync module while paused keeps the visualization from trying to ‘catch up’ once unpaused.

See scenarioBasicOrbitStream for an implementation that pauses/unpauses the scenario using the <p> key and cleanly quits the scenario using <z>.