Skip to content

Commit

Permalink
Merge pull request #367 from ltindall/ui
Browse files Browse the repository at this point in the history
Added interaction and improved GUI features.
  • Loading branch information
ltindall authored Dec 6, 2023
2 parents 9af1993 + 5de3209 commit 407e2fc
Show file tree
Hide file tree
Showing 3 changed files with 164 additions and 36 deletions.
127 changes: 91 additions & 36 deletions geolocate.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
import time

from datetime import datetime
from flask import Flask, render_template
from flask import Flask, render_template, send_from_directory, redirect, request, url_for, make_response, jsonify
from io import BytesIO
from timeit import default_timer as timer

Expand Down Expand Up @@ -119,6 +119,36 @@ def __init__(self, config_path="geolocate.ini"):
self.static_position = None
self.static_heading = None

#### CONFIGS
default_config = {
"local_plot": "false",
"make_gif": "false",
"n_targets": "2",
"antenna_type": "logp",
"planner_method": "repp",
"target_speed": "0.5",
"sensor_speed": "1.0",
"power_tx": "26.0",
"directivity_tx": "1.0",
"freq": "5.7e9",
"fading_sigma": "8.0",
"threshold": "-120",
"mcts_depth": "3",
"mcts_c": "20.0",
"mcts_simulations": "100",
"mcts_n_downsample": "400",
"static_position": None,
"static_heading": None,
"replay_file": None,
"mqtt_host": ORCHESTRATOR,
"mqtt_port": "1883",
"flask_host": "0.0.0.0", # nosec
"flask_port": "4999",
"use_flask": "false",
}
default_config.update(self.config)
self.config = default_config

def data_handler(self, message_data):
"""
Generic data processor
Expand Down Expand Up @@ -207,6 +237,51 @@ def run_flask(self, flask_host, flask_port, fig, results):
"""
app = Flask(__name__)

@app.route('/gui/<path:filename>')
def gui_file(filename):
return send_from_directory('gui', filename)

@app.route("/gui/data")
def gui_data():
data = base64.b64encode(self.image_buf.getvalue()).decode("ascii")
img = "data:image/png;base64,"+data
return jsonify(img)

@app.route('/refresh')
def refresh():
os.makedirs('gui', exist_ok=True)
with open("gui/map.png", "wb") as img:
img.write(self.image_buf.getbuffer())
# newmapp = np.random.rand(500,500,3) * 255
# data = Image.fromarray(newmapp.astype('uint8')).convert('RGBA')
# data.save('gui/map.png')
return "OK"

@app.route('/gui/form', methods = ['POST', 'GET'])
def gui_form():
if request.method == 'POST':
user = request.form.get('name', None)
self.config['n_targets'] = request.form.get('n_targets', self.config['n_targets'])
reset = request.form.get('reset', None)
if reset == "reset":
self.stop()
self.image_buf = BytesIO()
self.start()
return redirect(request.referrer)

@app.route("/guiFile")
def gui_from_file():
if not self.image_buf.getbuffer().nbytes:
return render_template("loading.html")
return render_template("gui_from_file.html", config=self.config)

@app.route("/guiBuffer")
def gui_from_buffer():
if not self.image_buf.getbuffer().nbytes:
return render_template("loading.html")
return render_template("gui_from_buffer.html", config=self.config)


@app.route("/")
def index():
flask_start_time = timer()
Expand Down Expand Up @@ -251,41 +326,21 @@ def get_replay_log(self, replay_file):
replay_data = json.loads(line)
yield replay_data

def main(self):
def start(self):
self.stop_threads = False
self.main_thread = threading.Thread(target=self.main, args=[lambda: self.stop_threads])
self.main_thread.start()
logging.info("Main thread started.")

def stop(self):
self.stop_threads = True
self.main_thread.join()
logging.info("Main thread stopped.")

def main(self, stopped):
"""
Main loop
"""

#### CONFIGS
default_config = {
"local_plot": "false",
"make_gif": "false",
"n_targets": "2",
"antenna_type": "logp",
"planner_method": "repp",
"target_speed": "0.5",
"sensor_speed": "1.0",
"power_tx": "26.0",
"directivity_tx": "1.0",
"freq": "5.7e9",
"fading_sigma": "8.0",
"threshold": "-120",
"mcts_depth": "3",
"mcts_c": "20.0",
"mcts_simulations": "100",
"mcts_n_downsample": "400",
"static_position": None,
"static_heading": None,
"replay_file": None,
"mqtt_host": ORCHESTRATOR,
"mqtt_port": "1883",
"flask_host": "0.0.0.0", # nosec
"flask_port": "4999",
"use_flask": "false",
}
default_config.update(self.config)
self.config = default_config

self.static_position = self.config["static_position"]
if self.static_position:
self.static_position = [float(i) for i in self.static_position.split(",")]
Expand Down Expand Up @@ -465,11 +520,11 @@ def main(self):
control_actions = []
step_time = 0

while self.data["gps"] != "fix" and not replay_file:
while self.data["gps"] != "fix" and not replay_file and not stopped():
time.sleep(1)
logging.info("Waiting for GPS...")

while True:
while True and not stopped():
loop_start = timer()
self.data["utc_time"] = datetime.utcnow().timestamp()

Expand Down Expand Up @@ -585,4 +640,4 @@ def main(self):
logging.getLogger("matplotlib.font_manager").disabled = True

instance = Geolocate(config_path=args.config_path)
instance.main()
instance.start()
37 changes: 37 additions & 0 deletions templates/gui_from_buffer.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<html>
<head>
<title>BirdsEye</title>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body>
<img id="map" src="" />
<form action = "{{ url_for('gui_form') }}" method = "post">
<p>Number of targets:</p>
<p><input type = "text" name="n_targets" value="{{ config.n_targets }}"/></p>

<p><button name="reset" type="submit" value="reset">Reset</button></p>
</form>
<script>
$(document).ready(function(){
setInterval(refreshFunction, 1000);
});

function refreshFunction(){

fetch("{{ url_for('gui_data') }}")
.then(res => res.json())
.then(data => {
$("#map").attr("src", data);

})
.catch(err => alert("Error: " + err));

// including jquery version
// $.get("{{ url_for('gui_data') }}", function(res){
// $("#map").attr("src", res);

// });
}
</script>
</body>
</html>
36 changes: 36 additions & 0 deletions templates/gui_from_file.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<html>
<head>
<title>BirdsEye</title>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
</head>
<body>
<img id="map" src="" />
<form action = "{{ url_for('gui_form') }}" method = "post">
<p>Number of targets:</p>
<p><input type = "text" name="n_targets" value="{{ config.n_targets }}"/></p>

<p><button name="reset" type="submit" value="reset">Reset</button></p>
</form>
<script>
$(document).ready(function(){
setInterval(refreshFunction, 1000);
});

function refreshFunction(){
fetch("/refresh")
.then(res => {
d = new Date();
$("#map").attr("src", "{{ url_for('gui_file', filename='map.png') }}?"+d.getTime());

})
.catch(err => alert("Error: " + err));

// including jquery version
// $.get('/refresh', function(){
// d = new Date();
// $("#map").attr("src", "{{ url_for('gui_file', filename='map.png') }}?"+d.getTime());
// });
}
</script>
</body>
</html>

0 comments on commit 407e2fc

Please sign in to comment.