diff --git a/html/countdown.js b/html/countdown.js new file mode 100644 index 0000000000000000000000000000000000000000..491b805213302070af21f429024f59797ffc92fe --- /dev/null +++ b/html/countdown.js @@ -0,0 +1,73 @@ +var countdown_timer; +var countdown_running=false; +var flash=0; + +function startTimer(duration, display) +{ + var timer = duration, minutes, seconds; + countdown_timer= setInterval(function () { + minutes = parseInt(timer / 60, 10); + seconds = parseInt(timer % 60, 10); + + minutes = minutes < 10 ? "0" + minutes : minutes; + seconds = seconds < 10 ? "0" + seconds : seconds; + + var slot_time_string = minutes + ":" + seconds + localStorage.setItem('slot_timer_output', slot_time_string); + display.textContent = slot_time_string; + + if (--timer < 0) + { + timer=0; + if(flash) + document.getElementById('slot_timer_output').style.backgroundColor="red"; + else + document.getElementById('slot_timer_output').style.backgroundColor="white"; + flash=!flash; + } + }, 1000); +} + +function slot_time() +{ + if(!countdown_running) + { + var time = document.getElementById("slot_time_input").value; + display = document.querySelector('#slot_timer_output'); + document.getElementById("slot_time_button").innerHTML = "PAUSE"; + document.getElementById('slot_time_button').style.backgroundColor="RoyalBlue"; + startTimer(time, display); + countdown_running=true; + } + else + { + clearTimeout(countdown_timer); + document.getElementById("slot_time_button").innerHTML = "START"; + document.getElementById('slot_time_button').style.backgroundColor="blue"; + } + +} + +function slot_time_reset() +{ + clearTimeout(countdown_timer); + document.getElementById('slot_timer_output').style.backgroundColor="white"; +} + +window.onload = function () +{ + var duration = document.getElementById("slot_time_input").value; + var timer = duration, minutes, seconds; + display = document.querySelector('#slot_timer_output'); + minutes = parseInt(timer / 60, 10); + seconds = parseInt(timer % 60, 10); + + minutes = minutes < 10 ? "0" + minutes : minutes; + seconds = seconds < 10 ? "0" + seconds : seconds; + + var slot_timer_string = minutes+":"+seconds; + + localStorage.setItem('slot_timer_output', slot_timer_string); + + display.textContent = minutes + ":" + seconds; +}; diff --git a/html/index.html b/html/index.html index ed240ec3f4e841ddcfc9d6f2fb8a24d686d9aabc..037648b4c1d0e0a3d0bf484868873bf304b32a10 100644 --- a/html/index.html +++ b/html/index.html @@ -16,6 +16,7 @@ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ" crossorigin="anonymous"></script> <script src="timer.js"></script> + <script src="countdown.js"></script> <script src="./js-yaml/dist/js-yaml.min.js"></script> <link rel="stylesheet" href="style.css"> @@ -41,7 +42,7 @@ var adc_jury_service_client = new ROSLIB.Service({ ros : ros, - name : '/jury_mode', + name : '/jury/set_mode', serviceType : 'iri_adc_msgs/jury_mode' }); @@ -51,7 +52,7 @@ var adc_jury_client = new ROSLIB.ActionClient({ ros : ros, - serverName : '/adc_jury', + serverName : '/jury/challenge', actionName : 'iri_adc_msgs/adc_juryAction' }); @@ -227,7 +228,7 @@ { document.getElementById("service_info").innerHTML = "ERROR: couldn't contact service server!!!"; document.getElementById("service_info").style.backgroundColor = 'red' ; - console.log("ERROR: couldn't contact service server!!!"); + console.error("ERROR: couldn't contact service server!!!"); } } @@ -279,9 +280,9 @@ else { //clearTimeout(feedback_timer); - console.log("ERROR: feedback not received!"); - document.getElementById("action_info").innerHTML = "ERROR: feedback NOT received!"; - document.getElementById("action_info").style.backgroundColor = 'red' ; + console.warn("WARN: feedback not received!"); + document.getElementById("action_info").innerHTML = "WARN: feedback NOT received!"; + document.getElementById("action_info").style.backgroundColor = 'yellow' ; //TODO: what to do then? feedback_watchdog_timer(); } @@ -322,6 +323,7 @@ document.getElementById("goals_info").innerHTML = "Error loading file"; document.getElementById("goals_info").style.backgroundColor = 'red' ; document.getElementById('startStop').disabled=true; + console.error("ERROR: couldn't load goals"); } } ); @@ -389,10 +391,23 @@ <main role="main" class="container"> - Team:          <input type="number" id="team_input" min="1" max="6" step="1" style="width: 2em" value="1" onchange="update_team()"> - <br> - Challenge: <input type="number" id="challenge_input" min="0" max="5" step="1" style="width: 2em" value="1" onchange="update_challenge()"> - + <div class="row"> + <div class="column"> + Team:          + <input type="number" id="team_input" min="1" max="6" step="1" style="width: 2em" value="1" onchange="update_team()"> + <br> + Challenge: + <input type="number" id="challenge_input" min="0" max="5" step="1" style="width: 2em" value="1" onchange="update_challenge()"> + </div> + <div class="column"> + SLOT TIME + <input type="number" id="slot_time_input" min="1" max="60" step="1" style="width: 2.5em" value="12"> + <button class="btn btn-success" id ="slot_time_button" style="width:20%; height: 50px" onclick = "this.blur();slot_time()">START</button> + <button class="btn btn-danger" id ="slot_time_reset_button" style="width:20%; height: 50px" onclick = "this.blur();slot_time_reset()">RESET</button> + <span id="slot_timer_output">00:00</span> + </div> + </div> + <hr> <b>Goals file:</b> (will be automatic for each chosen challenge # (goals#.yaml)) <br> @@ -415,9 +430,7 @@ <!--<button class="btn btn-danger" id = "resetButton" style="width:49.25%; height: 50px; background-color: red" onclick = "this.blur();reset()">RESET</button>--> </div> <br> - <p id = "output" class = "text-left">00:00:00</p> - - + <p id = "timer_output" class = "text-left">00:00:00</p> <hr> <b>Jury Mode</b> diff --git a/html/public.html b/html/public.html new file mode 100644 index 0000000000000000000000000000000000000000..4cf9c233618af92c28702d2b9c4deabe7b19139b --- /dev/null +++ b/html/public.html @@ -0,0 +1,421 @@ +<html> + <head> + <meta charset="utf-8"> + <!-- + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap.min.css"> + <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/css/bootstrap-theme.min.css"> + + <script src="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.6/js/bootstrap.min.js"></script> + <script src="https://rawgit.com/rbonghi/roswebconsole/master/js/ros/eventemitter2/eventemitter2.min.js"></script> + --> + <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script> + <script src="https://rawgit.com/RobotWebTools/roslibjs/develop/build/roslib.min.js"></script> + + <!--<link href="include/bootstrap-5.1.1-dist/css/bootstrap.min.css" rel="stylesheet"></link>--> + <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous"> + <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js" integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ" crossorigin="anonymous"></script> + +<!-- <script src="timer.js"></script> --> +<!-- <script src="countdown.js"></script> --> +<!-- <script src="./js-yaml/dist/js-yaml.min.js"></script> --> + <link rel="stylesheet" href="style.css"> + + + + <script> + document.title="ADC GUI"; + + var ip; + ip = document.domain; + //ip = window.location.hostname + //ip = prompt("Enter server ip address", "192.168.100.219"); + + ////////////////////////////////////// + ///ROS + var ros = new ROSLIB.Ros(); + ros.connect('ws://'+ip+':9090'); + + var goals_param = new ROSLIB.Param({ + ros : ros, + name : '/goals' + }); + + var adc_jury_service_client = new ROSLIB.Service({ + ros : ros, + name : '/jury/set_mode', + serviceType : 'iri_adc_msgs/jury_mode' + }); + + var srv_request = new ROSLIB.ServiceRequest({ + enable : false + }); + + var adc_jury_client = new ROSLIB.ActionClient({ + ros : ros, + serverName : '/jury/challenge', + actionName : 'iri_adc_msgs/adc_juryAction' + }); + + var goal_array_msg = new ROSLIB.Message( + { + }); + + var team; + var challenge; + var feedback_text=""; + var last_feedback_line=""; + var i=0; + var service_answered=false; + var service_ok=false; + var received_feedback=false; + var feedback_timer; + var jury_mode_running=false; + var action_running=false; + var goals_loaded=false; + + function update_team() + { + team = document.getElementById("team_input").value; + localStorage.setItem('team', team); + } + + function update_challenge() + { + challenge = document.getElementById("challenge_input").value; + localStorage.setItem('challenge', challenge); + } + + function send_goal() + { + //load_goals_from_yaml(); //TODO: sync load. Now is async and done on input.onchange and at the beginning + + init_goal_msg(); + + action_goal.send(); + + document.getElementById("action_info").innerHTML = "Goal sent. Expecting feedback..."; + document.getElementById("action_info").style.backgroundColor = 'yellow' ; + + feedback_watchdog_timer(); + //action_running=true; //true when received feedback? + } + + function init_goal_msg() + { + action_goal = new ROSLIB.Goal( + { + actionClient : adc_jury_client, + goalMessage : goal_array_msg + } + ); + + action_goal.on('feedback', function(msg) + { + received_feedback=true; + action_running=true; + document.getElementById("action_info").innerHTML = "Feedback received!"; + document.getElementById("action_info").style.backgroundColor = 'green' ; + var feedback_new_line= msg.status; + add_feedback_line(feedback_new_line); + }); + + action_goal.on('result', function(result) + { + if(action_running) + { + finish_action(); + } + }); + + } + + function finish_action() + { + if(timer_running) + startStop(); + document.getElementById("action_info").innerHTML = "Action finished"; + document.getElementById("action_info").style.backgroundColor = 'white' ; + action_running=false; + clearTimeout(feedback_timer); + add_feedback_line("Finished"); + } + + function cancel_goal() + { + action_goal.cancel(); + document.getElementById("action_info").innerHTML = "Goal cancelled"; + document.getElementById("action_info").style.backgroundColor = 'white' ; + } + + function jury_mode() + { + if(!jury_mode_running) + jury_mode_enable(); + else + jury_mode_disable(); + } + + function jury_mode_enable() + { + document.getElementById("service_info").innerHTML = "Called service, waiting response..."; + document.getElementById("service_info").style.backgroundColor = 'yellow' ; + document.getElementById('jury_mode_button').disabled=true; + srv_request.enable=true; + adc_jury_service_client.callService(srv_request, + function(result) + { + service_answered=true; + service_ok=true; + jury_mode_answered(); + }, + function(result) + { + service_answered=true; + service_ok=false; + jury_mode_answered(); + }); + } + + function jury_mode_disable() + { + document.getElementById("service_info").innerHTML = "Called service server, waiting response..."; + document.getElementById("service_info").style.backgroundColor = 'yellow' ; + document.getElementById('jury_mode_button').disabled=true; + srv_request.enable=false; + adc_jury_service_client.callService(srv_request, + function(result) + { + service_answered=true; + service_ok=true; + jury_mode_answered(); + }, + function(result) + { + service_answered=true; + service_ok=false; + jury_mode_answered(); + }); + } + + function jury_mode_answered() + { + document.getElementById('jury_mode_button').disabled=false; + if(service_ok) + { + service_ok=false; + document.getElementById("service_info").innerHTML = "Service responded"; + document.getElementById("service_info").style.backgroundColor = 'green' ; + if(!jury_mode_running) + { + add_feedback_line("Jury mode enabled"); + jury_mode_running = true; + document.getElementById("jury_mode_button").innerHTML = "DISABLE"; + document.getElementById('jury_mode_button').style.backgroundColor="Red"; + if(document.getElementById("startStop").innerHTML=="START") + document.getElementById('startStop').disabled=true; + } + else + { + add_feedback_line("Jury mode disabled"); + jury_mode_running = false; + document.getElementById("jury_mode_button").innerHTML = "ENABLE"; + document.getElementById('jury_mode_button').style.backgroundColor="RoyalBlue"; + if(document.getElementById("startStop").innerHTML=="START") + document.getElementById('startStop').disabled=false; + } + } + else + { + document.getElementById("service_info").innerHTML = "ERROR: couldn't contact service server!!!"; + document.getElementById("service_info").style.backgroundColor = 'red' ; + console.error("ERROR: couldn't contact service server!!!"); + } + } + + // function add_fake_feedback() + // { + // feedback_new_line=document.getElementById("fake_feedback_text").value+" "+i; + // i=i+1; + // add_feedback_line(feedback_new_line); + // } + + function add_feedback_line(text) + { + if(text!=last_feedback_line) + { +// var currentTime = new Date(); +// var secs = Math.floor(currentTime.getTime()/1000); +// var nsecs = Math.round(1000000000*(currentTime.getTime()/1000-secs)); +// var time = "["+secs+","+nsecs+"]: "; + var time = "[" + time_string + "]: "; + + feedback_text = time + text + '
' + feedback_text ; + document.getElementById("feedback_text").innerHTML = feedback_text; + } + last_feedback_line=text; + } + + function clear_feedback() + { + feedback_text=""; + last_feedback_line=""; + i=0; + document.getElementById("feedback_text").innerHTML = feedback_text; + } + + function feedback_watchdog_timer() + { + feedback_timer = setTimeout( + function() + { + if(action_running) + { + if(received_feedback) + { + received_feedback=false; + document.getElementById("action_info").innerHTML = "Feedback received!"; + document.getElementById("action_info").style.backgroundColor = 'green' ; + feedback_watchdog_timer(); + } + else + { + //clearTimeout(feedback_timer); + console.warn("WARN: feedback not received!"); + document.getElementById("action_info").innerHTML = "WARN: feedback NOT received!"; + document.getElementById("action_info").style.backgroundColor = 'yellow' ; + //TODO: what to do then? + feedback_watchdog_timer(); + } + } + },2000); + } + + function load_goals_from_yaml() + { + document.getElementById("goals_info").innerHTML = "Loading file"; + document.getElementById("goals_info").style.backgroundColor = 'yellow' ; + goals_file = document.getElementById("goals_file").value; + var goals_from_yaml; + + $.ajax( + { + url: goals_file, + success: + function(result) + { + goals_from_yaml = jsyaml.load( result ); + + goal_array_msg = new ROSLIB.Message( + { + goals: goals_from_yaml + }); + + goals_loaded=true; + document.getElementById("goals_info").innerHTML = "Loaded"; + document.getElementById("goals_info").style.backgroundColor = 'green' ; + document.getElementById('startStop').disabled=false; + }, + error: + function (xhr, ajaxOptions, thrownError) + { + //alert(xhr.status); + //alert(thrownError); + document.getElementById("goals_info").innerHTML = "Error loading file"; + document.getElementById("goals_info").style.backgroundColor = 'red' ; + document.getElementById('startStop').disabled=true; + console.error("ERROR: couldn't load goals"); + } + } + ); + } + + function iteration() + { + public_timer_timeout = setTimeout( + function() + { + var public_time_string= localStorage.getItem('attempt_time'); + + //console.log("time_string: ", time_string); + document.getElementById("timer_output").innerHTML = public_time_string ; + var public_slot_time_string = localStorage.getItem('slot_time'); + document.getElementById("slot_timer_output").innerHTML = public_slot_time_string ; + iteration(); + },100); + } + + $(document).ready + ( + function () + { + document.getElementById("team_id").innerHTML = localStorage.getItem('team'); + document.getElementById("challenge_id").innerHTML = localStorage.getItem('challenge'); + iteration(); + } + ); + </script> + + </head> + + <body> + <style>body { padding-top: 60px;}</style> + + <nav class="navbar navbar-expand-md navbar-dark bg-dark fixed-top"> + <a class="navbar-brand" href="https://autonomous-driving-challenge.com/"> + <img src="images/carnet.png" width="30" height="30" class="d-inline-block align-top" alt=""> + ADC + </a> + <button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarsExampleDefault" aria-controls="navbarsExampleDefault" aria-expanded="false" aria-label="Toggle navigation"> + <span class="navbar-toggler-icon"></span> + </button> + + <div class="collapse navbar-collapse" id="navbarsExampleDefault"> + <ul class="navbar-nav mr-auto"> + <li class="nav-item active"> + <a class="nav-link" href="index.html"><b>Home</b></a> + </li> + <!-- + <li class="nav-item"> + <a class="nav-link" href="map.html">Map<a/> + </li> + --> + </ul> + </div> + </nav> + + <main role="main" class="container"> + + <div class="row"> + <div class="column"> + Team:          + <span style='border:2px black solid;' id="team_id" >1</span> + <br> + Challenge: + <span style='border:2px black solid;' id="challenge_id" >1</span> + </div> + <div class="column"> + SLOT TIME + <span id="slot_timer_output">00:00</span> + </div> + </div> + + <hr> + + <b>Attempt</b> + <br> + <p id = "timer_output" class = "text-left">00:00:00</p> + <hr> + + <b>Jury Mode</b> + <br> + <span style='border:2px black solid;' id="service_info" >Disabled</span> + + <hr> + <b>Feedback</b> + <br> + <textarea readonly id="feedback_text" style="resize: vertical; width:100%; border-style:solid;" wrap='off' rows="3" cols="auto">Received feedback messages will be shown here. Each message starting a new line</textarea> + + </main> + + </body> +</html> diff --git a/html/style.css b/html/style.css index e3c7fd0bc0e88fe59b9b2271802799dd58ef2d23..e5df8f38f9c83b6ae0fa55bc1b11c3abecc23896 100644 --- a/html/style.css +++ b/html/style.css @@ -5,13 +5,24 @@ font-size: 4.0em; } -#output { +#timer_output { font-size: 3.0em; width: auto; height: auto; background-color: white; border: 3px solid black; margin-right: auto; + margin-left: 0; + margin-top: auto; +} + +#slot_timer_output { + font-size: 2.5em; + width: auto; + height: auto; + background-color: white; + border: 3px solid black; + margin-right: auto; margin-left: 0px; margin-top: auto; } @@ -20,3 +31,8 @@ margin-top: auto; font-size: 1.0em; } + +.column { + float: left; + width: 49%; +} diff --git a/html/timer.js b/html/timer.js index 30b78e2ac93ffd2fbd80119faef9283459145f70..16ca8f1488e84648a5de573201e4ad0988365364 100644 --- a/html/timer.js +++ b/html/timer.js @@ -43,7 +43,8 @@ function increment() secs = "0" + secs; } time_string = mins + ":" + secs + ":" + "0" + tenths; - document.getElementById("output").innerHTML = time_string ; + localStorage.setItem('attempt_time', time_string); + document.getElementById("timer_output").innerHTML = time_string ; increment(); } },100);