Move to subdirectory
This commit is contained in:
93
lab_ui/client/app/components/connect/connect.html
Normal file
93
lab_ui/client/app/components/connect/connect.html
Normal file
@@ -0,0 +1,93 @@
|
||||
<div class="tab-pane" id="rosbridgeconnection">
|
||||
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body">
|
||||
|
||||
<form class="form-inline" role="form" onsubmit="return validateForm()">
|
||||
<div id="ConnectionIPForm" class="form-group" align="center">
|
||||
<span>
|
||||
<label id="ConnectionIPLabel" class="control-label" for="inputWarning">
|
||||
Connect To:
|
||||
</label>
|
||||
</span>
|
||||
|
||||
<span>
|
||||
<div class="input-group">
|
||||
<input type="text" id="ConnectionIPInput" class="form-control" placeholder="ROS Bridge Master IP" placeholder="No IP Address yet">
|
||||
<span class="input-group-btn">
|
||||
<button id="ConnectionButton" type="button" onclick="ros.attemptConnection()" class="btn btn-primary">
|
||||
Connect
|
||||
<script type="text/javascript">
|
||||
document.getElementById("ConnectionIPInput").value = ros.connectionName;
|
||||
</script>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Predefined ROSBridge Connections
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<button id="localhostButton" type="button" onclick="ros.attemptConnection('ws://localhost:9090')" class="btn btn-primary">
|
||||
localhost
|
||||
<script type="text/javascript">
|
||||
document.getElementById("ConnectionIPInput").value = ros.connectionName;
|
||||
</script>
|
||||
</button>
|
||||
<button id="TitanButton" type="button" onclick="ros.attemptConnection('ws://titan.local:9090')" class="btn btn-primary">
|
||||
Titan
|
||||
<script type="text/javascript">
|
||||
document.getElementById("ConnectionIPInput").value = ros.connectionName;
|
||||
</script>
|
||||
</button>
|
||||
<button id="PhoebeButton" type="button" onclick="ros.attemptConnection('ws://phoebe.local:9090')" class="btn btn-primary">
|
||||
Phoebe
|
||||
<script type="text/javascript">
|
||||
document.getElementById("ConnectionIPInput").value = ros.connectionName;
|
||||
</script>
|
||||
</button>
|
||||
<button id="RheaButton" type="button" onclick="ros.attemptConnection('ws://rhea.local:9090')" class="btn btn-primary">
|
||||
Rhea
|
||||
<script type="text/javascript">
|
||||
document.getElementById("ConnectionIPInput").value = ros.connectionName;
|
||||
</script>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
// Create a connection to the rosbridge WebSocket server.
|
||||
ros.connect(ros.connectionName);
|
||||
</script>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
ROS Topics.
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<div class="col-sm-1" id="ROSTopics">
|
||||
N/A
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
ROS Nodes.
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
|
||||
<div class="col-sm-1" id="ROSNodes">
|
||||
N/A
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
706
lab_ui/client/app/components/coordinator/coordinator.html
Normal file
706
lab_ui/client/app/components/coordinator/coordinator.html
Normal file
@@ -0,0 +1,706 @@
|
||||
|
||||
<div id="coordinator">
|
||||
<div class="col-md-6">
|
||||
<div class="hand-panel hand-panel-left panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<i class="far fa-2x fa-hand-point-left"></i>
|
||||
Left Arm
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="status-bar">
|
||||
<div class="status-container">
|
||||
<div class="safety-monitor panel panel-default panel-horizontal">
|
||||
<div class="panel-heading">
|
||||
Safety Monitor
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="status-list">
|
||||
<ul class="list-group list-group-horizontal">
|
||||
<li id="left_safetyRunning" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Running</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="left_safetyStopped" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Stopped</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-button panel-footer">
|
||||
<button type="button" onclick="triggerService('/left/aescape/mode/activateSafetyController')" class="btn">
|
||||
Activate
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-container">
|
||||
<div class="franka panel panel-default panel-horizontal">
|
||||
<div class="panel-heading">
|
||||
Franka Arm
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="status-list">
|
||||
<ul class="list-group list-group-horizontal">
|
||||
<li id="left_frankaModeOther" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Other</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="left_frankaModeIdle" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Idle</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="left_frankaModeMove" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Move</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="left_frankaModeGuiding" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Guiding</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="left_frankaModeReflex" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Reflex</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="left_frankaModeUserStopped" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>User Stopped</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="left_frankaModeErrorRecovery" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Automatic Error Recovery</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-button panel-footer">
|
||||
<button id="left_fixFrankaButton" type="button" onclick="triggerService('/left/aescape/hardware/resetFrankaError')" class="btn">
|
||||
Fix Errors
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-container">
|
||||
<div class="franka-force force-bar panel panel-default panel-horizontal">
|
||||
<div class="panel-heading">
|
||||
Franka Force
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="status-list">
|
||||
<div class="commanded">
|
||||
<div class="progress">
|
||||
<!-- <div class="progress-bar-label">Commanded</div> -->
|
||||
<div class="progress-bar bg-success" role="progressbar" id="frankaForceCommandedLeft" aria-valuenow="25" aria-valuemin="0" aria-valuemax="200">N/A</div>
|
||||
</div>
|
||||
<ul class="list-group list-group-horizontal text-center">
|
||||
<li class="list-group-item force-value">
|
||||
<h4>X: <span id="frankaForceLeftCommandedX">0.0</span></h4>
|
||||
</li>
|
||||
<li class="list-group-item force-value">
|
||||
<h4>Y: <span id="frankaForceLeftCommandedY">0.0</span></h4>
|
||||
</li>
|
||||
<li class="list-group-item force-value">
|
||||
<h4>Z: <span id="frankaForceLeftCommandedZ">0.0</span></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="observed">
|
||||
<div class="progress">
|
||||
<!-- <div class="progress-bar-label">Observed</div> -->
|
||||
<div class="progress-bar bg-success" role="progressbar" id="frankaForceObservedLeft" aria-valuenow="25" aria-valuemin="0" aria-valuemax="200">
|
||||
<span>N/A</span>
|
||||
<div>
|
||||
<span>Observed</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="list-group list-group-horizontal text-center">
|
||||
<li class="list-group-item force-value">
|
||||
<h4>X: <span id="frankaForceLeftObservedX">0.0</span></h4>
|
||||
</li>
|
||||
<li class="list-group-item force-value">
|
||||
<h4>Y: <span id="frankaForceLeftObservedY">0.0</span></h4>
|
||||
</li>
|
||||
<li class="list-group-item force-value">
|
||||
<h4>Z: <span id="frankaForceLeftObservedZ">0.0</span></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-button panel-footer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-container">
|
||||
<div class="robotiq force-bar panel panel-default panel-horizontal">
|
||||
<div class="panel-heading">
|
||||
Robotiq
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="status-list">
|
||||
<div class="progress" id="robotiqForce">
|
||||
<div class="progress-bar bg-success" role="progressbar" id="robotiqForceBar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="200">N/A</div>
|
||||
</div>
|
||||
<ul class="list-group list-group-horizontal text-center">
|
||||
<li class="list-group-item force-value">
|
||||
<h4>X: <span id="robotiqX">0.0</span></h4>
|
||||
</li>
|
||||
<li class="list-group-item force-value">
|
||||
<h4>Y: <span id="robotiqY">0.0</span></h4>
|
||||
</li>
|
||||
<li class="list-group-item force-value">
|
||||
<h4>Z: <span id="robotiqZ">0.0</span></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-button panel-footer">
|
||||
<button id="calibrateButton" type="button" onclick="triggerService('/left/aescape/hardware/calibrateRobotiq')" class="btn">
|
||||
Calibrate
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-container col-md-6">
|
||||
<div class="control-card panel panel-default">
|
||||
<div class="panel-heading">
|
||||
EEF Configuration
|
||||
<i class="fas fa-info-circle" tabindex="0" data-toggle="popover" data-trigger="focus" data-content="This selects the end-effector attached to the left arm."></i>
|
||||
</div>
|
||||
|
||||
<div class="panel-body text-center">
|
||||
<div class="button-area">
|
||||
<button type="button" onclick="setEEFConfig('left', 'teach')" active class="btn btn-primary col-md-6">
|
||||
Recording EEF
|
||||
</button>
|
||||
<button type="button" onclick="setEEFConfig('left', 'play')" class="btn btn-primary col-md-6">
|
||||
Massage EEF
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-area panel-footer">
|
||||
<div class="message">
|
||||
<!--You must be in "Stopped Mode" to change the EEF configuration! -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-container col-md-6">
|
||||
<div id="left-operation-mode" class="control-card-six control-card panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Operation Mode
|
||||
<i class="fas fa-info-circle" tabindex="0" data-toggle="popover" data-trigger="focus" data-content="This selects the operation mode of the left arm."></i>
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="button-area">
|
||||
<button id="left_teachingModeButton" type="button" onclick="triggerService('/left/aescape/mode/activateTeachingController')" class="btn btn-primary col-md-4">
|
||||
Teaching
|
||||
</button>
|
||||
<button id="left_executionModeButton" type="button" onclick="triggerService('/left/aescape/mode/activateExecutionController')" class="btn btn-primary col-md-4">
|
||||
Massage
|
||||
</button>
|
||||
<button id="left_readyModeButton" type="button" onclick="triggerService('/left/aescape/mode/activateReadyController')" class="btn btn-primary col-md-4">
|
||||
Ready
|
||||
</button>
|
||||
<button id="left_standbyModeButton" type="button" onclick="triggerService('/left/aescape/mode/activateStandbyController')" class="btn btn-primary col-md-4">
|
||||
Standby
|
||||
</button>
|
||||
<button id="left_stoppedModeButton" type="button" onclick="triggerService('/left/aescape/mode/stopControllers')" class="btn btn-primary col-md-4">
|
||||
Stopped
|
||||
</button>
|
||||
</div>
|
||||
<!--
|
||||
<div class="col-md-6">
|
||||
Safety Monitor Status:
|
||||
<div class="row-md-3">
|
||||
<h4><span id="left_safetyRunning" class="label label-default">Running</span></h4>
|
||||
</div>
|
||||
<div class="row-md-3">
|
||||
<h4><span id="left_safetyStopped" class="label label-default">Stopped</span></h4>
|
||||
</div>
|
||||
<div class="row-md-3">
|
||||
<button type="button" onclick="triggerService('/left/aescape/mode/activateSafetyController')" class="btn btn-sm">
|
||||
Activate Safety Monitor
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
<div class="action-area panel-footer">
|
||||
<div class="message">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="control-container col-md-6">
|
||||
<div class="control-card panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Robotiq
|
||||
<i class="fas fa-info-circle"></i>
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="progress" id="robotiqForce">
|
||||
<div class="progress-bar bg-success" role="progressbar" id="robotiqForceBar" aria-valuenow="25" aria-valuemin="0" aria-valuemax="200">N/A</div>
|
||||
</div>
|
||||
<div class="button-area">
|
||||
Current Robotiq Values:
|
||||
<h4>X: <span id="robotiqX" class="label label-default">0.0</span></h4>
|
||||
<h4>Y: <span id="robotiqY" class="label label-default">0.0</span></h4>
|
||||
<h4>Z: <span id="robotiqZ" class="label label-default">0.0</span></h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-area panel-footer">
|
||||
<div class="button">
|
||||
<button id="calibrateButton" type="button" onclick="triggerService('/left/aescape/hardware/calibrateRobotiq')" class="btn btn-primary">
|
||||
Calibrate Robotiq
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
<div class="control-container teaching-mode-operations col-md-7">
|
||||
<div class="control-card panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Teaching Mode Operations
|
||||
<i class="fas fa-info-circle" tabindex="0" data-toggle="popover" data-trigger="focus" data-content="This helps recoding a new massage!"></i>
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="button-area">
|
||||
<button id="recordingStartButton" type="button" onclick="startTeachRecoding()" class="btn btn-primary col-md-6">
|
||||
Start Recording
|
||||
</button>
|
||||
<button id="recordingStopButton" type="button" onclick="stopTeachRecording()" class="btn btn-primary col-md-6">
|
||||
Stop Recording
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-area panel-footer">
|
||||
<div id="RecordingStatusLabel" class="message">
|
||||
<!-- TO DO: Show errors in bag manager -->
|
||||
</div>
|
||||
<div class="slider-options tagging-options" id="teachTags">
|
||||
<div class="col-md-10">
|
||||
<!--full with naming box search:no new:yes-->
|
||||
<select id="teachBagFileName" placeholder="Filename"></select>
|
||||
<!--full width category box search:yes new:yes-->
|
||||
<select id="teachBagCategory" placeholder="Category"></select>
|
||||
<!--full width tags box search:yes new:yes-->
|
||||
<select id="teachBagTags" placeholder="Tags"></select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button class="btn btn-primary" onclick="hideTaggingOptions('teach', true)">Tag</button>
|
||||
<button class="btn btn-primary" onclick="hideTaggingOptions('teach', false)">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="teachTagError" class="col-md-10 error"></div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-container play-mode-operations col-md-10">
|
||||
<div class="control-card panel panel-default execution-control">
|
||||
<div class="panel-heading">
|
||||
Play Mode Operations
|
||||
<i class="fas fa-info-circle" tabindex="0" data-toggle="popover" data-trigger="focus" data-content="This helps selecting and playback of recorded massages!"></i>
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="button-area">
|
||||
<button id="executionLoadButton" type="button" onclick="displayLoadingOptions()" class="btn btn-primary col-md-3">
|
||||
Load Recording
|
||||
</button>
|
||||
<button id="executionLoadButton" type="button" onclick="triggerService('/aescape/massageReady')" class="btn btn-primary col-md-3">
|
||||
Complete Body Scaling
|
||||
</button>
|
||||
<button id="executionStartButton" type="button" onclick="playLoadedRecording()" class="btn btn-primary col-md-3">
|
||||
Play Loaded Recording
|
||||
</button>
|
||||
<button id="executionStopButton" type="button" onclick="stopPlayingRecording()" class="btn btn-primary col-md-3">
|
||||
Stop Playing Recording
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<!-- <div class="row-md-4">
|
||||
<<div class="col-md-3"> -->
|
||||
<!-- Bagfile name must not start with "/"
|
||||
<button class="btn btn-primary" type="button" onclick="updateRecordingsList()">
|
||||
Refresh List
|
||||
</button>
|
||||
</div> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-area panel-footer">
|
||||
<div class="message" id="ExecutionStatusLabel">
|
||||
<!-- TO DO: Show errors in bag manager -->
|
||||
</div>
|
||||
<!-- TO DO: Bagfile name must not start with "/" -->
|
||||
<div class="slider-options tagging-options" id="playTags">
|
||||
<div class="col-md-10">
|
||||
<!--full with naming box search:no new:yes-->
|
||||
<select id="playBagFileName" placeholder="Filename"></select>
|
||||
<!--full width category box search:yes new:yes-->
|
||||
<select id="playBagCategory" placeholder="Category"></select>
|
||||
<!--full width tags box search:yes new:yes-->
|
||||
<select id="playBagTags" placeholder="Tags"></select>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<button class="btn btn-primary" onclick="hideTaggingOptions('play', true)">Tag</button>
|
||||
<button class="btn btn-primary" onclick="hideTaggingOptions('play', false)">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="slider-options loading-options" id="loadBags">
|
||||
<div class="col-md-10">
|
||||
<div class="dropdown">
|
||||
<div>
|
||||
<select id="loadBagList" placeholder="Select bag to play"></select>
|
||||
<select id="armMode"></select>
|
||||
</div>
|
||||
<!-- <i class="fas fa-sync-alt" onclick="updateRecordingsList()"></i> -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-2">
|
||||
<!-- <i class="fas fa-check-circle" onclick="hideLoadingOptions(true)"></i> -->
|
||||
<button class="btn btn-primary" onclick="hideLoadingOptions(true)">Load</button>
|
||||
<button class="btn btn-primary" onclick="hideLoadingOptions(false)">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="playTagError" class="col-md-10 error"></div>
|
||||
<div class="clearfix"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="hand-panel hand-panel-right panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Right Arm
|
||||
<i class="far fa-2x fa-hand-point-right"></i>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="status-bar">
|
||||
<div class="status-container">
|
||||
<div class="safety-monitor panel panel-default panel-horizontal">
|
||||
<div class="panel-heading">
|
||||
Safety Monitor
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="status-list">
|
||||
<ul class="list-group list-group-horizontal">
|
||||
<li id="right_safetyRunning" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Running</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="right_safetyStopped" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Stopped</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-button panel-footer">
|
||||
<button type="button" onclick="triggerService('/left/aescape/mode/activateSafetyController')" class="btn">
|
||||
Activate
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-container">
|
||||
<div class="franka panel panel-default panel-horizontal">
|
||||
<div class="panel-heading">
|
||||
Franka Arm
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="status-list">
|
||||
<ul class="list-group list-group-horizontal">
|
||||
<li id="right_frankaModeOther" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Other</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="right_frankaModeIdle" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Idle</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="right_frankaModeMove" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Move</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="right_frankaModeGuiding" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Guiding</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="right_frankaModeReflex" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Reflex</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="right_frankaModeUserStopped" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>User Stopped</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
<li id="right_frankaModeErrorRecovery" class="list-group-item">
|
||||
<div class="pretty p-default p-round">
|
||||
<input type="checkbox" class="disabled"/>
|
||||
<div class="state p-success-o">
|
||||
<label>Automatic Error Recovery</label>
|
||||
</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="action-button panel-footer">
|
||||
<button id="right_fixFrankaButton" type="button" onclick="triggerService('/right/aescape/hardware/resetFrankaError')" class="btn">
|
||||
Fix Errors
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="status-container">
|
||||
<div class="franka-force force-bar panel panel-default panel-horizontal">
|
||||
<div class="panel-heading">
|
||||
Franka Force
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="status-list">
|
||||
<div class="commanded">
|
||||
<div class="progress">
|
||||
<!-- <div class="progress-bar-label">Commanded</div> -->
|
||||
<div class="progress-bar bg-success" role="progressbar" id="frankaForceCommandedRight" aria-valuenow="25" aria-valuemin="0" aria-valuemax="200">N/A</div>
|
||||
</div>
|
||||
<ul class="list-group list-group-horizontal text-center">
|
||||
<li class="list-group-item force-value">
|
||||
<h4>X: <span id="frankaForceRightCommandedX">0.0</span></h4>
|
||||
</li>
|
||||
<li class="list-group-item force-value">
|
||||
<h4>Y: <span id="frankaForceRightCommandedY">0.0</span></h4>
|
||||
</li>
|
||||
<li class="list-group-item force-value">
|
||||
<h4>Z: <span id="frankaForceRightCommandedZ">0.0</span></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="observed">
|
||||
<div class="progress">
|
||||
<!-- <div class="progress-bar-label">Observed</div> -->
|
||||
<div class="progress-bar bg-success" role="progressbar" id="frankaForceObservedRight" aria-valuenow="25" aria-valuemin="0" aria-valuemax="200">
|
||||
<span>N/A</span>
|
||||
<div>
|
||||
<span>Observed</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="list-group list-group-horizontal text-center">
|
||||
<li class="list-group-item force-value">
|
||||
<h4>X: <span id="frankaForceRightObservedX">0.0</span></h4>
|
||||
</li>
|
||||
<li class="list-group-item force-value">
|
||||
<h4>Y: <span id="frankaForceRightObservedY">0.0</span></h4>
|
||||
</li>
|
||||
<li class="list-group-item force-value">
|
||||
<h4>Z: <span id="frankaForceRightObservedZ">0.0</span></h4>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-button panel-footer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="control-container col-md-6">
|
||||
<div class="control-card panel panel-default">
|
||||
<div class="panel-heading">
|
||||
EEF Configuration
|
||||
<i class="fas fa-info-circle" tabindex="0" data-toggle="popover" data-trigger="focus" data-content="This selects the end-effector attached to the right arm."></i>
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="button-area">
|
||||
<button type="button" onclick="setEEFConfig('right', 'teach')" class="btn btn-primary col-md-6">
|
||||
Recording EEF
|
||||
</button>
|
||||
<button type="button" onclick="setEEFConfig('right', 'play')" class="btn btn-primary col-md-6">
|
||||
Massage EEF
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-area panel-footer">
|
||||
<div class="message">
|
||||
<!--You must be in "Stopped Mode" to change the EEF configuration! -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="control-container col-md-6">
|
||||
<div id="right-operation-mode" class="control-card-six control-card panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Operation Mode
|
||||
<i class="fas fa-info-circle" tabindex="0" data-toggle="popover" data-trigger="focus" data-placement="bottom" data-content="This selects the operation mode of the right arm."></i>
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="button-area">
|
||||
<button id="right_teachingModeButton" type="button" onclick="triggerService('/right/aescape/mode/activateTeachingController')" class="btn btn-primary col-md-4">
|
||||
Teaching
|
||||
</button>
|
||||
<button id="right_executionModeButton" type="button" onclick="triggerService('/right/aescape/mode/activateExecutionController')" class="btn btn-primary col-md-4">
|
||||
Massage
|
||||
</button>
|
||||
<button id="right_readyModeButton" type="button" onclick="triggerService('/right/aescape/mode/activateReadyController')" class="btn btn-primary col-md-4">
|
||||
Ready
|
||||
</button>
|
||||
<button id="right_standbyModeButton" type="button" onclick="triggerService('/right/aescape/mode/activateStandbyController')" class="btn btn-primary col-md-4">
|
||||
Standby
|
||||
</button>
|
||||
<button id="right_stoppedModeButton" type="button" onclick="triggerService('/right/aescape/mode/stopControllers')" class="btn btn-primary col-md-4">
|
||||
Stopped
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="action-area panel-footer">
|
||||
<div class="message">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- <div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Robotiq
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<div class="col-md-4">
|
||||
Current Robotiq Values:
|
||||
<div class="row-md-3">
|
||||
<h4>X: <span id="robotiqX" class="label label-default">0.0</span></h4>
|
||||
</div>
|
||||
<div class="row-md-3">
|
||||
<h4>Y: <span id="robotiqY" class="label label-default">0.0</span></h4>
|
||||
</div>
|
||||
<div class="row-md-3">
|
||||
<h4>Z: <span id="robotiqZ" class="label label-default">0.0</span></h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row-md-3">
|
||||
<button id="calibrateButton" type="button" onclick="triggerService('/right/aescape/hardware/calibrateRobotiq')" class="btn btn-primary">
|
||||
Calibrate Robotiq
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div> -->
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<button type="button" onclick="triggerService('/aescape/safety_activate')" class="safety-button danger btn">
|
||||
Stop Now!
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<!-- <div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Execution Recording Operations
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<button id="executionStartButton" type="button" onclick="triggerService('/startExecutionRecording')" class="btn btn-primary">
|
||||
Start Recording Execution
|
||||
</button>
|
||||
<button id="executionRecordingStopButton" type="button" onclick="triggerService('/stopExecutionRecording')" class="btn btn-primary">
|
||||
Stop Recording Execution
|
||||
</button>
|
||||
</div>
|
||||
</div> -->
|
||||
661
lab_ui/client/app/components/coordinator/js/ros_scripts.js
Normal file
661
lab_ui/client/app/components/coordinator/js/ros_scripts.js
Normal file
@@ -0,0 +1,661 @@
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Publishers
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
function triggerTopic(topicName)
|
||||
{
|
||||
var topic = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : topicName,
|
||||
messageType : 'std_msgs/Empty'
|
||||
});
|
||||
|
||||
var msg = new ROSLIB.Message({});
|
||||
|
||||
topic.publish(msg);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Topics
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Subscribers
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class ArmControls
|
||||
{
|
||||
constructor(namespace) {
|
||||
this.namespace = namespace;
|
||||
|
||||
// Franka Status
|
||||
this.frankaStatusTopic = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/'+this.namespace+'/franka_state_controller/franka_states',
|
||||
messageType : 'franka_msgs/FrankaState',
|
||||
throttle_rate : 500 // 2Hz
|
||||
});
|
||||
this.frankaStatusTopic.subscribe(this.frankaStatus.bind(this));
|
||||
|
||||
// Mode Status
|
||||
this.modeStatusTopic = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/'+this.namespace+'/aescape/mode/status',
|
||||
messageType : 'std_msgs/String',
|
||||
throttle_rate : 500 // 2Hz
|
||||
});
|
||||
this.modeStatusTopic.subscribe(this.modeStatus.bind(this));
|
||||
|
||||
// Safety Status
|
||||
this.safetyStatusTopic = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/'+this.namespace+'/aescape/mode/safety_status',
|
||||
messageType : 'std_msgs/String',
|
||||
throttle_rate : 500 // 2Hz
|
||||
});
|
||||
this.safetyStatusTopic.subscribe(this.safetyStatus.bind(this));
|
||||
|
||||
this.frankaForceObservedTopic = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/'+this.namespace+'/franka_state_controller/F_ext_base',
|
||||
messageType : 'geometry_msgs/WrenchStamped',
|
||||
throttle_rate : 500 // 2Hz
|
||||
});
|
||||
|
||||
this.frankaForceObservedTopic.subscribe(this.frankaForce.bind(this, 'observed'));
|
||||
|
||||
this.frankaForceCommandedTopic = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/'+this.namespace+'/robot_goal',
|
||||
messageType : 'aescape_control/RobotGoal',
|
||||
throttle_rate : 500 // 2Hz
|
||||
});
|
||||
|
||||
this.frankaForceCommandedTopic.subscribe(this.frankaForce.bind(this, 'commanded'));
|
||||
|
||||
this.lastActiveButton = {
|
||||
safetyMode : null,
|
||||
frankaMode : null,
|
||||
operationMode : null,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Operation Mode
|
||||
modeStatus(message) {
|
||||
var operationModeToButtonMap = {
|
||||
"stopped" : "stoppedModeButton",
|
||||
"standby" : "standbyModeButton",
|
||||
"teach" : "teachingModeButton",
|
||||
"execution" : "executionModeButton",
|
||||
"ready" : "readyModeButton"
|
||||
}
|
||||
|
||||
if (this.namespace == "left")
|
||||
{
|
||||
document.getElementById("recordingStartButton").disabled = true
|
||||
document.getElementById("executionStartButton").disabled = true
|
||||
}
|
||||
|
||||
if (message.data == "ready")
|
||||
{
|
||||
if (this.namespace == "left")
|
||||
{
|
||||
document.getElementById("recordingStartButton").disabled = false
|
||||
document.getElementById("executionStartButton").disabled = false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
var operationModeLastActive = this.lastActiveButton.operationMode;
|
||||
|
||||
if(operationModeLastActive && operationModeLastActive != message.data) {
|
||||
var operationModeButton = operationModeToButtonMap[operationModeLastActive];
|
||||
if (operationModeButton) {
|
||||
document.getElementById(this.namespace+"_"+operationModeButton).classList.remove("active");
|
||||
}
|
||||
}
|
||||
|
||||
var operationModeButton = operationModeToButtonMap[message.data];
|
||||
if (operationModeButton) {
|
||||
document.getElementById(this.namespace+"_"+operationModeButton).classList.add('active');
|
||||
}
|
||||
|
||||
this.lastActiveButton.operationMode = message.data;
|
||||
|
||||
}
|
||||
|
||||
// FrankaState
|
||||
frankaStatus(message) {
|
||||
var frankaModeToButtonMap = {
|
||||
0 : "frankaModeOther",
|
||||
1 : "frankaModeIdle",
|
||||
2 : "frankaModeMove",
|
||||
3 : "frankaModeGuiding",
|
||||
4 : "frankaModeReflex",
|
||||
5 : "frankaModeUserStopped",
|
||||
6 : "frankaModeErrorRecovery"
|
||||
}
|
||||
|
||||
var frankaModeLastActive = this.lastActiveButton.frankaMode;
|
||||
|
||||
if(frankaModeLastActive && frankaModeLastActive != message.robot_mode) {
|
||||
var frankaButton = frankaModeToButtonMap[frankaModeLastActive];
|
||||
if (frankaButton) {
|
||||
document.getElementById(this.namespace+"_"+frankaButton).getElementsByTagName("input")[0].checked = false;
|
||||
document.getElementById(this.namespace+"_"+frankaButton).getElementsByTagName("input")[0].disabled = true;
|
||||
}
|
||||
}
|
||||
var frankaButton = frankaModeToButtonMap[message.robot_mode];
|
||||
if (frankaButton) {
|
||||
document.getElementById(this.namespace+"_"+frankaButton).getElementsByTagName("input")[0].disabled = false;
|
||||
document.getElementById(this.namespace+"_"+frankaButton).getElementsByTagName("input")[0].checked = true;
|
||||
}
|
||||
|
||||
if(message.robot_mode == 0 || message.robot_mode == 4) {
|
||||
document.getElementById(this.namespace+"_"+"fixFrankaButton").classList.add("danger");
|
||||
} else {
|
||||
document.getElementById(this.namespace+"_"+"fixFrankaButton").classList.remove("danger");
|
||||
}
|
||||
|
||||
//if(message.robot_mode == 1) {
|
||||
// document.getElementById(this.namespace+"_"+"fixFrankaButton").classList.add("warning");
|
||||
//} else {
|
||||
// document.getElementById(this.namespace+"_"+"fixFrankaButton").classList.remove("warning");
|
||||
//}
|
||||
|
||||
this.lastActiveButton.frankaMode = message.robot_mode;
|
||||
}
|
||||
|
||||
|
||||
safetyStatus(message) {
|
||||
var safetyStatusToButtonMap = {
|
||||
"stopped" : "safetyStopped",
|
||||
"running" : "safetyRunning"
|
||||
}
|
||||
|
||||
var safetyButtonLastActive = this.lastActiveButton.safetyMode;
|
||||
|
||||
if(safetyButtonLastActive && safetyButtonLastActive != message.data) {
|
||||
var safetyButton = safetyStatusToButtonMap[safetyButtonLastActive];
|
||||
if(safetyButton) {
|
||||
document.getElementById(this.namespace+"_"+safetyButton).getElementsByTagName("input")[0].checked = false;
|
||||
document.getElementById(this.namespace+"_"+safetyButton).getElementsByTagName("input")[0].disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
var safetyButton = safetyStatusToButtonMap[message.data];
|
||||
if(safetyButton) {
|
||||
document.getElementById(this.namespace+"_"+safetyButton).getElementsByTagName("input")[0].disabled = false;
|
||||
document.getElementById(this.namespace+"_"+safetyButton).getElementsByTagName("input")[0].checked = true;
|
||||
}
|
||||
|
||||
this.lastActiveButton.safetyMode = message.data;
|
||||
}
|
||||
|
||||
frankaForce(forceTypeCode, message) {
|
||||
if(this.namespace == 'left') {
|
||||
var bindedArm = "Left";
|
||||
}
|
||||
if(this.namespace == 'right') {
|
||||
var bindedArm = "Right";
|
||||
}
|
||||
if (forceTypeCode == 'observed') {
|
||||
var forceType = "Observed";
|
||||
}
|
||||
if (forceTypeCode == 'commanded') {
|
||||
var forceType = "Commanded";
|
||||
}
|
||||
|
||||
// if(this.namespace == 'right' && forceTypeCode == 'commanded') {
|
||||
// console.log("frankaForce");
|
||||
// console.log(message)
|
||||
// }
|
||||
|
||||
var force = message.wrench.force
|
||||
|
||||
document.getElementById("frankaForce" + bindedArm + forceType + "X").innerHTML = force.x.toFixed(1)
|
||||
document.getElementById("frankaForce" + bindedArm + forceType + "Y").innerHTML = force.y.toFixed(1)
|
||||
document.getElementById("frankaForce" + bindedArm + forceType + "Z").innerHTML = force.z.toFixed(1)
|
||||
|
||||
var totalForce = math.norm([force.x, force.y, force.z]).toFixed(1)
|
||||
var totalForcePercent = totalForce/2
|
||||
|
||||
var doc = document.getElementById("frankaForce" + forceType + bindedArm);
|
||||
doc.style.width = totalForcePercent + "%";
|
||||
doc.innerHTML = totalForce + " N";
|
||||
doc.setAttribute('aria-valuenow', totalForce);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
var leftArmControls = new ArmControls('left');
|
||||
var rightArmControls = new ArmControls('right');
|
||||
|
||||
var lastActiveButton = {
|
||||
teachingMode : null,
|
||||
executionMode : null
|
||||
}
|
||||
|
||||
// Robotiq Data
|
||||
var robotiqDataTopic = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/left/monitor/eef_wrench',
|
||||
messageType : 'geometry_msgs/WrenchStamped',
|
||||
throttle_rate : 500 // 2Hz
|
||||
});
|
||||
|
||||
robotiqDataTopic.subscribe(function(message) {
|
||||
var force = message.wrench.force
|
||||
document.getElementById("robotiqX").innerHTML = force.x.toFixed(1)
|
||||
document.getElementById("robotiqY").innerHTML = force.y.toFixed(1)
|
||||
document.getElementById("robotiqZ").innerHTML = force.z.toFixed(1)
|
||||
|
||||
var totalForce = math.norm([force.x, force.y, force.z]).toFixed(1)
|
||||
var totalForcePercent = totalForce/2
|
||||
|
||||
doc = document.getElementById("robotiqForceBar");
|
||||
doc.style.width = totalForcePercent + "%";
|
||||
doc.innerHTML = totalForce + " N";
|
||||
doc.setAttribute('aria-valuenow', totalForce);
|
||||
|
||||
|
||||
if ((Math.abs(force.x) > 0.5) || (Math.abs(force.y) > 0.5) || (Math.abs(force.z) > 0.5))
|
||||
{
|
||||
//consider adding warning buttons
|
||||
} else {
|
||||
//document.getElementById("calibrateButton").disabled = true;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Recording bag
|
||||
var recordingBagTopic = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/aescape/bags/recording_status',
|
||||
messageType : 'std_msgs/String'
|
||||
});
|
||||
|
||||
recordingBagTopic.subscribe(function(message) {
|
||||
if (message.data == "stopped")
|
||||
{
|
||||
//document.getElementById("RecordingStatusLabel").innerHTML = 'Not Running';
|
||||
}
|
||||
else if (message.data == "running")
|
||||
{
|
||||
//document.getElementById("RecordingStatusLabel").innerHTML = 'Running!';
|
||||
}
|
||||
|
||||
var teachingModeToButtonMap = {
|
||||
"stopped" : "recordingStopButton",
|
||||
"running" : "recordingStartButton"
|
||||
}
|
||||
|
||||
var teachingModeLastActive = lastActiveButton.teachingMode;
|
||||
|
||||
//status changed
|
||||
if(teachingModeLastActive && teachingModeLastActive != message.data) {
|
||||
var teachingModeButton = teachingModeToButtonMap[teachingModeLastActive];
|
||||
if (teachingModeButton) {
|
||||
document.getElementById(teachingModeButton).classList.remove("active");
|
||||
}
|
||||
if(message.data == 'stopped') {
|
||||
triggerService('/left/aescape/mode/activateReadyController');
|
||||
triggerService('/right/aescape/mode/activateReadyController');
|
||||
displayTaggingOptions('teach');
|
||||
}
|
||||
}
|
||||
|
||||
var teachingModeButton = teachingModeToButtonMap[message.data];
|
||||
if (teachingModeButton) {
|
||||
document.getElementById(teachingModeButton).classList.add("active");
|
||||
}
|
||||
|
||||
lastActiveButton.teachingMode = message.data;
|
||||
});
|
||||
|
||||
|
||||
// Execution bag
|
||||
// Use playback status instead of this
|
||||
var executingBagTopic = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/aescape/bags/execution_status',
|
||||
messageType : 'std_msgs/String'
|
||||
});
|
||||
|
||||
executingBagTopic.subscribe(function(message) {
|
||||
if (message.data == "stopped")
|
||||
{
|
||||
//document.getElementById("ExecutionStatusLabel").innerHTML = 'Not Running';
|
||||
}
|
||||
else if (message.data == "running")
|
||||
{
|
||||
//document.getElementById("ExecutionStatusLabel").innerHTML = 'RUNNING!';
|
||||
}
|
||||
var executionModeToButtonMap = {
|
||||
"stopped" : "executionStopButton",
|
||||
"running" : "executionStartButton"
|
||||
}
|
||||
|
||||
var executionModeLastActive = lastActiveButton.executionMode;
|
||||
|
||||
if(executionModeLastActive && executionModeLastActive != message.data) {
|
||||
var executionModeButton = executionModeToButtonMap[executionModeLastActive];
|
||||
if (executionModeButton) {
|
||||
document.getElementById(executionModeButton).classList.remove("active");
|
||||
}
|
||||
}
|
||||
|
||||
var executionModeButton = executionModeToButtonMap[message.data];
|
||||
if (executionModeButton) {
|
||||
document.getElementById(executionModeButton).classList.add("active");
|
||||
}
|
||||
|
||||
lastActiveButton.executionMode = message.data;
|
||||
});
|
||||
|
||||
|
||||
// Playback status
|
||||
var lastPlaybackStatus;
|
||||
var lastStatusBag;
|
||||
var playbackStatus = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/left/playback/status',
|
||||
messageType : 'std_msgs/String'
|
||||
});
|
||||
|
||||
playbackStatus.subscribe(function(message) {
|
||||
message = JSON.parse(message.data);
|
||||
console.log("message");
|
||||
console.log(message);
|
||||
status = message.status;
|
||||
bagName = message.bag_file;
|
||||
if (true) {
|
||||
|
||||
if (status === "playing") {
|
||||
|
||||
} else if (status === "stopped") {
|
||||
triggerService('/aescape/bags/stopPlayingBag');
|
||||
triggerService('/left/aescape/mode/activateReadyController');
|
||||
triggerService('/right/aescape/mode/activateReadyController');
|
||||
displayTaggingOptions('play');
|
||||
} else if (status === "loaded") {
|
||||
enableUI();
|
||||
triggerService('/left/aescape/mode/activateReadyController');
|
||||
triggerService('/right/aescape/mode/activateReadyController');
|
||||
displayMessage(true, "Loaded the selected bag file!")
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
// Last played bag
|
||||
var lastPlayedBag = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/aescape/bags/last_played',
|
||||
messageType : 'std_msgs/String'
|
||||
});
|
||||
|
||||
lastPlayedBag.subscribe(function(message) {
|
||||
//document.getElementById("lastbagText").innerHTML = message.data
|
||||
console.log("Last played bag");
|
||||
console.log(message);
|
||||
});
|
||||
|
||||
|
||||
//Last recorded bag
|
||||
var lastRecordedBag = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/aescape/bags/last_recorded',
|
||||
messageType : 'std_msgs/String'
|
||||
});
|
||||
|
||||
lastRecordedBag.subscribe(function(message) {
|
||||
//document.getElementById("lastbagText").innerHTML = message.data
|
||||
console.log("Last recorded bag");
|
||||
console.log(message);
|
||||
});
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Services
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
function triggerService(serviceName, toSend, callback) {
|
||||
|
||||
disableUI();
|
||||
|
||||
var callback = callback || $.noop;
|
||||
|
||||
if(!toSend) {
|
||||
serviceType = 'std_srvs/demobot.Trigger'
|
||||
} else {
|
||||
serviceType = 'std_srvs/demobot.TriggerMessage'
|
||||
}
|
||||
|
||||
var service = new ROSLIB.Service({
|
||||
ros : ros,
|
||||
name : serviceName,
|
||||
serviceType : serviceType,
|
||||
});
|
||||
|
||||
if(!toSend) {
|
||||
var request = new ROSLIB.ServiceRequest({});
|
||||
} else {
|
||||
var toSend = JSON.stringify(toSend);
|
||||
var request = new ROSLIB.ServiceRequest({message : toSend});
|
||||
}
|
||||
|
||||
/*
|
||||
var service = new ROSLIB.Service({
|
||||
ros : ros,
|
||||
name : serviceName,
|
||||
serviceType : 'std_srvs/demobot.TriggerMessage'
|
||||
});
|
||||
|
||||
if(toSend) {
|
||||
toSend = JSON.stringify(toSend)
|
||||
} else {
|
||||
toSend = ""
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
//var request = new ROSLIB.ServiceRequest({message : toSend});
|
||||
|
||||
|
||||
var serviceCallTimeStamp = Date.now();
|
||||
var serviceCallReturned = false;
|
||||
service.callService(request, function(result) {
|
||||
serviceCallReturned = true;
|
||||
if(result.success == true) {
|
||||
$(document).ready(function(){
|
||||
$.notify({
|
||||
message: "Going good! "+ serviceName
|
||||
}, {
|
||||
"placement" : {
|
||||
from: "bottom",
|
||||
align: "right"
|
||||
},
|
||||
type: 'success',
|
||||
delay: 1000
|
||||
});
|
||||
});
|
||||
enableUI();
|
||||
return callback(null, {success : true});
|
||||
} else {
|
||||
$(document).ready(function(){
|
||||
$.notify({
|
||||
message: "Something went wrong :( " + serviceName
|
||||
}, {
|
||||
"placement" : {
|
||||
from: "bottom",
|
||||
align: "right"
|
||||
},
|
||||
type: 'danger',
|
||||
delay: 1000
|
||||
});
|
||||
});
|
||||
enableUI();
|
||||
return callback("Something went wrong :( " + serviceName, {success : false});
|
||||
}
|
||||
}, function(error){
|
||||
$(document).ready(function(){
|
||||
serviceCallReturned = true;
|
||||
$.notify({
|
||||
message: "Something went wrong :( " + serviceName
|
||||
}, {
|
||||
"placement" : {
|
||||
from: "bottom",
|
||||
align: "right"
|
||||
},
|
||||
type: 'danger',
|
||||
delay: 1000
|
||||
});
|
||||
});
|
||||
enableUI();
|
||||
return callback("Something went wrong :( " + serviceName, {success : false})
|
||||
});
|
||||
var responseCheckInterval = setInterval(function() {
|
||||
var timeElapsedSinceServiceCall = Date.now() - serviceCallTimeStamp; // milliseconds elapsed since start
|
||||
if(serviceCallReturned) {
|
||||
clearInterval(responseCheckInterval);
|
||||
return;
|
||||
} else if (timeElapsedSinceServiceCall > 3000){
|
||||
$(document).ready(function(){
|
||||
$.notify({
|
||||
message: "Timeout on " + serviceName
|
||||
}, {
|
||||
"placement" : {
|
||||
from: "bottom",
|
||||
align: "right"
|
||||
},
|
||||
type: 'danger',
|
||||
delay: 1000
|
||||
});
|
||||
});
|
||||
clearInterval(responseCheckInterval);
|
||||
enableUI();
|
||||
return;
|
||||
}
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
|
||||
//document.addEventListener("keydown", invokeSafetyController);
|
||||
function invokeSafetyController(event)
|
||||
{
|
||||
var keyID = event.keyCode;
|
||||
//8 == backspace, 46 == delete
|
||||
if(keyID == 46) {
|
||||
triggerService('/aescape/safety_activate');
|
||||
}
|
||||
}
|
||||
|
||||
function setEEFConfig(arm, config) {
|
||||
var operationModeSelector = '#' + arm + '-operation-mode';
|
||||
document.querySelectorAll(operationModeSelector + ' button').forEach(function(element){
|
||||
element.classList.add('disabled')
|
||||
})
|
||||
var serviceMap = {
|
||||
teach : 'setTrainingEEF',
|
||||
play : 'setExecutionEEF'
|
||||
}
|
||||
var service = '/' + arm + '/aescape/hardware/' + serviceMap[config]
|
||||
triggerService(service, false, function(error, result){
|
||||
document.querySelectorAll(operationModeSelector + ' button').forEach(function(element){
|
||||
element.classList.remove('disabled')
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function startTeachRecoding() {
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
triggerService('/left/aescape/hardware/calibrateRobotiq', false, function(err, res){
|
||||
//callback(err, res);
|
||||
callback(null, null);
|
||||
});
|
||||
},
|
||||
function(response, callback) {
|
||||
triggerService('/left/aescape/mode/activateTeachingController', false, callback);
|
||||
},
|
||||
function(response, callback) {
|
||||
triggerService('/aescape/bags/startTeachRecording', false, callback)
|
||||
}
|
||||
], function (err, result) {
|
||||
console.log("starting teach recoding");
|
||||
});
|
||||
}
|
||||
|
||||
function stopTeachRecording() {
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
triggerService('/aescape/bags/stopTeachRecording', false, callback);
|
||||
},
|
||||
// function(response, callback) {
|
||||
// triggerService('/left/aescape/mode/activateReadyController', false, callback);
|
||||
// },
|
||||
function(response, callback) {
|
||||
//displayTaggingOptions('teach');
|
||||
callback();
|
||||
}
|
||||
], function (err, result) {
|
||||
console.log(err);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function playLoadedRecording() {
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
triggerService('/left/aescape/mode/activateExecutionController', false, callback);
|
||||
},
|
||||
function(response, callback) {
|
||||
var singleArmMode = $('#armMode').val();
|
||||
if (singleArmMode == "1") {
|
||||
singleArmMode = true;
|
||||
callback(null, null);
|
||||
} else {
|
||||
singleArmMode = false;
|
||||
triggerService('/right/aescape/mode/activateExecutionController', false, callback);
|
||||
}
|
||||
},
|
||||
function(response, callback) {
|
||||
triggerTopic('/left/run_trajectory', false, callback)
|
||||
}
|
||||
], function (err, result) {
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
function stopPlayingRecording() {
|
||||
async.waterfall([
|
||||
function(callback) {
|
||||
triggerService('/aescape/bags/stopPlayingBag', false, callback);
|
||||
},
|
||||
function(response, callback) {
|
||||
triggerService('/left/aescape/mode/activateReadyController', false, callback);
|
||||
},
|
||||
function(response, callback) {
|
||||
triggerService('/right/aescape/mode/activateReadyController', false, callback);
|
||||
},
|
||||
function(response, callback) {
|
||||
//displayTaggingOptions('play');
|
||||
callback();
|
||||
}
|
||||
], function (err, result) {
|
||||
// result now equals 'done'
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
373
lab_ui/client/app/components/coordinator/js/update_guis.js
Normal file
373
lab_ui/client/app/components/coordinator/js/update_guis.js
Normal file
@@ -0,0 +1,373 @@
|
||||
|
||||
var bagList = Array();
|
||||
|
||||
function getBagList(callback)
|
||||
{
|
||||
var service = new ROSLIB.Service({
|
||||
ros : ros,
|
||||
name : '/aescape/bags/getBagList',
|
||||
serviceType : 'demobot/TriggerList'
|
||||
});
|
||||
|
||||
toSend = {
|
||||
message : String(Math.random())
|
||||
}
|
||||
|
||||
var request = new ROSLIB.ServiceRequest(toSend);
|
||||
|
||||
service.callService(request, function(result) {
|
||||
callback(JSON.parse(result.message));
|
||||
});
|
||||
}
|
||||
|
||||
function getBagCategoryList(callback)
|
||||
{
|
||||
var service = new ROSLIB.Service({
|
||||
ros : ros,
|
||||
name : '/aescape/bags/getCategoryList',
|
||||
serviceType : 'demobot/TriggerList'
|
||||
});
|
||||
|
||||
var request = new ROSLIB.ServiceRequest({});
|
||||
|
||||
service.callService(request, function(result) {
|
||||
callback(JSON.parse(result.message));
|
||||
});
|
||||
}
|
||||
|
||||
function getBagTagList(callback)
|
||||
{
|
||||
var service = new ROSLIB.Service({
|
||||
ros : ros,
|
||||
name : '/aescape/bags/getTagList',
|
||||
serviceType : 'demobot/TriggerList'
|
||||
});
|
||||
|
||||
var request = new ROSLIB.ServiceRequest({});
|
||||
|
||||
service.callService(request, function(result) {
|
||||
callback(JSON.parse(result.message));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
setTimeout(function(){
|
||||
document.querySelector('.hand-panel-right .status-bar').style.height = document.querySelector('.hand-panel-left .status-bar').offsetHeight + 20 + "px";
|
||||
$(function () {
|
||||
$('[data-toggle="popover"]').popover()
|
||||
})
|
||||
}, 100);
|
||||
|
||||
|
||||
|
||||
function displayTaggingOptions(mode) {
|
||||
|
||||
hideAllSlidingControllers();
|
||||
|
||||
var modeTag = '#' + mode + 'Tags';
|
||||
var fileNameSelector = '#' + mode + 'BagFileName';
|
||||
var categorySelector = '#' + mode + 'BagCategory';
|
||||
var tagSelector = '#' + mode + 'BagTags';
|
||||
|
||||
//Subscribe to topics from the backend which indicate recording or playback is complete
|
||||
document.querySelector(modeTag).classList.add('open');
|
||||
//Putting this in a timeout to wait for the animation to finish completing
|
||||
setTimeout(function(){
|
||||
document.querySelector(modeTag).style.overflow = "visible";
|
||||
}, 600)
|
||||
|
||||
var $fileNameSelect = $(fileNameSelector).selectize({
|
||||
valueField: 'name',
|
||||
labelField: 'name',
|
||||
searchField: ['name'],
|
||||
options: [],
|
||||
create: true,
|
||||
placeholder : "Enter a name for the bag"
|
||||
});
|
||||
|
||||
var fileNameSelectize = $fileNameSelect[0].selectize;
|
||||
fileNameSelectize.clearOptions()
|
||||
// /aescape/bags/getBagList
|
||||
getBagList(function(results){
|
||||
fileNameSelectize.addOption(results)
|
||||
if(results[0]) {
|
||||
fileNameSelectize.setValue(results[0]._id);
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
var $categoryNameSelect = $(categorySelector).selectize({
|
||||
valueField: 'name',
|
||||
labelField: 'name',
|
||||
searchField: ['name'],
|
||||
options: [],
|
||||
create: true,
|
||||
placeholder : "Enter or select a category for the bag"
|
||||
});
|
||||
|
||||
var categoryNameSelectize = $categoryNameSelect[0].selectize;
|
||||
categoryNameSelectize.clearOptions()
|
||||
getBagCategoryList(function(results){
|
||||
categoryNameSelectize.addOption(results.map(function(element){
|
||||
return {name : element}
|
||||
}));
|
||||
})
|
||||
|
||||
var $tagSelect = $(tagSelector).selectize({
|
||||
valueField: 'name',
|
||||
labelField: 'name',
|
||||
searchField: ['name'],
|
||||
maxItems: 20,
|
||||
options: [],
|
||||
create: true,
|
||||
placeholder : "Enter or select tags for the bag"
|
||||
});
|
||||
|
||||
var tagSelectize = $tagSelect[0].selectize;
|
||||
tagSelectize.clearOptions()
|
||||
getBagTagList(function(results){
|
||||
tagSelectize.addOption(results.map(function(element){
|
||||
return {name : element}
|
||||
}));
|
||||
})
|
||||
|
||||
}
|
||||
|
||||
function hideTaggingOptions(mode, updateValues=false) {
|
||||
if(!mode) {
|
||||
return;
|
||||
}
|
||||
|
||||
var modeTag = '#' + mode + 'Tags';
|
||||
var bagLabelSelector = '#' + mode + 'BagFileName';
|
||||
var categorySelector = '#' + mode + 'BagCategory';
|
||||
var tagSelector = '#' + mode + 'BagTags';
|
||||
var errorSelector = '#' + mode + 'TagError';
|
||||
|
||||
|
||||
|
||||
if(updateValues) {
|
||||
var bagLabel = $(bagLabelSelector).val();
|
||||
var category = $(categorySelector).val();
|
||||
var tags = $(tagSelector).val() || [];
|
||||
|
||||
getBagList(function(results){
|
||||
if(!(results && results[0] && results[0]._id)) {
|
||||
displayMessage(false, "Could not retrieve the last recorded bag :(");
|
||||
return;
|
||||
}
|
||||
bag_id = results[0]._id;
|
||||
updateBagMetadata(mode, bag_id, bagLabel, category, tags, function(updateError) {
|
||||
if(updateError) {
|
||||
displayMessage(flase, updateError);
|
||||
} else {
|
||||
displayMessage("Bag data saved successfully!");
|
||||
//clear selectize
|
||||
$(bagLabelSelector).selectize()[0].selectize.destroy();
|
||||
$(categorySelector).selectize()[0].selectize.destroy();
|
||||
$(tagSelector).selectize()[0].selectize.destroy();
|
||||
}
|
||||
});
|
||||
})
|
||||
}
|
||||
//TO DO: Wait for the response from the backend before setting the display to none
|
||||
document.querySelector(modeTag).style.overflow = "hidden";
|
||||
document.querySelector(modeTag).classList.remove('open');
|
||||
}
|
||||
|
||||
function updateBagMetadata(mode, bag_id, bag_label, category, tags, callback) {
|
||||
if(!mode) {
|
||||
return callback();
|
||||
}
|
||||
if(!bag_id) {
|
||||
return callback();
|
||||
}
|
||||
|
||||
var toSend = {
|
||||
mode : mode,
|
||||
bag_id : bag_id,
|
||||
bag_label : bag_label,
|
||||
category : category,
|
||||
tags : tags
|
||||
}
|
||||
|
||||
triggerService('/aescape/bags/updateBagMeta', toSend, function(error, result) {
|
||||
if(!result) {
|
||||
return callback("Something went wrong in the backend while updating.");
|
||||
}
|
||||
else {
|
||||
return callback();
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function displayLoadingOptions() {
|
||||
|
||||
hideAllSlidingControllers();
|
||||
|
||||
selector = "#loadBags";
|
||||
|
||||
document.querySelector(selector).classList.add('open');
|
||||
//Putting this in a timeout to wait for the animation to finish completing
|
||||
setTimeout(function(){
|
||||
document.querySelector(selector).style.overflow = "visible";
|
||||
}, 420) //This is not a Hitchhiker's reference. This is not a 420 reference. This value has been computed to match the speed of the larger drop down.
|
||||
|
||||
var $select = $('#loadBagList').selectize({
|
||||
valueField: '_id',
|
||||
labelField: 'name',
|
||||
searchField: ['name', 'category', 'tags'],
|
||||
options: [],
|
||||
create: false,
|
||||
placeholder : "Select bag to play",
|
||||
render : {
|
||||
item: function(item, escape) {
|
||||
name = item.name;
|
||||
category = item.category || 'None';
|
||||
return '<div class="bag-select-element">' +
|
||||
'<div class="bag-select-element">' +
|
||||
'<span class="filename">' + escape(name) + '</span>' +
|
||||
'<span class="category">' + ' (' + escape(category) + ') ' + '</span>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
},
|
||||
option: function(item, escape) {
|
||||
|
||||
name = item.name;
|
||||
category = item.category || 'None';
|
||||
return '<div class="bag-select-element bag-option">' +
|
||||
'<div class="primary">' +
|
||||
'<div class="filename">' + escape(name) + '</div>' +
|
||||
'<div class="category">' + escape(category) + '</div>' +
|
||||
'</div>' +
|
||||
'<div class="secondary">' +
|
||||
'<div class="tags">' +
|
||||
item.tags.map(function(tag) {
|
||||
return '<span class="tag label label-info">' + escape(tag) + '</span>'
|
||||
}).join(' ') +
|
||||
'</div>' +
|
||||
'<div class="timestamp">' + escape(item.created_at) + '</div>' +
|
||||
'</div>' +
|
||||
'</div>';
|
||||
}
|
||||
}
|
||||
});
|
||||
$('#loadBagList').next().find('div.selectize-input > input').prop('disabled', 'disabled');
|
||||
|
||||
getBagList(function(results){
|
||||
if(!results) {
|
||||
displayMessage(false, "Could not fetch a list of recordings :(")
|
||||
}
|
||||
var selectize = $select[0].selectize;
|
||||
selectize.clearOptions();
|
||||
//results = [{filename : 'testfile', category: 'testcategory', tags : ['testtag1', 'testtag2', 'testtag3']}, {filename : 'testfile2', category: 'testcategory2', tags : ['testtag21', 'testtag22', 'testtag23']}]
|
||||
console.log(results);
|
||||
selectize.addOption(results);
|
||||
if(results[0]) {
|
||||
selectize.setValue(results[0].filename);
|
||||
}
|
||||
})
|
||||
|
||||
var $armModeSelect = $('#armMode').selectize({
|
||||
valueField: 'value',
|
||||
labelField: 'name',
|
||||
options: [],
|
||||
create: false,
|
||||
placeholder : "Select dual or single arm mode"
|
||||
});
|
||||
|
||||
var armSelectize = $armModeSelect[0].selectize;
|
||||
armSelectize.clearOptions()
|
||||
armSelectize.addOption([{name: 'Dual-arm', value: false}, {name: 'Single-arm', value: true}]);
|
||||
armSelectize.setValue(false);
|
||||
|
||||
$('#armMode').next().find('div.selectize-input > input').prop('disabled', 'disabled');
|
||||
}
|
||||
|
||||
function hideLoadingOptions(loadBag) {
|
||||
var singleArmMode = $('#armMode').val();
|
||||
if (singleArmMode == "1") {
|
||||
singleArmMode = true
|
||||
} else {
|
||||
singleArmMode = false
|
||||
}
|
||||
|
||||
if(loadBag) {
|
||||
var selectedBagId = $('#loadBagList').val();
|
||||
disableUI();
|
||||
loadSelectedBagFile(selectedBagId, singleArmMode, function(updateError){
|
||||
// if(updateError) {
|
||||
// displayMessage(false, "Something went wrong in the backend while fetching the bag files :(")
|
||||
// } else {
|
||||
// displayMessage(true, "Loaded the selected bag file!")
|
||||
// }
|
||||
})
|
||||
}
|
||||
var selector = '#loadBags';
|
||||
document.querySelector(selector).style.overflow = "hidden";
|
||||
document.querySelector(selector).classList.remove('open');
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function loadSelectedBagFile(selectedBagId, singleArmMode, callback) {
|
||||
var toSend = {
|
||||
bag_id : selectedBagId,
|
||||
single_arm : singleArmMode
|
||||
}
|
||||
|
||||
triggerService('/aescape/bags/startPlayingRecording', toSend, function(error, result) {
|
||||
if(!result) {
|
||||
return callback("Something went wrong in the backend while updating.");
|
||||
}
|
||||
else {
|
||||
return callback();
|
||||
}
|
||||
})
|
||||
|
||||
/*
|
||||
var toSendString = JSON.stringify(toSend);
|
||||
|
||||
var topic = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : "/left/playback/control",
|
||||
messageType : 'std_msgs/String'
|
||||
});
|
||||
|
||||
var msg = new ROSLIB.Message({data:toSendString});
|
||||
|
||||
topic.publish(msg);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
function hideAllSlidingControllers () {
|
||||
document.querySelectorAll('.slider-options').forEach(function(element){
|
||||
element.style.overflow = "hidden";
|
||||
element.classList.remove('open');
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
|
||||
function displayMessage (success, message) {
|
||||
if(success) {
|
||||
type = 'success';
|
||||
} else {
|
||||
type = 'danger';
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$.notify({
|
||||
message: message
|
||||
}, {
|
||||
"placement" : {
|
||||
from: "bottom",
|
||||
align: "right"
|
||||
},
|
||||
type: type,
|
||||
delay: 1000
|
||||
});
|
||||
});
|
||||
}
|
||||
104
lab_ui/client/app/components/vision/js/ros_scripts.js
Normal file
104
lab_ui/client/app/components/vision/js/ros_scripts.js
Normal file
@@ -0,0 +1,104 @@
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Publishers
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Topics
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Subscribers
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
// Operation Mode
|
||||
var modeStatus = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/aescape/mode/status',
|
||||
messageType : 'std_msgs/String'
|
||||
});
|
||||
|
||||
modeStatus.subscribe(function(message) {
|
||||
document.getElementById("stoppedModeButton").className = "btn btn-secondary"
|
||||
document.getElementById("standbyModeButton").className = "btn btn-primary"
|
||||
document.getElementById("teachingModeButton").className = "btn btn-primary"
|
||||
document.getElementById("executionModeButton").className = "btn btn-primary"
|
||||
|
||||
|
||||
if (message.data === "stopped") {
|
||||
document.getElementById("stoppedModeButton").className = "btn btn-warning"
|
||||
} else if (message.data === "standby")
|
||||
{
|
||||
document.getElementById("standbyModeButton").className = "btn btn-primary btn-success"
|
||||
} else if (message.data === "teach")
|
||||
{
|
||||
document.getElementById("teachingModeButton").className = "btn btn-primary btn-success"
|
||||
} else if (message.data === "execution")
|
||||
{
|
||||
document.getElementById("executionModeButton").className = "btn btn-primary btn-success"
|
||||
}
|
||||
});
|
||||
|
||||
// Playing Bag
|
||||
var bagPlayingTopic = new ROSLIB.Topic({
|
||||
ros : ros,
|
||||
name : '/aescape/bags/playing',
|
||||
messageType : 'std_msgs/String'
|
||||
});
|
||||
|
||||
bagPlayingTopic.subscribe(function(message) {
|
||||
document.getElementById("bagPlayingText").innerHTML = message.data
|
||||
});
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
// Services
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
function triggerService(serviceName)
|
||||
{
|
||||
var service = new ROSLIB.Service({
|
||||
ros : ros,
|
||||
name : serviceName,
|
||||
serviceType : 'std_srvs/Trigger'
|
||||
});
|
||||
|
||||
var request = new ROSLIB.ServiceRequest({});
|
||||
|
||||
service.callService(request, function(result) {
|
||||
console.log('Result for service call on '
|
||||
+ serviceName
|
||||
+ ': '
|
||||
+ result.sum);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function triggerMessageService(serviceName, textInput)
|
||||
{
|
||||
var text = document.getElementById(textInput).value
|
||||
|
||||
var service = new ROSLIB.Service({
|
||||
ros : ros,
|
||||
name : serviceName,
|
||||
serviceType : 'demobot.TriggerMessage'
|
||||
});
|
||||
|
||||
var request = new ROSLIB.ServiceRequest({
|
||||
message : text
|
||||
});
|
||||
|
||||
service.callService(request, function(result) {
|
||||
console.log('Result for service call on '
|
||||
+ serviceName
|
||||
+ ': '
|
||||
+ result.sum);
|
||||
});
|
||||
}
|
||||
122
lab_ui/client/app/components/vision/vision.html
Normal file
122
lab_ui/client/app/components/vision/vision.html
Normal file
@@ -0,0 +1,122 @@
|
||||
|
||||
<!-- <div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Select Operation Mode
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<button id="teachingModeButton" type="button" onclick="triggerService('/aescape/mode/activateTeachingController')" class="btn btn-primary">
|
||||
Teaching Mode
|
||||
</button>
|
||||
<button id="executionModeButton" type="button" onclick="triggerService('/aescape/mode/activateExecutionController')" class="btn btn-primary">
|
||||
Massage Mode
|
||||
</button>
|
||||
<button id="standbyModeButton" type="button" onclick="triggerService('/aescape/mode/activateStandbyController')" class="btn btn-primary">
|
||||
Standby Mode
|
||||
</button>
|
||||
<button id="stoppedModeButton" type="button" onclick="triggerService('/aescape/mode/stopControllers')" class="btn btn-primary">
|
||||
Stopped Mode
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Hardware Commands
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<button id="fixFrankaButton" type="button" onclick="triggerService('/aescape/hardware/resetFrankaError')" class="btn btn-primary">
|
||||
Fix Franka Errors
|
||||
</button>
|
||||
<button id="calibrateButton" type="button" onclick="triggerService('/aescape/hardware/calibrateRobotiq')" class="btn btn-primary">
|
||||
Calibrate Robotiq
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Teaching Mode Operations
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<button id="recordingStartButton" type="button" onclick="triggerService('/aescape/bags/startTeachRecording')" class="btn btn-primary">
|
||||
Start Teach Recording
|
||||
</button>
|
||||
<button id="recordingStopButton" type="button" onclick="triggerService('/aescape/bags/stopTeachRecording')" class="btn btn-primary">
|
||||
Stop Teach Recording
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Execution Mode Operations
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
Last Bag Playing:
|
||||
<span id="bagPlayingText">
|
||||
None
|
||||
</span>
|
||||
<div>
|
||||
<button id="executionStartButton" type="button" onclick="triggerService('/aescape/bags/startPlayingLastRecording')" class="btn btn-primary">
|
||||
Play Last Recording
|
||||
</button>
|
||||
<button id="executionStopButton" type="button" onclick="triggerService('/aescape/bags/stopPlayingBag')" class="btn btn-primary">
|
||||
Stop Playing Recording
|
||||
</button>
|
||||
<div class="row">
|
||||
<div class="col-md-3">
|
||||
Bagfile name must not start with "/"
|
||||
<div class="input-group">
|
||||
<input type="text" id="bagNameText" class="form-control" placeholder="bag_filename">
|
||||
<span class="input-group-btn">
|
||||
<button class="btn btn-primary" type="button" onclick="triggerMessageService('/startPlayingRecording', 'bagNameText')">
|
||||
<span>
|
||||
Start Playing Bag
|
||||
</span>
|
||||
</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div> -->
|
||||
|
||||
<script type="text/javascript" src="vision/js/ros_scripts.js"></script>
|
||||
<script type="text/javascript" src="vision/js/update_guis.js"></script>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Camera Views
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
Webcam
|
||||
<div class="row-lg-4">
|
||||
<img height="350" alt="No Camera Image" id="imageStream" src="http://titan.aescape.co:8080/stream?topic=/webcam/image_raw&type=ros_compressed"></img>
|
||||
</div>
|
||||
Realsense Red
|
||||
<div class="row-lg-4">
|
||||
<img height="350" alt="No Camera Image" id="imageStream" src="http://titan.aescape.co:8080/stream?topic=/real_red/color/image_raw&type=ros_compressed"></img>
|
||||
</div>
|
||||
Realsense Green
|
||||
<div class="row-lg-4">
|
||||
<img height="350" alt="No Camera Image" id="imageStream" src="http://titan.aescape.co:8080/stream?topic=/real_green/color/image_raw&type=ros_compressed"></img>
|
||||
</div>
|
||||
Thermal
|
||||
<div class="row-lg-4">
|
||||
<img height="350" alt="No Camera Image" id="imageStream" src="http://titan.aescape.co:8080/stream?topic=/thermal/image_raw&type=ros_compressed"></img>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- <div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Execution Recording Operations
|
||||
</div>
|
||||
<div class="panel-body text-center">
|
||||
<button id="executionStartButton" type="button" onclick="triggerService('/startExecutionRecording')" class="btn btn-primary">
|
||||
Start Recording Execution
|
||||
</button>
|
||||
<button id="executionRecordingStopButton" type="button" onclick="triggerService('/stopExecutionRecording')" class="btn btn-primary">
|
||||
Stop Recording Execution
|
||||
</button>
|
||||
</div>
|
||||
</div> -->
|
||||
498
lab_ui/client/app/main.css
Normal file
498
lab_ui/client/app/main.css
Normal file
@@ -0,0 +1,498 @@
|
||||
@import url(http://fonts.googleapis.com/css?family=Roboto:400,400italic,500,500italic,700,700italic,900,900italic,300italic,300,100italic,100);
|
||||
|
||||
html, body {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 16pt;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background: #020625;
|
||||
//color: #EDF0F4;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.fill-container {
|
||||
display: block;
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.transparent-button {
|
||||
background-color: Transparent;
|
||||
background-repeat:no-repeat;
|
||||
border: none;
|
||||
cursor:pointer;
|
||||
overflow: hidden;
|
||||
outline:none;
|
||||
}
|
||||
|
||||
.font-roboto-regular {
|
||||
font-family: 'Roboto';
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.font-roboto-thin {
|
||||
font-family: 'Roboto';
|
||||
font-weight: 100;
|
||||
}
|
||||
|
||||
.font-roboto-light {
|
||||
font-family: 'Roboto';
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.font-roboto-medium {
|
||||
font-family: 'Roboto';
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.font-roboto-medium-italic {
|
||||
font-family: 'Roboto';
|
||||
font-weight: 500;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.dialog {
|
||||
position: fixed;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: #020625;
|
||||
}
|
||||
|
||||
body {
|
||||
font-family: "Roboto";
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-family: "Roboto";
|
||||
font-size: 22pt;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.header {
|
||||
width: 100vw;
|
||||
display: flex;
|
||||
overflow: hidden;
|
||||
flex-wrap: nowrap;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
background-color: #182048;
|
||||
padding: 0 40px 0 40px;
|
||||
}
|
||||
|
||||
.header .logo img {
|
||||
width: 101px;
|
||||
height: 68px;
|
||||
}
|
||||
|
||||
.header .title {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.header .user {
|
||||
width: 101px;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.header .user i {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.header-bar {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 10px;
|
||||
padding: 0px 15px;
|
||||
}
|
||||
|
||||
.fa-circle {
|
||||
background: -webkit-gradient(linear, left top, left bottom, from(#bf9000), to(#7f6000));
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.main-tabs-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#task-connection-message {
|
||||
position: relative;
|
||||
margin: auto;
|
||||
left: -8%;
|
||||
font-weight: 600;
|
||||
font-size: 19pt;
|
||||
text-transform: capitalize;
|
||||
}
|
||||
|
||||
.panel{
|
||||
background: #182048;
|
||||
border: 1px solid;
|
||||
border-radius: 30px;
|
||||
border-color: #3573FB;
|
||||
}
|
||||
|
||||
.hand-panel .panel-body{
|
||||
background: #020625;
|
||||
}
|
||||
|
||||
.panel-heading, .panel-footer {
|
||||
background-color: #020625 !important;
|
||||
//color: #EDF0F4 !important;
|
||||
color: white !important;
|
||||
text-align: center;
|
||||
font-size: 14pt;
|
||||
}
|
||||
|
||||
.panel-heading {
|
||||
border: 1px solid;
|
||||
border-radius: 30px 30px 0 0;
|
||||
border-color: #3573FB !important;
|
||||
|
||||
}
|
||||
|
||||
.panel-footer {
|
||||
border: 1px solid;
|
||||
border-radius: 0 0 30px 30px;
|
||||
border-color: #3573FB;
|
||||
}
|
||||
|
||||
.control-container {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.control-card > .panel-body {
|
||||
height: 150px;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.control-card .button-area {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.control-card .button-area > button {
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
//color: #EDF0F4;
|
||||
color: white;
|
||||
font-size : 14pt;
|
||||
background: #182048;
|
||||
}
|
||||
|
||||
.status-container .action-button {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.status-container .action-button > button {
|
||||
height: 100%;
|
||||
border-radius: 0;
|
||||
//color: #EDF0F4;
|
||||
color: white;
|
||||
font-size : 14pt;
|
||||
background: #182048;
|
||||
width: 100%;
|
||||
border-radius: 0 30px 30px 0;
|
||||
}
|
||||
|
||||
.control-card-six .button-area > button {
|
||||
height: 50%;
|
||||
/* font-size: 12pt; */
|
||||
}
|
||||
|
||||
.control-card .panel-heading i {
|
||||
position: absolute;
|
||||
right: 25px;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
.nav-pills li a {
|
||||
border-radius: 0;
|
||||
//color: #EDF0F4;
|
||||
color: white;
|
||||
font-size : 16pt;
|
||||
font-weight: 600;
|
||||
background: #020625;
|
||||
}
|
||||
|
||||
|
||||
.nav-pills>li.active>a, .nav-pills>li.active>a:focus, .nav-pills>li.active>a:hover, .nav>li>a:focus, .nav>li>a:hover{
|
||||
//color: #EDF0F4;
|
||||
color: white;
|
||||
background: #182048;
|
||||
}
|
||||
|
||||
.hand-panel .panel-heading {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hand-panel .panel-heading i{
|
||||
margin-left: 10px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.panel-footer .message {
|
||||
font-size : 12pt;
|
||||
}
|
||||
|
||||
.status-container .status-list .list-group-horizontal{
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.status-list .list-group {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.status-list .list-group-item {
|
||||
border: none;
|
||||
background: none;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
|
||||
.panel.panel-horizontal {
|
||||
display:table;
|
||||
width:100%;
|
||||
}
|
||||
.panel.panel-horizontal > .panel-heading, .panel.panel-horizontal > .panel-body, .panel.panel-horizontal > .panel-footer {
|
||||
display:table-cell;
|
||||
}
|
||||
.panel.panel-horizontal > .panel-heading, .panel.panel-horizontal > .panel-footer {
|
||||
border:0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.panel.panel-horizontal > .panel-heading {
|
||||
border-right: 1px solid #ddd;
|
||||
border-radius: 30px 0 0 30px;
|
||||
font-size: 12pt;
|
||||
width: 20%;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
.panel.panel-horizontal > .panel-footer {
|
||||
border-left: 1px solid #ddd;
|
||||
border-radius: 0 30px 30px 0;
|
||||
width: 20%;
|
||||
padding: 0px;
|
||||
border-color: #3573FB;
|
||||
}
|
||||
|
||||
.panel.panel-horizontal > .panel-body {
|
||||
height: auto;
|
||||
padding: 0px;
|
||||
font-size: 14pt;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.btn {
|
||||
white-space: normal;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
|
||||
button[class*="active"] {
|
||||
//background-color: #085394 !important;
|
||||
background-image: linear-gradient(#085394, #073763) !important;
|
||||
}
|
||||
|
||||
button[class*="danger"] {
|
||||
background-image: linear-gradient(#990000, #660000) !important;
|
||||
}
|
||||
|
||||
button[class*="warning"] {
|
||||
background-image: linear-gradient(#b45f06, #783f04) !important;
|
||||
}
|
||||
|
||||
.force-bar .progress {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.force-bar .list-group-horizontal {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.force-bar .force-value {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.force-bar .bar-label {
|
||||
color: black;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
#recordingStartButton[active] {
|
||||
animation: blinker 3s linear infinite;
|
||||
}
|
||||
|
||||
#executionStartButton[active] {
|
||||
animation: blinker 3s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes blinker {
|
||||
50% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.execution-control .button-area > button {
|
||||
/* font-size: 12pt !important; */
|
||||
}
|
||||
|
||||
button[class*="disabled"] {
|
||||
background-color: #262b40 !important;
|
||||
cursor: not-allowed !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
input[class*="disabled"] {
|
||||
cursor: not-allowed !important;
|
||||
pointer-events: none !important;
|
||||
}
|
||||
|
||||
.disabled i{
|
||||
color: grey;
|
||||
}
|
||||
|
||||
input[class*="disabled"] + div[class*="state"] {
|
||||
color: grey;
|
||||
}
|
||||
|
||||
.safety-button {
|
||||
width: 100%;
|
||||
height: 200px;
|
||||
font-size: 32px;
|
||||
color: white !important;
|
||||
}
|
||||
|
||||
.popover {
|
||||
color: black;
|
||||
width: 500px;
|
||||
}
|
||||
|
||||
.slider-options {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.slider-options select{
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.slider-options .error {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.slider-options i {
|
||||
font-size: 30px;
|
||||
margin-top: 5px;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.slider-options {
|
||||
height: 0;
|
||||
overflow: hidden;
|
||||
}
|
||||
.tagging-options {
|
||||
transition: height 600ms ease 0ms;
|
||||
}
|
||||
.loading-options {
|
||||
transition: height 420ms ease 0ms;
|
||||
}
|
||||
.tagging-options.open {
|
||||
height: 122px;
|
||||
}
|
||||
.loading-options.open {
|
||||
height: 85px;
|
||||
}
|
||||
|
||||
|
||||
.bag-option > div {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
|
||||
.bag-option .filename {
|
||||
width: 60%;
|
||||
font-size: 12pt;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.bag-option .category {
|
||||
width: 40%;
|
||||
}
|
||||
|
||||
.bag-option .tags {
|
||||
width: 60%;
|
||||
|
||||
}
|
||||
|
||||
.bag-option .timestamp {
|
||||
width: 40%;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
.loading-options .selectize-input {
|
||||
font-size: 13pt;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/*
|
||||
.selectize-dropdown, .selectize-dropdown.form-control{
|
||||
height: 90vh !important;
|
||||
}
|
||||
|
||||
.selectize-dropdown-content{
|
||||
max-height: 100% !important;
|
||||
height: 100% !important;
|
||||
}
|
||||
*/
|
||||
|
||||
.teaching-mode-operations {
|
||||
margin-left : 20.833%;
|
||||
}
|
||||
|
||||
.play-mode-operations {
|
||||
margin-left : 8.33% !important
|
||||
}
|
||||
|
||||
.slider-options .btn-primary {
|
||||
background : #3671F9;
|
||||
width: 100%;
|
||||
margin-bottom: 10px;
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.slider-options .col-md-2 {
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
background : #3671F9;
|
||||
}
|
||||
|
||||
.progress-bar-label {
|
||||
color: grey;
|
||||
line-height: 21px;
|
||||
font-size: 16px;
|
||||
}
|
||||
3
lab_ui/client/app/utilities/Node.js
Normal file
3
lab_ui/client/app/utilities/Node.js
Normal file
@@ -0,0 +1,3 @@
|
||||
function Node (name) {
|
||||
this.name = name;
|
||||
}
|
||||
12
lab_ui/client/app/utilities/Topic.js
Normal file
12
lab_ui/client/app/utilities/Topic.js
Normal file
@@ -0,0 +1,12 @@
|
||||
function Topic (name) {
|
||||
this.name = name;
|
||||
this.bag = true;
|
||||
this.type = "";
|
||||
}
|
||||
|
||||
Array.prototype.indexOfTopic = function(name) {
|
||||
for (var i = 0; i < this.length; i++)
|
||||
if (this[i].name == name)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
31
lab_ui/client/app/utilities/config.js
Normal file
31
lab_ui/client/app/utilities/config.js
Normal file
@@ -0,0 +1,31 @@
|
||||
commonControls = [{
|
||||
title : "EEF Configuration",
|
||||
buttons : [
|
||||
{
|
||||
name : "Recording",
|
||||
clickAction : "/aescape/hardware/setTrainingEEF",
|
||||
clickAttributes : {
|
||||
includeArm : true,
|
||||
},
|
||||
},
|
||||
{
|
||||
name : "Recording",
|
||||
clickAction : "/aescape/hardware/setTrainingEEF",
|
||||
clickAttributes : {
|
||||
includeArm : true,
|
||||
},
|
||||
}
|
||||
]
|
||||
}]
|
||||
|
||||
sharedControls = {
|
||||
|
||||
}
|
||||
|
||||
leftArmControls = {
|
||||
|
||||
}
|
||||
|
||||
rightArmControls = {
|
||||
|
||||
}
|
||||
251
lab_ui/client/app/utilities/ros_scripts.js
Normal file
251
lab_ui/client/app/utilities/ros_scripts.js
Normal file
@@ -0,0 +1,251 @@
|
||||
var ros = new ROSLIB.Ros();
|
||||
|
||||
|
||||
ros.topics = Array();
|
||||
ros.nodes = Array();
|
||||
ros.recording = false;
|
||||
ros.connected = false;
|
||||
|
||||
// ros.connectionName = 'ws://192.168.1.105:9090';
|
||||
|
||||
function getQueryVariable(variable)
|
||||
{
|
||||
var query = window.location.search.substring(1);
|
||||
var vars = query.split("&");
|
||||
for (var i=0;i<vars.length;i++) {
|
||||
var pair = vars[i].split("=");
|
||||
if(pair[0] == variable){
|
||||
return pair[1];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var master = "localhost"
|
||||
master = getQueryVariable("master")
|
||||
if(master == null)
|
||||
{
|
||||
master = window.location.hostname
|
||||
//"localhost"
|
||||
}
|
||||
console.log('Master = ' + master);
|
||||
|
||||
ros.connectionName = 'ws://' + master + ':9090';
|
||||
// ros.connectionName = 'ws://localhost:9090';
|
||||
// ros.connectionName = 'ws://titan.aescape.co:9090';
|
||||
console.log('ros.connectionName = ' + ros.connectionName);
|
||||
|
||||
function enableUI() {
|
||||
try {
|
||||
var buttons = document.getElementById("coordinator").getElementsByTagName("button");
|
||||
for(var i = 0; i < buttons.length; i++)
|
||||
{
|
||||
buttons.item(i).classList.remove("disabled");
|
||||
}
|
||||
var checkBoxes = document.getElementById("coordinator").querySelectorAll(".pretty .state");
|
||||
for(var i = 0; i < checkBoxes.length; i++)
|
||||
{
|
||||
checkBoxes.item(i).classList.add("p-success-o");
|
||||
}
|
||||
document.querySelector('.dropdown').classList.remove("disabled");
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
|
||||
function disableUI() {
|
||||
try {
|
||||
var buttons = document.getElementById("coordinator").getElementsByTagName("button");
|
||||
for(var i = 0; i < buttons.length; i++)
|
||||
{
|
||||
buttons.item(i).classList.add("disabled");
|
||||
}
|
||||
var checkBoxes = document.getElementById("coordinator").querySelectorAll(".pretty .state");
|
||||
for(var i = 0; i < checkBoxes.length; i++)
|
||||
{
|
||||
checkBoxes.item(i).classList.remove("p-success-o");
|
||||
}
|
||||
document.querySelector('.dropdown').classList.add("disabled");
|
||||
|
||||
|
||||
|
||||
} catch(err) {
|
||||
console.log(err);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
setTimeout(function(){
|
||||
disableUI();
|
||||
})
|
||||
|
||||
|
||||
// If there is an error on the backend, an 'error' emit will be emitted.
|
||||
ros.on('error', function(error) {
|
||||
/*
|
||||
document.getElementById("ConnectionIPForm").className = "form-group has-warning has-feedback";
|
||||
document.getElementById("ConnectionIPInput").value = ros.connectionName;
|
||||
document.getElementById("ConnectionIPLabel").innerHTML = 'No connection';
|
||||
document.getElementById("ConnectionButton").className = "btn btn-warning"
|
||||
document.getElementById("rosbridgeconnection_badge").innerHTML = 'No connection';
|
||||
document.getElementById("ROSNodes").innerHTML = "No Nodes Detected";
|
||||
*/
|
||||
/*
|
||||
$(document).ready(function(){
|
||||
$.notify({
|
||||
message: "Something went wrong in the connection: "+ ros.connectionName
|
||||
}, {
|
||||
"placement" : {
|
||||
from: "bottom",
|
||||
align: "right"
|
||||
},
|
||||
type: 'danger',
|
||||
delay: 1000
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
document.getElementById("ConnectionButton").innerHTML = "Connect";
|
||||
document.getElementById("ConnectionIPInput").value = ros.connectionName;
|
||||
document.getElementById("task-connection-message").innerHTML = "Disconnected"
|
||||
disableUI();
|
||||
//rosbridgeconnection_badge
|
||||
console.log(error);
|
||||
});
|
||||
// Find out exactly when we made a connection.
|
||||
ros.on('connection', function() {
|
||||
ros.connected = true;
|
||||
console.log('Connection made!');
|
||||
document.getElementById("ConnectionButton").innerHTML = "Disconnect";
|
||||
document.getElementById("ConnectionIPInput").value = ros.connectionName;
|
||||
/*
|
||||
document.getElementById("ConnectionIPForm").className = "form-group has-success has-feedback";
|
||||
document.getElementById("ConnectionIPInput").value = ros.connectionName;
|
||||
document.getElementById("ConnectionIPLabel").innerHTML = 'Connection made at:';
|
||||
document.getElementById("rosbridgeconnection_badge").innerHTML = 'Connected';
|
||||
document.getElementById("ConnectionButton").className = "btn btn-success";
|
||||
*/
|
||||
|
||||
$(document).ready(function(){
|
||||
$.notify({
|
||||
message: "Connected to: "+ ros.connectionName
|
||||
}, {
|
||||
"placement" : {
|
||||
from: "bottom",
|
||||
align: "right"
|
||||
},
|
||||
type: 'success',
|
||||
delay: 1000
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
enableUI();
|
||||
document.getElementById("task-connection-message").innerHTML = "Connected to: " + ros.connectionName;
|
||||
getMasterName();
|
||||
|
||||
ros.nodes = Array();
|
||||
ros.topics = Array();
|
||||
|
||||
});
|
||||
|
||||
ros.on('close', function() {
|
||||
console.log('Connection closed.');
|
||||
ros.connected = false;
|
||||
|
||||
/*
|
||||
document.getElementById("ConnectionIPForm").className = "form-group has-warning has-feedback";
|
||||
document.getElementById("ConnectionIPLabel").innerHTML = 'Connection closed';
|
||||
document.getElementById("ConnectionButton").className = "btn btn-warning"
|
||||
document.getElementById("rosbridgeconnection_badge").innerHTML = 'Connection closed';
|
||||
*/
|
||||
/*
|
||||
$(document).ready(function(){
|
||||
$.notify({
|
||||
message: "Disconnected from "+ ros.connectionName
|
||||
}, {
|
||||
"placement" : {
|
||||
from: "bottom",
|
||||
align: "right"
|
||||
},
|
||||
type: 'danger',
|
||||
delay: 1000
|
||||
});
|
||||
});
|
||||
*/
|
||||
|
||||
document.getElementById("ConnectionButton").innerHTML = "Connect";
|
||||
document.getElementById("ConnectionIPInput").value = ros.connectionName;
|
||||
document.getElementById("task-connection-message").innerHTML = "Disconnected"
|
||||
|
||||
disableUI();
|
||||
|
||||
ros.nodes = Array();
|
||||
ros.topics = Array();
|
||||
});
|
||||
// Create a connection to the rosbridge WebSocket server.
|
||||
//ros.connect(ros.connectionName);
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
// Functions
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// attept to connect to the ros master from the IP given orgrab it from the form
|
||||
ros.attemptConnection = function(ipAddress)
|
||||
{
|
||||
ros.close();
|
||||
if( typeof ipAddress !== "undefined")
|
||||
{
|
||||
ros.connectionName = ipAddress;
|
||||
}
|
||||
else
|
||||
{
|
||||
ros.connectionName = document.getElementById("ConnectionIPInput").value
|
||||
}
|
||||
console.log('Connection = ' + ros.connectionName);
|
||||
ros.connect(ros.connectionName);
|
||||
}
|
||||
|
||||
function toggleRecording()
|
||||
{
|
||||
if(ros.connected)
|
||||
{
|
||||
document.getElementById("recordButtonText").innerHTML = "Wait"
|
||||
document.getElementById("recordButton").className = "btn btn-warning"
|
||||
|
||||
if (!ros.recording) {
|
||||
ros.recording = true
|
||||
topicstobag = " "
|
||||
for (i = 0; i < ros.topics.length; i ++)
|
||||
{
|
||||
if (ros.topics[i].bag == true)
|
||||
{
|
||||
topicstobag = topicstobag.concat(ros.topics[i].name + " ")
|
||||
}
|
||||
}
|
||||
publishBagMessage(document.getElementById("recordText").value + topicstobag)
|
||||
} else {
|
||||
ros.recording = false
|
||||
publishBagMessage("STOP")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getMasterName()
|
||||
{
|
||||
var service = new ROSLIB.Service({
|
||||
ros : ros,
|
||||
name : '/rosapi/service_host',
|
||||
serviceType : 'rosapi/ServiceHost'
|
||||
});
|
||||
|
||||
var request = new ROSLIB.ServiceRequest({
|
||||
service: '/rosout/get_loggers' // Only the master hosts this service.
|
||||
});
|
||||
|
||||
service.callService(request, function(result) {
|
||||
document.getElementById("task-connection-message").innerHTML = "Connected to: " + result.host;
|
||||
});
|
||||
}
|
||||
101
lab_ui/client/app/utilities/update_guis.js
Normal file
101
lab_ui/client/app/utilities/update_guis.js
Normal file
@@ -0,0 +1,101 @@
|
||||
|
||||
|
||||
function updateTopicsGUI()
|
||||
{
|
||||
|
||||
ros.getTopics(function(result)
|
||||
{
|
||||
ros.topics = result;
|
||||
});
|
||||
|
||||
var topics = ros.topics;
|
||||
|
||||
if(topics != null){
|
||||
var innerHTML = "";
|
||||
for (var i = 0; i < topics.length; i++ )
|
||||
{
|
||||
innerHTML = innerHTML.concat(topics[i]);
|
||||
innerHTML = innerHTML.concat("<br>");
|
||||
}
|
||||
document.getElementById("ROSTopics").innerHTML = innerHTML;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
function updateNodesGUI()
|
||||
{
|
||||
|
||||
ros.getNodes(function(result)
|
||||
{
|
||||
ros.nodes = result;
|
||||
});
|
||||
|
||||
var nodes = ros.nodes;
|
||||
|
||||
nodes.sort()
|
||||
|
||||
if(nodes != null){
|
||||
var innerHTML = "";
|
||||
for (var i = 0; i < nodes.length; i++ )
|
||||
{
|
||||
innerHTML = innerHTML.concat(nodes[i]);
|
||||
innerHTML = innerHTML.concat("<br>");
|
||||
}
|
||||
document.getElementById("ROSNodes").innerHTML = innerHTML;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
// window.setInterval(function(){
|
||||
|
||||
// updateTopicsGUI();
|
||||
// updateNodesGUI();
|
||||
|
||||
// }, 5000);
|
||||
|
||||
function validateForm()
|
||||
{
|
||||
ros.attemptConnection();
|
||||
return false;
|
||||
};
|
||||
|
||||
function addInputsForConnection()
|
||||
{
|
||||
|
||||
var innerHTML = "";
|
||||
|
||||
for (var i = 0; i < ros.connectioninfo.length; i ++)
|
||||
{
|
||||
|
||||
console.log(ros.connectioninfo[i])
|
||||
el = document.getElementById("ConnectionInformation")
|
||||
|
||||
innerHTML = innerHTML.concat("<span class=\"col-sm-1\">");
|
||||
innerHTML = innerHTML.concat("<input type=\"text\" class=\"form-control\" value=\"");
|
||||
innerHTML = innerHTML.concat(ros.connectioninfo[i])
|
||||
innerHTML = innerHTML.concat("\"/>")
|
||||
innerHTML = innerHTML.concat("</span>")
|
||||
if(i >0 && i < 4)
|
||||
{
|
||||
innerHTML = innerHTML.concat("<span class=\"col-sxm-1\">.</span>")
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
el.innerHTML = innerHTML;
|
||||
|
||||
console.log(innerHTML)
|
||||
|
||||
|
||||
}
|
||||
|
||||
function mylog(input)
|
||||
{
|
||||
console.log(input)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user