diff --git a/dfall_ws/src/dfall_pkg/crazyradio/CrazyRadio.py b/dfall_ws/src/dfall_pkg/crazyradio/CrazyRadio.py index ca3dd25a35f3dbb14215e26cd19c5168dda744c4..fb0e3cf53fcea56b250d0eaceb46e3af1fbbee4c 100755 --- a/dfall_ws/src/dfall_pkg/crazyradio/CrazyRadio.py +++ b/dfall_ws/src/dfall_pkg/crazyradio/CrazyRadio.py @@ -252,6 +252,20 @@ class CrazyRadioClient: def _data_received_stateEstimate_callback(self, timestamp, data, logconf): + # Perform safety check if required + if (isEnabled_strictSafety): + # Estimate the height at the next measurement + height_at_next_measurement = data["stateEstimateZ.z"] / 1000.0 + (cfStateEstimate_polling_period / 1000.0) * (data["stateEstimateZ.vz"] / 1000.0) + # Turn-off if too high + if (height_at_next_measurement > maxHeight_for_strictSafety_meters): + # Publish a motors OFF command + msg = IntWithHeader() + msg.shouldCheckForAgentID = False + msg.data = CMD_CRAZYFLY_MOTORS_OFF + self.flyingAgentClient_command_publisher.publish(msg) + # Inform the user + rospy.logerr("[CRAZY RADIO] Height safety check failed, measured = %f, max allowed = %f" % (height_at_next_measurement, maxHeight_for_strictSafety_meters)) + # Initialise the variable for the flying vehicle state cfStateEstimate = FlyingVehicleState() @@ -747,6 +761,12 @@ if __name__ == '__main__': global cfStateEstimate_polling_period cfStateEstimate_polling_period = rospy.get_param(ros_namespace + "CrazyRadio/CrazyRadioConfig/cfStateEstimate_polling_period") + global isEnabled_strictSafety + isEnabled_strictSafety = rospy.get_param(ros_namespace + "CrazyRadio/CrazyRadioConfig/isEnabled_strictSafety") + + global maxHeight_for_strictSafety_meters + maxHeight_for_strictSafety_meters = rospy.get_param(ros_namespace + "CrazyRadio/CrazyRadioConfig/maxHeight_for_strictSafety_meters") + # Fetch the YAML paramter "agentID" and "coordID" global m_agentID m_agentID = rospy.get_param(ros_namespace + "/FlyingAgentClient/agentID") diff --git a/dfall_ws/src/dfall_pkg/include/nodes/AgentStatusForWebInterface.h b/dfall_ws/src/dfall_pkg/include/nodes/AgentStatusForWebInterface.h index 48ea108645a10ac252c5dd77e037b3f824e5f449..c7dcef7ef98362f9bd8875a3c153612c31c96fb8 100644 --- a/dfall_ws/src/dfall_pkg/include/nodes/AgentStatusForWebInterface.h +++ b/dfall_ws/src/dfall_pkg/include/nodes/AgentStatusForWebInterface.h @@ -56,6 +56,8 @@ // Include the DFALL message types #include "dfall_pkg/SetpointWithHeader.h" +#include "dfall_pkg/FlyingVehicleState.h" +#include "dfall_pkg/DebugMsg.h" // Include the DFALL service types #include "dfall_pkg/IntStringService.h" @@ -95,6 +97,10 @@ using namespace dfall_pkg; // > as received via messages int m_crazyradio_status = CRAZY_RADIO_STATE_DISCONNECTED; +// The battery level +// > as received via messages +int m_battery_level = BATTERY_LEVEL_UNAVAILABLE; + // The flying state of the agent // > as received via messages int m_agent_operating_state = STATE_UNAVAILABLE; @@ -103,10 +109,6 @@ int m_agent_operating_state = STATE_UNAVAILABLE; // > as received via messages int m_instant_controller = DEFAULT_CONTROLLER; -// The battery level -// > as received via messages -int m_battery_level = BATTERY_LEVEL_UNAVAILABLE; - // The setpoint of the default controller // > as received via messages float m_setpoint_default[4] = {0.0,0.0,0.4,0.0}; @@ -115,6 +117,14 @@ float m_setpoint_default[4] = {0.0,0.0,0.4,0.0}; // > as received via messages float m_setpoint_student[4] = {0.0,0.0,0.4,0.0}; +// The debug values of the student controller +// > as received via messages +float m_debug_values_student[10] = {0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,0.0}; + +// The current state estimate of the Crazyflie +// > as received via messages +float m_cf_state_estimate_xyz_rpy[6] = {0.0,0.0,0.0,0.0,0.0,0.0}; + @@ -137,16 +147,20 @@ float m_setpoint_student[4] = {0.0,0.0,0.4,0.0}; // Callbacks for messages with the status of things: // > For the status of the crazyradio void crazyRadioStatusCallback(const std_msgs::Int32& msg); +// > For the battery level +void newBatteryLevelCallback(const std_msgs::Int32& msg); // > For the flying state of the agent void agentOperatingStateCallback(const std_msgs::Int32& msg); // > For the instant controller void instantControllerChangedCallback(const std_msgs::Int32& msg); -// > For the battery level -void newBatteryLevelCallback(const std_msgs::Int32& msg); // > For the Default Controller Setpoint void defaultControllerSetpointChangedCallback(const SetpointWithHeader& newSetpoint); // > For the Student Controller Setpoint void studentControllerSetpointChangedCallback(const SetpointWithHeader& newSetpoint); +// > For the Student Controller Debug Values +void studentControllerDebugValuesCallback(const DebugMsg& newDebugMsg); +// > For the State Estimate from the Crazyflie +void cfStateEstimateCallback(const FlyingVehicleState & newStateEstimate); // Service callback for providing status to the Web Interface bool statusForWebInterfaceCallback(IntStringService::Request &request, IntStringService::Response &response); \ No newline at end of file diff --git a/dfall_ws/src/dfall_pkg/include/nodes/CrazyRadioEmulator.h b/dfall_ws/src/dfall_pkg/include/nodes/CrazyRadioEmulator.h index 71481271b13d60a1b5d79b65993fb2869e2e9229..a4af6736fc89346d2ec3a7a6aad2ff25b130ee60 100644 --- a/dfall_ws/src/dfall_pkg/include/nodes/CrazyRadioEmulator.h +++ b/dfall_ws/src/dfall_pkg/include/nodes/CrazyRadioEmulator.h @@ -153,6 +153,11 @@ ros::Publisher cfSimulationStatePublisher; // Frequency of requesting the battery voltage, in [seconds] float yaml_battery_polling_period_in_seconds = 0.2f; +// Flag for whether to use height as a trigger for +// publishing a motors-OFF command +bool yaml_isEnabled_strictSafety = true; +float yaml_maxHeight_for_strictSafety_meters = 1.2; + // // Battery thresholds while in the "motors off" state, in [Volts] // float yaml_battery_voltage_threshold_lower_while_standby = 3.30f; // float yaml_battery_voltage_threshold_upper_while_standby = 4.20f; diff --git a/dfall_ws/src/dfall_pkg/include/nodes/StudentControllerService.h b/dfall_ws/src/dfall_pkg/include/nodes/StudentControllerService.h index 67647069d1ddbd9d7e8499ee3acdef9ce9da95b7..bb04171a063e7ee268acf96ec43333676aaddcb1 100644 --- a/dfall_ws/src/dfall_pkg/include/nodes/StudentControllerService.h +++ b/dfall_ws/src/dfall_pkg/include/nodes/StudentControllerService.h @@ -69,7 +69,7 @@ // Include the DFALL service types #include "dfall_pkg/LoadYamlFromFilename.h" #include "dfall_pkg/GetSetpointService.h" -#include "dfall_pkg/GetDebugValuesService.h" +//#include "dfall_pkg/GetDebugValuesService.h" // Include the shared definitions #include "nodes/Constants.h" diff --git a/dfall_ws/src/dfall_pkg/param/CrazyRadioConfig.yaml b/dfall_ws/src/dfall_pkg/param/CrazyRadioConfig.yaml index 88ddd0a794bc2963d7d810abe6ebf13c71b47a19..6f2892f8109d935083d3f34ee6faa7f81c192826 100755 --- a/dfall_ws/src/dfall_pkg/param/CrazyRadioConfig.yaml +++ b/dfall_ws/src/dfall_pkg/param/CrazyRadioConfig.yaml @@ -1,6 +1,10 @@ # Frequency of requesting the onboard state estimate, in [milliseconds] cfStateEstimate_polling_period: 20 +# Flag for whether to use height as a trigger for +# publishing a motors-OFF command +isEnabled_strictSafety: true +maxHeight_for_strictSafety_meters: 1.2 # ----------------------------------------------- # diff --git a/dfall_ws/src/dfall_pkg/src/nodes/AgentStatusForWebInterface.cpp b/dfall_ws/src/dfall_pkg/src/nodes/AgentStatusForWebInterface.cpp index d7718333e1e1ee7fdea6cd736111f7589556f99a..612fd244f8fed4808e77624b15091a7e1964784b 100644 --- a/dfall_ws/src/dfall_pkg/src/nodes/AgentStatusForWebInterface.cpp +++ b/dfall_ws/src/dfall_pkg/src/nodes/AgentStatusForWebInterface.cpp @@ -70,6 +70,11 @@ void crazyRadioStatusCallback(const std_msgs::Int32& msg) m_crazyradio_status = msg.data; } +// > For the battery level +void newBatteryLevelCallback(const std_msgs::Int32& msg) +{ + m_battery_level = msg.data; +} // > For the flying state of the agent void agentOperatingStateCallback(const std_msgs::Int32& msg) @@ -83,12 +88,6 @@ void instantControllerChangedCallback(const std_msgs::Int32& msg) m_instant_controller = msg.data; } -// > For the battery level -void newBatteryLevelCallback(const std_msgs::Int32& msg) -{ - m_battery_level = msg.data; -} - // > For the Default Controller Setpoint void defaultControllerSetpointChangedCallback(const SetpointWithHeader& newSetpoint) { @@ -107,6 +106,34 @@ void studentControllerSetpointChangedCallback(const SetpointWithHeader& newSetpo m_setpoint_student[3] = newSetpoint.yaw; } +// > For the Student Controller Debug Values +void studentControllerDebugValuesCallback(const DebugMsg& newDebugMsg) +{ + m_debug_values_student[0] = newDebugMsg.value_1; + m_debug_values_student[1] = newDebugMsg.value_2; + m_debug_values_student[2] = newDebugMsg.value_3; + m_debug_values_student[3] = newDebugMsg.value_4; + m_debug_values_student[4] = newDebugMsg.value_5; + m_debug_values_student[5] = newDebugMsg.value_6; + m_debug_values_student[6] = newDebugMsg.value_7; + m_debug_values_student[7] = newDebugMsg.value_8; + m_debug_values_student[8] = newDebugMsg.value_9; + m_debug_values_student[9] = newDebugMsg.value_10; +} + +// > For the State Estimate from the Crazyflie +void cfStateEstimateCallback(const FlyingVehicleState & newStateEstimate) +{ + // > For (x,y,z) positions + m_cf_state_estimate_xyz_rpy[0] = newStateEstimate.x; + m_cf_state_estimate_xyz_rpy[1] = newStateEstimate.y; + m_cf_state_estimate_xyz_rpy[2] = newStateEstimate.z; + // > For (roll,pitch,yaw) orientation + m_cf_state_estimate_xyz_rpy[3] = newStateEstimate.roll; + m_cf_state_estimate_xyz_rpy[4] = newStateEstimate.pitch; + m_cf_state_estimate_xyz_rpy[5] = newStateEstimate.yaw; +} + @@ -114,8 +141,8 @@ void studentControllerSetpointChangedCallback(const SetpointWithHeader& newSetpo // SERVICE CALLBACK FOR PROVIDING STATUS TO THE WEB INTERFACE bool statusForWebInterfaceCallback(IntStringService::Request &request, IntStringService::Response &response) { - // Get the statuses as string - str::string crazyradio_status_string; + // Get the CrazyRadio status as a string + std::string crazyradio_status_string; switch (m_crazyradio_status) { case CRAZY_RADIO_STATE_CONNECTED: @@ -140,11 +167,248 @@ bool statusForWebInterfaceCallback(IntStringService::Request &request, IntString } } + + // Get the Battery level as a string + std::string battery_level_string; + switch (m_battery_level) + { + case BATTERY_LEVEL_000: + { + battery_level_string = "000"; + break; + } + case BATTERY_LEVEL_010: + { + battery_level_string = "010"; + break; + } + case BATTERY_LEVEL_020: + { + battery_level_string = "020"; + break; + } + case BATTERY_LEVEL_030: + { + battery_level_string = "030"; + break; + } + case BATTERY_LEVEL_040: + { + battery_level_string = "040"; + break; + } + case BATTERY_LEVEL_050: + { + battery_level_string = "050"; + break; + } + case BATTERY_LEVEL_060: + { + battery_level_string = "060"; + break; + } + case BATTERY_LEVEL_070: + { + battery_level_string = "070"; + break; + } + case BATTERY_LEVEL_080: + { + battery_level_string = "080"; + break; + } + case BATTERY_LEVEL_090: + { + battery_level_string = "090"; + break; + } + case BATTERY_LEVEL_100: + { + battery_level_string = "100"; + break; + } + case BATTERY_LEVEL_UNAVAILABLE: + { + battery_level_string = "unavailable"; + break; + } + default: + { + battery_level_string = "unavailable"; + break; + } + } + + // Get the Flying status as a string + std::string flying_state_string; + switch (m_agent_operating_state) + { + case STATE_MOTORS_OFF: + { + flying_state_string = "motorsoff"; + break; + } + case STATE_TAKE_OFF: + { + flying_state_string = "takeoff"; + break; + } + case STATE_FLYING: + { + flying_state_string = "flying"; + break; + } + case STATE_LAND: + { + flying_state_string = "land"; + break; + } + case STATE_UNAVAILABLE: + { + flying_state_string = "unavailable"; + break; + } + default: + { + flying_state_string = "unavailable"; + break; + } + } + + // Get the Flying status as a string + std::string instant_controller_string; + switch (m_instant_controller) + { + case DEFAULT_CONTROLLER: + { + instant_controller_string = "default"; + break; + } + case DEMO_CONTROLLER: + { + instant_controller_string = "demo"; + break; + } + case STUDENT_CONTROLLER: + { + instant_controller_string = "student"; + break; + } + case MPC_CONTROLLER: + { + instant_controller_string = "mpc"; + break; + } + case REMOTE_CONTROLLER: + { + instant_controller_string = "remote"; + break; + } + case TUNING_CONTROLLER: + { + instant_controller_string = "tuning"; + break; + } + case PICKER_CONTROLLER: + { + instant_controller_string = "picker"; + break; + } + case TEMPLATE_CONTROLLER: + { + instant_controller_string = "template"; + break; + } + case CSONE_CONTROLLER: + { + instant_controller_string = "csone"; + break; + } + case TESTMOTORS_CONTROLLER: + { + instant_controller_string = "testmotors"; + break; + } + default: + { + instant_controller_string = "none"; + break; + } + } + // Concatenate the json together using a string stream std::stringstream ss; - ss << "{\u0022crazyradiostatus\u0022: \u0022" << crazyradio_status_string << "\u0022}"; - //ss << R"({"crazyradiostatus": ")" << m_crazyradio_status << R"("})"; - std::string s = ss.str(); + ss << "{"; + ss << "\u0022crazyradiostatus\u0022: \u0022" << crazyradio_status_string << "\u0022"; + ss << " , "; + ss << "\u0022batterylevel\u0022: \u0022" << battery_level_string << "\u0022"; + ss << " , "; + ss << "\u0022flyingstate\u0022: \u0022" << flying_state_string << "\u0022"; + ss << " , "; + ss << "\u0022instantcontroller\u0022: \u0022" << instant_controller_string << "\u0022"; + ss << " , "; + ss << "\u0022setpointdefault\u0022:"; + ss << "{"; + ss << "\u0022x\u0022: " << std::setprecision(3) << std::fixed << m_setpoint_default[0]; + ss << " , "; + ss << "\u0022y\u0022: " << std::setprecision(3) << std::fixed << m_setpoint_default[1]; + ss << " , "; + ss << "\u0022z\u0022: " << std::setprecision(3) << std::fixed << m_setpoint_default[2]; + ss << " , "; + ss << "\u0022yaw\u0022: " << std::setprecision(1) << std::fixed << m_setpoint_default[3]*RAD2DEG; + ss << "}"; + ss << " , "; + ss << "\u0022setpointstudent\u0022:"; + ss << "{"; + ss << "\u0022x\u0022: " << std::setprecision(3) << std::fixed << m_setpoint_student[0]; + ss << " , "; + ss << "\u0022y\u0022: " << std::setprecision(3) << std::fixed << m_setpoint_student[1]; + ss << " , "; + ss << "\u0022z\u0022: " << std::setprecision(3) << std::fixed << m_setpoint_student[2]; + ss << " , "; + ss << "\u0022yaw\u0022: " << std::setprecision(1) << std::fixed << m_setpoint_student[3]*RAD2DEG; + ss << "}"; + ss << " , "; + ss << "\u0022stateestimate\u0022:"; + ss << "{"; + ss << "\u0022x\u0022: " << std::setprecision(3) << std::fixed << m_cf_state_estimate_xyz_rpy[0]; + ss << " , "; + ss << "\u0022y\u0022: " << std::setprecision(3) << std::fixed << m_cf_state_estimate_xyz_rpy[1]; + ss << " , "; + ss << "\u0022z\u0022: " << std::setprecision(3) << std::fixed << m_cf_state_estimate_xyz_rpy[2]; + ss << " , "; + ss << "\u0022roll\u0022: " << std::setprecision(1) << std::fixed << m_cf_state_estimate_xyz_rpy[3]*RAD2DEG; + ss << " , "; + ss << "\u0022pitch\u0022: " << std::setprecision(1) << std::fixed << m_cf_state_estimate_xyz_rpy[4]*RAD2DEG; + ss << " , "; + ss << "\u0022yaw\u0022: " << std::setprecision(1) << std::fixed << m_cf_state_estimate_xyz_rpy[5]*RAD2DEG; + ss << "}"; + ss << " , "; + ss << "\u0022debugvaluesstudent\u0022:"; + ss << "{"; + ss << "\u0022value1\u0022: " << std::setprecision(3) << std::fixed << m_debug_values_student[0]; + ss << " , "; + ss << "\u0022value2\u0022: " << std::setprecision(3) << std::fixed << m_debug_values_student[1]; + ss << " , "; + ss << "\u0022value3\u0022: " << std::setprecision(3) << std::fixed << m_debug_values_student[2]; + ss << " , "; + ss << "\u0022value4\u0022: " << std::setprecision(3) << std::fixed << m_debug_values_student[3]; + ss << " , "; + ss << "\u0022value5\u0022: " << std::setprecision(3) << std::fixed << m_debug_values_student[4]; + ss << " , "; + ss << "\u0022value6\u0022: " << std::setprecision(3) << std::fixed << m_debug_values_student[5]; + ss << " , "; + ss << "\u0022value7\u0022: " << std::setprecision(3) << std::fixed << m_debug_values_student[6]; + ss << " , "; + ss << "\u0022value8\u0022: " << std::setprecision(3) << std::fixed << m_debug_values_student[7]; + ss << " , "; + ss << "\u0022value9\u0022: " << std::setprecision(3) << std::fixed << m_debug_values_student[8]; + ss << " , "; + ss << "\u0022value10\u0022: " << std::setprecision(3) << std::fixed << m_debug_values_student[9]; + ss << "}"; + ss << "}"; + + //std::string s = ss.str(); // Put the string into the response //response.data = "test of service for web interface"; //response.data = "{\"crazyradiostatus\": \"%d\"}", m_crazyradio_status; @@ -192,6 +456,13 @@ int main(int argc, char* argv[]) // > Subscribe to the topic ros::Subscriber crazyRadioStatusSubscriber = nodeHandle_to_crazyradio.subscribe("CrazyRadioStatus", 1, crazyRadioStatusCallback); + // FOR THE BATTERY LEVEL + // > Get a node handle to the Battery Monitor + std::string namespace_to_BatteryMonitor = m_namespace + "/BatteryMonitor"; + ros::NodeHandle nodeHandle_to_BatteryMonitor(namespace_to_BatteryMonitor); + // > Subscribe to the topic + ros::Subscriber newBatteryLevelSubscriber = nodeHandle_to_BatteryMonitor.subscribe("Level", 1, newBatteryLevelCallback); + // FOR THE FLYING STATE OF THE AGENT // > Get a node handle to the Flying Agent Client std::string namespace_to_FlyingAgentClient = m_namespace + "/FlyingAgentClient"; @@ -203,13 +474,6 @@ int main(int argc, char* argv[]) // > Subscribe to the topic ros::Subscriber instantControllerSubscriber = nodeHandle_to_FlyingAgentClient.subscribe("ControllerUsed", 1, instantControllerChangedCallback); - // FOR THE BATTERY LEVEL - // > Get a node handle to the Battery Monitor - std::string namespace_to_BatteryMonitor = m_namespace + "/BatteryMonitor"; - ros::NodeHandle nodeHandle_to_BatteryMonitor(namespace_to_BatteryMonitor); - // > Subscribe to the topic - ros::Subscriber newBatteryLevelSubscriber = nodeHandle_to_BatteryMonitor.subscribe("Level", 1, newBatteryLevelCallback); - // FOR THE DEFAULT CONTROLLER SETPOINT // > Get a node handle to the Default Controller Service std::string namespace_to_DefaultController = m_namespace + "/DefaultControllerService"; @@ -222,7 +486,18 @@ int main(int argc, char* argv[]) std::string namespace_to_StudentController = m_namespace + "/StudentControllerService"; ros::NodeHandle nodeHandle_to_StudentController(namespace_to_StudentController); // > Subscribe to the topic - ros::Subscriber stuentControllerSetpointChangedSubscriber = nodeHandle_to_StudentController.subscribe("SetpointChanged", 1, studentControllerSetpointChangedCallback); + ros::Subscriber studentControllerSetpointChangedSubscriber = nodeHandle_to_StudentController.subscribe("SetpointChanged", 1, studentControllerSetpointChangedCallback); + + // FOR THE DEBUG VALUES OF THE STUDENT CONTROLLER + // > Subscribe to the topic + ros::Subscriber studentControllerDebugValuesSubscriber = nodeHandle_to_StudentController.subscribe("DebugTopic", 1, studentControllerDebugValuesCallback); + + // FOR THE STATE ESTIMATE FROM THE CRAZYFLIE + // > Get a node handle to the Crazy Radio node + std::string namespace_to_CrazyRadio = m_namespace + "/CrazyRadio"; + ros::NodeHandle nodeHandle_to_CrazyRadio(namespace_to_CrazyRadio); + // > Subscribe to the topic + ros::Subscriber cfStateEstimateSubscriber = nodeHandle_to_CrazyRadio.subscribe("CFStateEstimate", 1, cfStateEstimateCallback); diff --git a/dfall_ws/src/dfall_pkg/src/nodes/CrazyRadioEmulator.cpp b/dfall_ws/src/dfall_pkg/src/nodes/CrazyRadioEmulator.cpp index 87af0d62cd1b02d881af12c44219bf6afb663861..6ce70b498bafb2d42bcd365c82b022f26ea350c2 100644 --- a/dfall_ws/src/dfall_pkg/src/nodes/CrazyRadioEmulator.cpp +++ b/dfall_ws/src/dfall_pkg/src/nodes/CrazyRadioEmulator.cpp @@ -305,6 +305,24 @@ void timerCallback_update_cfStateEstimate(const ros::TimerEvent&) // Simulate the quadrotor for one time step m_quadrotor_sim.simulate_for_one_time_step( yaml_cfSimulation_deltaT_in_seconds ); + // Perform safety check if required + if (yaml_isEnabled_strictSafety) + { + // Estimate the height at the next measurement + float height_at_next_measurement = m_quadrotor_sim.m_position[2] + yaml_cfSimulation_deltaT_in_seconds * m_quadrotor_sim.m_velocity[2]; + // Turn-off if too high + if (height_at_next_measurement > yaml_maxHeight_for_strictSafety_meters) + { + // Send the MOTORS-OFF command to the Flying Agent Client + IntWithHeader msg; + msg.shouldCheckForAgentID = false; + msg.data = CMD_CRAZYFLY_MOTORS_OFF; + flyingAgentClientCommandPublisher.publish(msg); + // Inform the user + ROS_ERROR_STREAM("[CRAZY RADIO] Height safety check failed, measured = " << height_at_next_measurement << ", max allowed = " << yaml_maxHeight_for_strictSafety_meters ); + } + } + // Local variable for the data of this quadrotor FlyingVehicleState quadrotor_data; @@ -467,6 +485,11 @@ void fetchCrazyRadioConfigYamlParameters(ros::NodeHandle& nodeHandle) // Add the "CrazyRadioConfig" namespace to the "nodeHandle" ros::NodeHandle nodeHandle_for_paramaters(nodeHandle, "CrazyRadioConfig"); + // FLAG FOR WHETHER TO USE HEIGHT AS A TRIGGER FOR + // PUBLISHING A MOTORS-OFF COMMAND + yaml_isEnabled_strictSafety = getParameterBool(nodeHandle_for_paramaters,"isEnabled_strictSafety"); + yaml_maxHeight_for_strictSafety_meters = getParameterFloat(nodeHandle_for_paramaters,"maxHeight_for_strictSafety_meters"); + // SIMULATION FREQUENCY FOR EMULATING A CRAZYFLIE [Hertz] float yaml_cfSimulation_frequency = getParameterFloat(nodeHandle_for_paramaters,"cfSimulation_frequency"); diff --git a/dfall_ws/src/dfall_pkg/src/nodes/StudentControllerService.cpp b/dfall_ws/src/dfall_pkg/src/nodes/StudentControllerService.cpp index 424a48dfcc9b4c6c7436bd346ed48663a2f4dcec..20c0131b793834925b081da783f1649bef283811 100644 --- a/dfall_ws/src/dfall_pkg/src/nodes/StudentControllerService.cpp +++ b/dfall_ws/src/dfall_pkg/src/nodes/StudentControllerService.cpp @@ -452,7 +452,10 @@ bool calculateControlOutput(Controller::Request &request, Controller::Response & // The "DebugMsg" type has 10 properties from "value_1" to "value_10", all of // type "float64" that you can fill in with data you would like to plot in // real-time. - // debugMsg.value_1 = thrustAdjustment; + debugMsg.value_1 = thrustAdjustment; + debugMsg.value_2 = rollRate_forResponse; + debugMsg.value_3 = pitchRate_forResponse; + debugMsg.value_4 = yawRate_forResponse; // ...................... // debugMsg.value_10 = your_variable_name; @@ -639,25 +642,6 @@ bool getCurrentSetpointCallback(GetSetpointService::Request &request, GetSetpoin return true; } -// -------------------------------------------------------------------------------- -// DDDD EEEEE BBBB U U GGGG V V A L U U EEEEE SSSS -// D D E B B U U G V V A A L U U E S -// D D EEE BBBB U U G GG V V A A L U U EEE SSS -// D D E B B U U G G V V AAAAA L U U E S -// DDDD EEEEE BBBB UUU GGG V A A LLLLL UUU EEEEE SSSS -// -// CCCC A L L BBBB A CCCC K K -// C A A L L B B A A C K K -// C A A L L BBBB A A C KKK -// C AAAAA L L B B AAAAA C K K -// CCCC A A LLLLL LLLLL BBBB A A CCCC K K -// -------------------------------------------------------------------------------- - -bool getDebugValuesCallback(GetDebugValuesService::Request &request, GetDebugValuesService::Response &response) -{ - // What should I write in this function? Or do the students fill it in depending on what they want to debug? -} - @@ -1101,14 +1085,6 @@ int main(int argc, char* argv[]) { - // Instantiate the local variable "getDebugValuesService" to be - // a "ros::ServiceServer" type variable that advertises the service - // called "GetDebugValues". This service has the input-output - // behaviour defined in the "GetDebugValuesService.srv" file (located - // in the "srv" folder). When a request is made - // of this service the "getDebugValuesCallback" function is called. - ros::ServiceServer getDebugValuesService = nodeHandle.advertiseService("GetDebugValues", getDebugValuesCallback); - // Print out some information to the user. diff --git a/web_interface/html/agent.php b/web_interface/html/agent.php index deee41d2b8afe19661fb2c4b4fc960d5adfc4c2f..6b19f212ddb587e9b57aa7eba4e60362ecaabdda 100644 --- a/web_interface/html/agent.php +++ b/web_interface/html/agent.php @@ -2,6 +2,10 @@ include("page_header.html"); ?> + +<script src="js/sse_agentStatus.js?ver=0.1"></script> + + <div class="full-window-fixed"> </div> @@ -29,8 +33,19 @@ </tr> </table> - <div class="top-bar-title padbelow"> - Agent (IP <?php echo $_SERVER['REMOTE_ADDR']; ?>) + <!-- + <div class="top-bar-title"> + Agent (IP <?php echo $_SERVER['REMOTE_ADDR']; ?>) + </div> + --> + + <div class="top-bar-status-icons padbelow"> + <div class="on-off-switch type2forstatusbar"> + <input type="checkbox" id="checkboxTopBarStatus" onchange=checkboxTopBarStatus_changed()><label for="checkboxTopBarStatus"></label> + </div> + <img id="radio-icon" class="status-icon-radio" src="img/rf_disconnected.png"> + <img id="battery-icon" class="status-icon-battery" src="img/battery_unavailable.png"> + <img id="flying-state-icon" class="status-icon-flying-state" src="img/flying_state_unavailable.png"> </div> </div> diff --git a/web_interface/html/agent_control_tab_default.html b/web_interface/html/agent_control_tab_default.html index 5f92bf87fca9407c5528b48cdf7727e96c6a3978..f187738bbf6fadde4f1a5df6227202c80a1c9a92 100644 --- a/web_interface/html/agent_control_tab_default.html +++ b/web_interface/html/agent_control_tab_default.html @@ -202,5 +202,126 @@ <hr class="hr-basic navy"> +<br> + +<table class="mse-table"> + <tr> + <td></td> + <td class="mse-column-title-cell"> + <span class="mse-column-title-span-full-text">Measured<br>Pose</span> + <span class="mse-column-title-span-short-text">Meas.<br>Pose</span> + </td> + <td class="mse-column-title-cell"> + <span class="mse-column-title-span-full-text">Error</span> + <span class="mse-column-title-span-short-text">Error</span> + </td> + <td class="mse-column-title-cell"> + <span class="mse-column-title-span-full-text">Current<br>Setpoint</span> + <span class="mse-column-title-span-short-text">Curr.<br>Setp.</span> + </td> + </tr> + <tr> + <td class="mse-row-title-cell"> + x + </td> + <td class="mse-data-cell" id="default-measurement-x">xx.xx</td> + <td class="mse-data-cell" id="default-error-x">xx.xx</td> + <td class="mse-data-cell" id="default-setpoint-x">xx.xx</td> + </tr> + <tr> + <td class="mse-row-title-cell"> + y + </td> + <td class="mse-data-cell" id="default-measurement-y">xx.xx</td> + <td class="mse-data-cell" id="default-error-y">xx.xx</td> + <td class="mse-data-cell" id="default-setpoint-y">xx.xx</td> + </tr> + <tr> + <td class="mse-row-title-cell"> + z + </td> + <td class="mse-data-cell" id="default-measurement-z">xx.xx</td> + <td class="mse-data-cell" id="default-error-z">xx.xx</td> + <td class="mse-data-cell" id="default-setpoint-z">xx.xx</td> + </tr> + <tr> + <td class="mse-row-title-cell"> + yaw + </td> + <td class="mse-data-cell" id="default-measurement-yaw">xx.xx</td> + <td class="mse-data-cell" id="default-error-yaw">xx.xx</td> + <td class="mse-data-cell" id="default-setpoint-yaw">xx.xx</td> + </tr> + <tr> + <td class="mse-row-title-cell"> + pitch + </td> + <td class="mse-data-cell" id="default-measurement-pitch">xx.xx</td> + <td></td> + <td></td> + </tr> + <tr> + <td class="mse-row-title-cell"> + roll + </td> + <td class="mse-data-cell" id="default-measurement-roll">xx.xx</td> + <td></td> + <td></td> + </tr> + <tr> + <td colspan="4" class="mse-caption-below"> + <b>NOTES:</b> + </td> + </tr> + <tr> + <td colspan="4" class="mse-caption-below"> + <b>(x,y,z)</b> in meters + </td> + </tr> + <tr> + <td colspan="4" class="mse-caption-below"> + <b>(roll,pitch,yaw)</b> in degrees + </td> + </tr> + <tr> + <td colspan="4" class="mse-caption-below"> + <b>error =</b> measured - setpoint + </td> + </tr> + <tr> + <td colspan="4" class="mse-caption-below"> + <b>~2Hz</b> data refresh rate + </td> + </tr> +</table> + +<br> + +<hr class="hr-basic navy"> + +<table class="git-table"> + <tr> + <td class="git-button-cell"> + <button + class="button-push navy fullwidth" + id="buttonLoadYamlDefault" + onclick="sendRosMessage_outputLabelID('loadyamldefault', 'labelLoadYamlDefault')" + > + Load YAML Paramters for Default Controller + <div class="div-for-button-highlight-on-touchscreen navy"></div> + </button> + </td> + </tr> + <tr> + <td + style="text-align: center;" + id="labelLoadYamlDefault" + > +   + </td> + </tr> +</table> + +<hr class="hr-basic navy"> -<br><br><br><br><br> \ No newline at end of file +<br><br><br><br> \ No newline at end of file diff --git a/web_interface/html/agent_control_tab_student.html b/web_interface/html/agent_control_tab_student.html index 9265271c9cd4be900fa993a825f6ad61d78374d4..57f0f48ec7ddce2e7737de7eee568f4b5ca198bc 100644 --- a/web_interface/html/agent_control_tab_student.html +++ b/web_interface/html/agent_control_tab_student.html @@ -200,51 +200,211 @@ </tr> </table> +<hr class="hr-basic navy"> + <br> -<table class="centered-table"> +<table class="mse-table"> <tr> - <td class="centered-table-button-cell"> - <button - class="button-push navy" - id="buttonGetSetpointStudent" - onclick="getSetpointViaRosServiceCall_outputLabelID('student', 'labelGetSetpointStudent')" - > - get current - <div class="div-for-button-highlight-on-touchscreen navy"></div> - </button> + <td></td> + <td class="mse-column-title-cell"> + <span class="mse-column-title-span-full-text">Measured<br>Pose</span> + <span class="mse-column-title-span-short-text">Meas.<br>Pose</span> + </td> + <td class="mse-column-title-cell"> + <span class="mse-column-title-span-full-text">Error</span> + <span class="mse-column-title-span-short-text">Error</span> + </td> + <td class="mse-column-title-cell"> + <span class="mse-column-title-span-full-text">Current<br>Setpoint</span> + <span class="mse-column-title-span-short-text">Curr.<br>Setp.</span> + </td> + </tr> + <tr> + <td class="mse-row-title-cell"> + x + </td> + <td class="mse-data-cell" id="student-measurement-x">xx.xx</td> + <td class="mse-data-cell" id="student-error-x">xx.xx</td> + <td class="mse-data-cell" id="student-setpoint-x">xx.xx</td> + </tr> + <tr> + <td class="mse-row-title-cell"> + y + </td> + <td class="mse-data-cell" id="student-measurement-y">xx.xx</td> + <td class="mse-data-cell" id="student-error-y">xx.xx</td> + <td class="mse-data-cell" id="student-setpoint-y">xx.xx</td> + </tr> + <tr> + <td class="mse-row-title-cell"> + z + </td> + <td class="mse-data-cell" id="student-measurement-z">xx.xx</td> + <td class="mse-data-cell" id="student-error-z">xx.xx</td> + <td class="mse-data-cell" id="student-setpoint-z">xx.xx</td> + </tr> + <tr> + <td class="mse-row-title-cell"> + yaw + </td> + <td class="mse-data-cell" id="student-measurement-yaw">xx.xx</td> + <td class="mse-data-cell" id="student-error-yaw">xx.xx</td> + <td class="mse-data-cell" id="student-setpoint-yaw">xx.xx</td> + </tr> + <tr> + <td class="mse-row-title-cell"> + pitch + </td> + <td class="mse-data-cell" id="student-measurement-pitch">xx.xx</td> + <td></td> + <td></td> + </tr> + <tr> + <td class="mse-row-title-cell"> + roll </td> - <td class="centered-table-button-cell"> + <td class="mse-data-cell" id="student-measurement-roll">xx.xx</td> + <td></td> + <td></td> + </tr> + <tr> + <td colspan="4" class="mse-caption-below"> + <b>NOTES:</b> + </td> + </tr> + <tr> + <td colspan="4" class="mse-caption-below"> + <b>(x,y,z)</b> in meters + </td> + </tr> + <tr> + <td colspan="4" class="mse-caption-below"> + <b>(roll,pitch,yaw)</b> in degrees + </td> + </tr> + <tr> + <td colspan="4" class="mse-caption-below"> + <b>error =</b> measured - setpoint + </td> + </tr> + <tr> + <td colspan="4" class="mse-caption-below"> + <b>~2Hz</b> data refresh rate + </td> + </tr> +</table> + +<br> + +<hr class="hr-basic navy"> + +<table class="git-table"> + <tr> + <td class="git-button-cell"> <button - class="button-push navy" - id="buttonSetDefaultSetpointStudent" - onclick="putDefaultSetpointForGivenBaseID('inputControlStudentSetpoint')" + class="button-push navy fullwidth" + id="buttonLoadYamlStudent" + onclick="sendRosMessage_outputLabelID('loadyamlstudent', 'labelLoadYamlStudent')" > - put default + Load YAML Paramters for Student Controller <div class="div-for-button-highlight-on-touchscreen navy"></div> </button> </td> </tr> <tr> - <td class="centered-table-button-cell"> - <div - style="text-align: center;" - id="labelGetSetpointStudent" - > -   - </div> + <td + style="text-align: center;" + id="labelLoadYamlStudent" + > +   </td> - <td class="centered-table-button-cell"> - <div - style="text-align: center;" - id="labelSetDeaultSetpointStudent" - > -   - </div> + </tr> +</table> + +<hr class="hr-basic navy"> + +<br> + +<h2 style="text-align: center;"> + Debug Values +</h2> + +<table class="debug-values-table"> + <tr> + <td></td> + <td class="debug-values-row-title-cell"> + Value 1 + </td> + <td class="debug-values-data-cell" id="debug-value1">xx.xx</td> + </tr> + <tr> + <td></td> + <td class="debug-values-row-title-cell"> + Value 2 </td> + <td class="debug-values-data-cell" id="debug-value2">xx.xx</td> + </tr> + <tr> + <td></td> + <td class="debug-values-row-title-cell"> + Value 3 + </td> + <td class="debug-values-data-cell" id="debug-value3">xx.xx</td> + </tr> + <tr> + <td></td> + <td class="debug-values-row-title-cell"> + Value 4 + </td> + <td class="debug-values-data-cell" id="debug-value4">xx.xx</td> + </tr> + <tr> + <td></td> + <td class="debug-values-row-title-cell"> + Value 5 + </td> + <td class="debug-values-data-cell" id="debug-value5">xx.xx</td> + </tr> + <tr> + <td></td> + <td class="debug-values-row-title-cell"> + Value 6 + </td> + <td class="debug-values-data-cell" id="debug-value6">xx.xx</td> + </tr> + <tr> + <td></td> + <td class="debug-values-row-title-cell"> + Value 7 + </td> + <td class="debug-values-data-cell" id="debug-value7">xx.xx</td> + </tr> + <tr> + <td></td> + <td class="debug-values-row-title-cell"> + Value 8 + </td> + <td class="debug-values-data-cell" id="debug-value8">xx.xx</td> + </tr> + <tr> + <td></td> + <td class="debug-values-row-title-cell"> + Value 9 + </td> + <td class="debug-values-data-cell" id="debug-value9">xx.xx</td> + </tr> + <tr> + <td></td> + <td class="debug-values-row-title-cell"> + Value 10 + </td> + <td class="debug-values-data-cell" id="debug-value10">xx.xx</td> </tr> </table> +<br> + <hr class="hr-basic navy"> -<br><br><br><br><br> \ No newline at end of file +<br><br><br><br> \ No newline at end of file diff --git a/web_interface/html/agent_tab_code.html b/web_interface/html/agent_tab_code.html index 08f1127ce1b41025a84c6dec282f11d2e1acaac8..38bf15e74bfc37d23a6e8e4eabb32aa1abee87fc 100644 --- a/web_interface/html/agent_tab_code.html +++ b/web_interface/html/agent_tab_code.html @@ -8,11 +8,16 @@ Upload your code below. <br> <br> - <input class="fileupload" type="file" id="myToUpload" name="fileToUpload"> - <br> - <input type="submit" value="Upload Code" name="submit"> + <input class="fileupload" type="file" id="myToUpload" name="fileToUpload"> + <br> + <input type="submit" value="Upload Code" name="submit"> </form> + <br><br><br> + + <div id="agentStatusDebuggingDiv"></div> + + <br><br> </main> </div> </body> \ No newline at end of file diff --git a/web_interface/html/agent_tab_control.php b/web_interface/html/agent_tab_control.php index 51095d44918a59067b6cba2235cdba42fba11156..77f93a7a5eb3c8308cfdbfed2dd07ba4790367a1 100644 --- a/web_interface/html/agent_tab_control.php +++ b/web_interface/html/agent_tab_control.php @@ -78,7 +78,7 @@ <div class="control-tabs"> <input name="control-tabs" type="radio" id="control-tab-1" checked="checked" class="control-tab-input"/> <label for="control-tab-1" class="control-tab-label">Default</label> - <div class="control-tab-panel"> + <div class="control-tab-panel" id="control-tab-panel-default"> <?php include("agent_control_tab_default.html"); ?> @@ -86,10 +86,12 @@ <input name="control-tabs" type="radio" id="control-tab-2" class="control-tab-input"/> <label for="control-tab-2" class="control-tab-label">Student</label> - <div class="control-tab-panel"> + <div class="control-tab-panel" id="control-tab-panel-student"> <?php include("agent_control_tab_student.html"); ?> </div> -</div> \ No newline at end of file +</div> + +<br> \ No newline at end of file diff --git a/web_interface/html/bashscripts/rosGetStatusJson_forAgent.sh b/web_interface/html/bashscripts/rosGetStatusJson_forAgent.sh new file mode 100755 index 0000000000000000000000000000000000000000..8b2d573e3de679ffbbc3fb87c5c1940879d46b54 --- /dev/null +++ b/web_interface/html/bashscripts/rosGetStatusJson_forAgent.sh @@ -0,0 +1,82 @@ +#!/bin/bash +# +# +# Check whether a command is supplied +# > and put it into a more redable variable +if [ "$#" -eq 0 ]; then + eventid="0" +elif [ "$#" -eq 1 ]; then + eventid=$1 +else + echo "not allowed to supply two or more arguments" + exit 1 +fi +# +# Check that the command supplied is valid +if ! [[ $eventid =~ ^[0-9]*$ ]]; then + echo "event id must be an integer, event id = $1" + exit 1 +fi +# +# Make the ROS commands available +# NOTE: these paths should NOT use ~ +source /opt/ros/melodic/setup.bash +source /home/www-share/dfall/dfall-system/dfall_ws/devel/setup.bash +source /home/www-share/dfall/dfall-system/dfall_ws/src/dfall_pkg/launch/Config.sh +# +# Check that the ROS Master exists +# > Note: the -q options converts the +# grep output to a true/false +if rosnode list | grep -q /rosout; then + # Check if the agent exists + if rosnode list | grep -q "$(printf "/dfall/agent%03d" $DFALL_DEFAULT_AGENT_ID)"; then + # Set a flag that agent was found + agentfound="true" + # Convert the agent ID to a zero padded string + agentnamespace=$(printf "agent%03d" $DFALL_DEFAULT_AGENT_ID) + # Perform the service call for the status json + statusjsonfull="$(rosservice call /$ROS_NAMESPACE/$agentnamespace/AgentStatusForWebInterface/StatusAsJson 0)" + # Cut out the "data: " from the start, and the single " at the end + statusjsoncut1="${statusjsonfull:7:${#statusjsonfull}-8}" + # Remove all new line characters followed by 2 spaces + statusjsoncut2=$(echo $statusjsoncut1|tr -d '\n ') + # Remove all remaining new line characters + statusjsoncut3=$(echo $statusjsoncut2|tr -d '\n') + #statusjsoncut3=${statusjsoncut2//$'\n'/} + # Remove all carriage return characters + statusjsoncut4=$(echo $statusjsoncut3|tr -d '\r') + # Remove all tab characters + statusjsoncut5=$(echo $statusjsoncut4|tr -d '\t') + # Remove all remaining \ escape characters + statusjson=${statusjsoncut5//\\} + # + # Check that the status json is valid based on length + if [ ${#statusjsonfull} -le 1 ]; then + # Set a flag that agent was NOT found + agentfound="false" + # Set all other values to "not available (na)" + statusjson="\"na\"" + fi + # + else + # Set a flag that agent was NOT found + agentfound="false" + # Set all other values to "not available (na)" + statusjson="\"na\"" + fi +else + # Set a flag that agent was NOT found + agentfound="false" + # Set all other values to "not available (na)" + statusjson="\"na\"" +fi + +# Return that the values collected +echo "{"\ + "\"id\": \"$eventid\","\ + "\"agentfound\": \"$agentfound\","\ + "\"statusjson\": $statusjson"\ + "}" + +# DEBUGGING: For testing directly in terminal +# rosservice call /dfall/agent001/AgentStatusForWebInterface/StatusAsJson 0 \ No newline at end of file diff --git a/web_interface/html/bashscripts/rosLoadYaml_forAgent.sh b/web_interface/html/bashscripts/rosLoadYaml_forAgent.sh new file mode 100755 index 0000000000000000000000000000000000000000..d2b2ecbed5f50179201c75a1a88159b2fd7b67b4 --- /dev/null +++ b/web_interface/html/bashscripts/rosLoadYaml_forAgent.sh @@ -0,0 +1,54 @@ +#!/bin/bash +# +# Check that exactly one command is supplied +if [ "$#" -ne 1 ]; then + echo "failed" + exit 1 +fi +# +# Check that the command supplied is valid +if [ "$1" != "default" ] && [ "$1" != "student" ]; then + echo "failed" + exit 1 +fi +# +# Put the command into a variable for make things more readable +command=$1 +# +# Make the ROS commands available +# NOTE: these paths should NOT use ~ +source /opt/ros/melodic/setup.bash +source /home/www-share/dfall/dfall-system/dfall_ws/devel/setup.bash +source /home/www-share/dfall/dfall-system/dfall_ws/src/dfall_pkg/launch/Config.sh +# +# Check that the ROS Master exists +# > Note: the -q options converts the +# grep output to a true/false +if rosnode list | grep -q /rosout; then + # Check if the agent exists + if rosnode list | grep -q "$(printf "/dfall/agent%03d" $DFALL_DEFAULT_AGENT_ID)"; then + # Convert the agent ID to a zero padded string + agentnamespace=$(printf "agent%03d" $DFALL_DEFAULT_AGENT_ID) + # Send the message + if [ "$command" == "default" ]; then + # Publish the request + temp="$(rostopic pub -1 /$ROS_NAMESPACE/$agentnamespace/ParameterService/requestLoadYamlFilename dfall_pkg/StringWithHeader "{data: DefaultController, shouldCheckForAgentID: False}")" + # Return that the message was sent + echo "sent" + # + elif [ "$command" == "student" ]; then + # Publish the request + temp="$(rostopic pub -1 /$ROS_NAMESPACE/$agentnamespace/ParameterService/requestLoadYamlFilename dfall_pkg/StringWithHeader "{data: StudentController, shouldCheckForAgentID: False}")" + # Return that the message was sent + echo "sent" + # + else + # Return that the command is not recognised + echo "controller = $command is not a valid option" + fi + else + echo "Agent $DFALL_DEFAULT_AGENT_ID not found" + fi +else + echo "ROS Master not found" +fi diff --git a/web_interface/html/callBashScript.php b/web_interface/html/callBashScript.php index 0e2b4553cfeb846776035609ba0f7a2a3a68e49b..c3b7401da1783e312ee76e0c0114ebbea26619eb 100644 --- a/web_interface/html/callBashScript.php +++ b/web_interface/html/callBashScript.php @@ -88,6 +88,14 @@ elseif ($scriptname == "rosGetSetpointStudent") { $output = shell_exec("./bashscripts/rosGetCurrentSetpoint_forAgent.sh student"); } + // For the CONTROL tab: + // LOAD YAML PARAMETERS + elseif ($scriptname == "rosLoadYamlDefault") { + $output = shell_exec("./bashscripts/rosLoadYaml_forAgent.sh default"); + } + elseif ($scriptname == "rosLoadYamlStudent") { + $output = shell_exec("./bashscripts/rosLoadYaml_forAgent.sh student"); + } echo "$output"; diff --git a/web_interface/html/checkForRosAgent.php b/web_interface/html/checkForRosAgent.php deleted file mode 100644 index df0985966207e723a7d6c4972e81fdac52620cc4..0000000000000000000000000000000000000000 --- a/web_interface/html/checkForRosAgent.php +++ /dev/null @@ -1,4 +0,0 @@ -<?php - $output = shell_exec("./checkForRosAgent.sh"); - echo "$output"; -?> diff --git a/web_interface/html/checkForRosMaster.php b/web_interface/html/checkForRosMaster.php deleted file mode 100644 index db6b26f8aaac3bce7180f58664f5f2be59430077..0000000000000000000000000000000000000000 --- a/web_interface/html/checkForRosMaster.php +++ /dev/null @@ -1,11 +0,0 @@ -<?php - $output = shell_exec("./checkForRosMaster.sh"); - if ($output == 1) - { - echo "exists"; - } - else - { - echo "not found"; - } -?> diff --git a/web_interface/html/css/buttons.css b/web_interface/html/css/buttons.css index b64a03fab2be3a81058859fac3a9b13e8ac38833..c69685cb5a59749b9a32dca80ac5773b99cd3050 100644 --- a/web_interface/html/css/buttons.css +++ b/web_interface/html/css/buttons.css @@ -1,39 +1,3 @@ -.setpoint-label-cell -{ - margin: 0; - padding-top: 2px; - padding-bottom: 2px; - font-size: 1.4em; - font-weight: bold; - text-align: center; - -} - -.setpoint-increment-cell -{ - margin: 0; - padding-top: 5px; - padding-bottom: 5px; -} - -.setpoint-input-field-cell -{ - margin: 0; - padding-top: 5px; - padding-bottom: 5px; -} - -.setpoint-input-field -{ - width:7em; - margin: 0; - padding-top: 5px; - padding-bottom: 5px; - font-size: 1.4em; - font-family: monospace; - text-align: right; -} - .button-push { position: relative; diff --git a/web_interface/html/css/debug_values_table.css b/web_interface/html/css/debug_values_table.css new file mode 100644 index 0000000000000000000000000000000000000000..81e5fef1c21631861d2121933428323b406b80c5 --- /dev/null +++ b/web_interface/html/css/debug_values_table.css @@ -0,0 +1,91 @@ +.debug-values-table +{ + margin-left: auto; + margin-right: auto; + padding: 0; + border-collapse: collapse; + table-layout: fixed; + //border: 1px solid black; + //border-left: 2px solid black; +} + +.debug-values-column-title-cell +{ + margin: 0; + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + padding-bottom: 2px; + font-size: 1.4em; + font-weight: bold; + text-align: center; + border: 1px solid black; +} + +.debug-values-row-title-cell +{ + margin: 0; + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + padding-bottom: 2px; + font-size: 1.4em; + font-weight: bold; + text-align: center; + border: 1px solid black; +} + +.debug-values-data-cell +{ + margin: 0; + padding-left: 10px; + padding-right: 10px; + padding-top: 2px; + padding-bottom: 2px; + font-size: 1.4em; + font-weight: normal; + font-family: monospace; + text-align: right; + border: 1px solid black; +} + +.debug-values-caption-below +{ + margin: 0; + padding-left: 5px; + padding-right: 5px; + padding-top: 5px; + padding-bottom: 2px; + font-size: 1.2em; + font-weight: normal; + text-align: left; + //border: 1px solid black; +} + + + + + +/* SETTINGS FOR WHEN THE SCREEN IS SMALL */ +@media screen and (max-width: 420px) +{ + .debug-values-column-title-cell + { + font-size: 1.2em; + } + + .debug-values-row-title-cell + { + font-size: 1.2em; + } + + .debug-values-data-cell + { + font-size: 1.2em; + } + + .debug-values-caption-below + { + font-size: 1.0em; + } +} diff --git a/web_interface/html/css/layout.css b/web_interface/html/css/layout.css index b156d1ebe5a7cd30b19e918ecafaaccc13d3415c..ec5d25d4b681939373255158aef2662a3572c310 100644 --- a/web_interface/html/css/layout.css +++ b/web_interface/html/css/layout.css @@ -107,6 +107,26 @@ padding-bottom: 10px; } +.top-bar-status-icons +{ + position: relative; + width: 100%; + text-align: center; + font-size: 1.2em; + font-weight: 400; + padding-top: 0px; + padding-bottom: 0px; + padding-left: 0px; + padding-right: 0px; + background: none; + white-space: nowrap; + overflow-x: hidden; +} +.top-bar-status-icons.padbelow +{ + padding-bottom: 5px; +} + .ros-table { diff --git a/web_interface/html/css/measurement_setpoint_error_table.css b/web_interface/html/css/measurement_setpoint_error_table.css new file mode 100644 index 0000000000000000000000000000000000000000..48f0e7fcb54af2ce368cdb126c0f83b95b59cc44 --- /dev/null +++ b/web_interface/html/css/measurement_setpoint_error_table.css @@ -0,0 +1,151 @@ +.setpoint-label-cell +{ + margin: 0; + padding-top: 2px; + padding-bottom: 2px; + font-size: 1.4em; + font-weight: bold; + text-align: center; +} + +.setpoint-increment-cell +{ + margin: 0; + padding-top: 5px; + padding-bottom: 5px; +} + +.setpoint-input-field-cell +{ + margin: 0; + padding-top: 5px; + padding-bottom: 5px; +} + +.setpoint-input-field +{ + width:7em; + margin: 0; + padding-top: 5px; + padding-bottom: 5px; + font-size: 1.4em; + font-family: monospace; + text-align: right; +} + + + + + +.mse-table +{ + margin-left: auto; + margin-right: auto; + padding: 0; + border-collapse: collapse; + table-layout: fixed; + //border: 1px solid black; + //border-left: 2px solid black; +} + +.mse-column-title-cell +{ + width: 28%; + margin: 0; + padding-left: 5px; + padding-right: 5px; + padding-top: 2px; + padding-bottom: 2px; + font-size: 1.4em; + font-weight: bold; + text-align: center; + border: 1px solid black; +} + +.mse-column-title-span-full-text +{ + display: inline; +} + +.mse-column-title-span-short-text +{ + display: none; +} + +.mse-row-title-cell +{ + margin: 0; + padding-left: 2px; + padding-right: 2px; + padding-top: 2px; + padding-bottom: 2px; + font-size: 1.4em; + font-weight: bold; + text-align: center; + border: 1px solid black; +} + +.mse-data-cell +{ + margin: 0; + padding-left: 5px; + padding-right: 5px; + padding-top: 2px; + padding-bottom: 2px; + font-size: 1.4em; + font-weight: normal; + font-family: monospace; + text-align: right; + border: 1px solid black; +} + +.mse-caption-below +{ + margin: 0; + padding-left: 5px; + padding-right: 5px; + padding-top: 5px; + padding-bottom: 2px; + font-size: 1.2em; + font-weight: normal; + text-align: left; + //border: 1px solid black; +} + + + + + +/* SETTINGS FOR WHEN THE SCREEN IS SMALL */ +@media screen and (max-width: 420px) +{ + .mse-column-title-cell + { + font-size: 1.2em; + } + + .mse-row-title-cell + { + font-size: 1.2em; + } + + .mse-column-title-span-full-text + { + display: none; + } + + .mse-column-title-span-short-text + { + display: inline; + } + + .mse-data-cell + { + font-size: 1.2em; + } + + .mse-caption-below + { + font-size: 1.0em; + } +} diff --git a/web_interface/html/css/status_bar.css b/web_interface/html/css/status_bar.css new file mode 100644 index 0000000000000000000000000000000000000000..936fc8f614551181e7ab24d9340f0797d8d64500 --- /dev/null +++ b/web_interface/html/css/status_bar.css @@ -0,0 +1,71 @@ +.status-icon-radio +{ + height: 40px; + width: 55px; + object-fit: contain; + text-align: center; + margin-left: 0px; + margin-right: 0px; + margin-top: 0px; + margin-bottom: 0px; + padding-left: 10px; + padding-right: 10px; + padding-top: 0px; + padding-bottom: 0px; +} + +.status-icon-battery +{ + height: 40px; + width: 26px; + object-fit: contain; + text-align: center; + margin-left: 0px; + margin-right: 0px; + margin-top: 0px; + margin-bottom: 0px; + padding-left: 10px; + padding-right: 10px; + padding-top: 0px; + padding-bottom: 0px; +} + +.status-icon-flying-state +{ + height: 40px; + width: 51px; + object-fit: contain; + text-align: center; + margin-left: 0px; + margin-right: 0px; + margin-top: 0px; + margin-bottom: 0px; + padding-left: 10px; + padding-right: 10px; + padding-top: 0px; + padding-bottom: 0px; +} + + + +/* SETTINGS FOR WHEN THE SCREEN IS SMALL */ +@media screen and (max-width: 420px) +{ + .status-icon-radio + { + padding-left: 5px; + padding-right: 5px; + } + + .status-icon-battery + { + padding-left: 5px; + padding-right: 5px; + } + + .status-icon-flying-state + { + padding-left: 5px; + padding-right: 5px; + } +} \ No newline at end of file diff --git a/web_interface/html/css/switches.css b/web_interface/html/css/switches.css index 82e09139295f8aeacfc5a9f857264703d1812ab0..2fcdce35b8cce2d5a87c0c5b9a406510ca5ab798 100644 --- a/web_interface/html/css/switches.css +++ b/web_interface/html/css/switches.css @@ -175,6 +175,81 @@ +/* =========================== */ +/* === TYPE 2 === */ +/* =========================== */ +.on-off-switch.type2forstatusbar:after +{ + position: absolute; + top: 0px; + right: 12px; + + content: ''; + + color: #ccc; + font-family: Arial; + font-size: 18px; + line-height: 40px; + font-weight: bold; +} + +.on-off-switch.type2forstatusbar label +{ + width: 70px; + height: 32px; + background: none; + border:3px solid #ccc; + border-radius: 19px; +} + +.on-off-switch.type2forstatusbar label:after +{ + top: 4px; + left: auto; + right: 4px; + overflow: hidden; + + content: 'LIVE'; + + width: 24px; + height: 24px; + + color: #fff; + font-family: Arial; + font-size: 18px; + line-height: 25px; + text-align: center; + font-weight: bold; + text-indent: 80px; + background: #ccc; + box-shadow: none; + border-radius: 12px; + + transform: translateX(-38px); + transition: all 0.4s 0.2s, width 0.2s linear, text-indent 0.4s linear; +} + +.on-off-switch.type2forstatusbar input:checked + label +{ + border-color: #269CE9; +} + +.on-off-switch.type2forstatusbar input:checked + label:after +{ + left: auto; + + width: 62px; + text-indent: 0; + background: #269CE9; + + transform: translateX(0px); + transition: all 0.4s, width 0.2s 0.4s linear, text-indent 0.3s 0.4s linear; +} + + + + + /* =========================== */ /* === TYPE 3 === */ /* =========================== */ diff --git a/web_interface/html/css/tabs_control.css b/web_interface/html/css/tabs_control.css index e02f56e944e701e22a3cbfd33411e983aa4a2fa0..7d0c8c4eaafdef028c7c12526fb3211698513973 100644 --- a/web_interface/html/css/tabs_control.css +++ b/web_interface/html/css/tabs_control.css @@ -70,6 +70,15 @@ color:black; overflow: hidden; overflow-y: scroll; + border-left: 1px solid; + border-right: 1px solid; + border-width: 10px; + border-color: #c43c35; + /* + border-color: #c43c35; + border-color: #f44336; + border-color: #57a957; + */ } /* Make the respective panel visible when its tab-input is checked */ diff --git a/web_interface/html/css/tabs_main.css b/web_interface/html/css/tabs_main.css index 3be20ea54bacb7e767fb3c654d6911524111220f..0fb1582f0727ec220dfd22952aa750e4324112ca 100644 --- a/web_interface/html/css/tabs_main.css +++ b/web_interface/html/css/tabs_main.css @@ -51,6 +51,16 @@ color: #000; } +/* The "top" specification here is critical */ +/* Use: */ +/* 189px when the top banner contains the */ +/* motors-off button and agent IP */ +/* 190px when the top banner contains the */ +/* motors-off button and status */ +/* icons */ +/* 229px when the top banner contains the */ +/* motors-off button, agent IP, and */ +/* status icons. */ .main-tab-panel { order: 99; @@ -60,7 +70,7 @@ bottom: 0; left: 0px; right: 0px; - top: 189px; + top: 190px; bottom: 0px; margin-top: 0px; margin-bottom: 0px; @@ -121,9 +131,19 @@ text-align: center; } + /* The "top" specification here is critical */ + /* Use: */ + /* 147px when the top banner contains the */ + /* motors-off button and agent IP */ + /* 162px when the top banner contains the */ + /* motors-off button and status */ + /* icons */ + /* 190px when the top banner contains the */ + /* motors-off button, agent IP, and */ + /* status icons. */ .main-tab-panel { - top: 147px; + top: 162px; } .main-tab-panel.thin-padding diff --git a/web_interface/html/img/battery_20.png b/web_interface/html/img/battery_20.png new file mode 100644 index 0000000000000000000000000000000000000000..cc7ae62ab7c662f7cf3e098e713232d2d6e0ae14 Binary files /dev/null and b/web_interface/html/img/battery_20.png differ diff --git a/web_interface/html/img/battery_40.png b/web_interface/html/img/battery_40.png new file mode 100644 index 0000000000000000000000000000000000000000..cea5ab35b9605910112dd8a7e2eda371c430894b Binary files /dev/null and b/web_interface/html/img/battery_40.png differ diff --git a/web_interface/html/img/battery_60.png b/web_interface/html/img/battery_60.png new file mode 100644 index 0000000000000000000000000000000000000000..1f75257c3c1f44fc10f318274741942916b47b70 Binary files /dev/null and b/web_interface/html/img/battery_60.png differ diff --git a/web_interface/html/img/battery_80.png b/web_interface/html/img/battery_80.png new file mode 100644 index 0000000000000000000000000000000000000000..8224e7e1e2ed8e251f37f802b14ce4ebd9027f35 Binary files /dev/null and b/web_interface/html/img/battery_80.png differ diff --git a/web_interface/html/img/battery_empty.png b/web_interface/html/img/battery_empty.png new file mode 100644 index 0000000000000000000000000000000000000000..0bf35549aab7c7c0247cebd69a176d68ea67387c Binary files /dev/null and b/web_interface/html/img/battery_empty.png differ diff --git a/web_interface/html/img/battery_full.png b/web_interface/html/img/battery_full.png new file mode 100644 index 0000000000000000000000000000000000000000..495383be5e346e624d7a92670fcf9ddb053f99ef Binary files /dev/null and b/web_interface/html/img/battery_full.png differ diff --git a/web_interface/html/img/battery_unavailable.png b/web_interface/html/img/battery_unavailable.png new file mode 100644 index 0000000000000000000000000000000000000000..71765cfe18b1d7a915b7f92daf06df3b6558521f Binary files /dev/null and b/web_interface/html/img/battery_unavailable.png differ diff --git a/web_interface/html/img/battery_unknown.png b/web_interface/html/img/battery_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..e20348f65a39bac7c0e40a2a4c0b338ef018dc03 Binary files /dev/null and b/web_interface/html/img/battery_unknown.png differ diff --git a/web_interface/html/img/flying_state_disabling.png b/web_interface/html/img/flying_state_disabling.png new file mode 100644 index 0000000000000000000000000000000000000000..667c8027f2b902f08f8e81d3120599a5ed151d48 Binary files /dev/null and b/web_interface/html/img/flying_state_disabling.png differ diff --git a/web_interface/html/img/flying_state_enabling.png b/web_interface/html/img/flying_state_enabling.png new file mode 100644 index 0000000000000000000000000000000000000000..ef2dc5bffa6d27edbb6c6ff1171cd77a5af5c20a Binary files /dev/null and b/web_interface/html/img/flying_state_enabling.png differ diff --git a/web_interface/html/img/flying_state_flying.png b/web_interface/html/img/flying_state_flying.png new file mode 100644 index 0000000000000000000000000000000000000000..b0b51f3d42edbfad9f875c1faa413391c4f21de9 Binary files /dev/null and b/web_interface/html/img/flying_state_flying.png differ diff --git a/web_interface/html/img/flying_state_off.png b/web_interface/html/img/flying_state_off.png new file mode 100644 index 0000000000000000000000000000000000000000..70669664f07c12ef27a41f5b5fb918aff93da688 Binary files /dev/null and b/web_interface/html/img/flying_state_off.png differ diff --git a/web_interface/html/img/flying_state_unavailable.png b/web_interface/html/img/flying_state_unavailable.png new file mode 100644 index 0000000000000000000000000000000000000000..60f6878b603abc0ba5dd375765ff06ad36a397ab Binary files /dev/null and b/web_interface/html/img/flying_state_unavailable.png differ diff --git a/web_interface/html/img/flying_state_unknown.png b/web_interface/html/img/flying_state_unknown.png new file mode 100644 index 0000000000000000000000000000000000000000..5c0c7337a103e5726af53def62e37ad22209c972 Binary files /dev/null and b/web_interface/html/img/flying_state_unknown.png differ diff --git a/web_interface/html/img/rf_connected.png b/web_interface/html/img/rf_connected.png new file mode 100644 index 0000000000000000000000000000000000000000..f9f3580113053f71fe86344e6f34a74e98c17b70 Binary files /dev/null and b/web_interface/html/img/rf_connected.png differ diff --git a/web_interface/html/img/rf_connecting.png b/web_interface/html/img/rf_connecting.png new file mode 100644 index 0000000000000000000000000000000000000000..5f1d4ca1b48496ecf1372e1a0f727058bbc24d95 Binary files /dev/null and b/web_interface/html/img/rf_connecting.png differ diff --git a/web_interface/html/img/rf_disconnected.png b/web_interface/html/img/rf_disconnected.png new file mode 100644 index 0000000000000000000000000000000000000000..0e99e624009059328820b317c908d337caf55ddc Binary files /dev/null and b/web_interface/html/img/rf_disconnected.png differ diff --git a/web_interface/html/js/sendRosMessage.js b/web_interface/html/js/sendRosMessage.js index cabbe8cd70bb54fd558344abff3b2320c1bc15df..91bbd954e73e6fd31048ae6e88d0866ad28f043c 100644 --- a/web_interface/html/js/sendRosMessage.js +++ b/web_interface/html/js/sendRosMessage.js @@ -30,6 +30,15 @@ function sendRosMessage_outputLabelID(rosMessage, labelID) { scriptname_for_php = scriptname_for_php + "rosEnablestudent"; } + else if (rosMessage == "loadyamldefault") + { + scriptname_for_php = scriptname_for_php + "rosLoadYamlDefault"; + } + else if (rosMessage == "loadyamlstudent") + { + scriptname_for_php = scriptname_for_php + "rosLoadYamlStudent"; + } + // Set the label to be sending diff --git a/web_interface/html/js/sse_agentStatus.js b/web_interface/html/js/sse_agentStatus.js new file mode 100644 index 0000000000000000000000000000000000000000..34c1172d463b85763d2f5512174812fbeb2f47d7 --- /dev/null +++ b/web_interface/html/js/sse_agentStatus.js @@ -0,0 +1,468 @@ +let agentStatusEventSource; + +window.onload = function() { + document.getElementById("checkboxTopBarStatus").checked = false; +}; + +function checkboxTopBarStatus_changed() +{ + if ( document.getElementById("checkboxTopBarStatus").checked ) + { + severSentAgentStatus_start(); + } + else + { + severSentAgentStatus_stop(); + } +} + + +function severSentAgentStatus_start() +{ + // Check is server sent events are supported + if (typeof(EventSource) == "undefined") + { + // Server-sent events are NOT supported + // Display this to the user + document.getElementById("agentStatusDebuggingDiv").innerHTML = "Server Sent Events are not supported by this browser."; + return; + } + + // If the code makes it to here, then + // server sent events are supported + + // Create the "EventSource" variable + agentStatusEventSource = new EventSource("sse_agentStatus.php"); + + // Handle the "onopen" event + agentStatusEventSource.onopen = function(eventSource) + { + // DEBUGGING: print out + //document.getElementById("agentStatusDebuggingDiv").innerHTML += "Event: on open <br>"; + }; + + // Handle the "onerror" event + agentStatusEventSource.onerror = function(eventSource) + { + // DEBUGGING: print out + document.getElementById("agentStatusDebuggingDiv").innerHTML += "Event: on error <br>"; + + // Check is the event is still connecting + if (this.readyState == EventSource.CONNECTING) + { + // DEBUGGING: print out + document.getElementById("agentStatusDebuggingDiv").innerHTML += "Reconnecting (readyState = " + this.readyState + ")... <br>"; + } + else + { + // DEBUGGING: print out + document.getElementById("agentStatusDebuggingDiv").innerHTML += "Error has occured. <br>"; + } + }; + + // Handle the "message" event + //agentStatusEventSource.onmessage = function(eventSource) + agentStatusEventSource.addEventListener("message", function(eventSource) + { + // DEBUGGING: print out the whole message + //document.getElementById("agentStatusDebuggingDiv").innerHTML += "Event: message, data: " + eventSource.data + " <br>"; + }); + + // Handle the "ping" event + agentStatusEventSource.addEventListener("agentstatus", function(eventSource) + { + // Extract "agent found" entry in the json + agent_found = JSON.parse(eventSource.data).agentfound; + + // If the agent is found + if ( agent_found === "true" ) + { + // Parse the status dictionary from the JSON + status_dict = JSON.parse(eventSource.data).statusjson; + + // Call the fuctions to update the status icons + // > For the Radio status: + updateStatusIconRadio( status_dict.crazyradiostatus ); + // > For the Battery level: + updateStatusIconBattery( status_dict.batterylevel ); + // > For the Flying state: + updateStatusIconFlyingState( status_dict.flyingstate ); + // > For the Instant controller: + updateStatusForInstantController( status_dict.instantcontroller ); + + // Call the function to update the "measurement, + // setpoint, error" tables + // > For the Default controller: + updateDefaultMseTable( status_dict.stateestimate , status_dict.setpointdefault ); + // > For the Student controller: + updateStudentMseTable( status_dict.stateestimate , status_dict.setpointstudent ); + + // Call the function to update the "debug values" table + updateStudentDebugValuesTable( status_dict.debugvaluesstudent ); + + // DEBUGGING: print out the whole message + //document.getElementById("agentStatusDebuggingDiv").innerHTML += "Event: agent status, data: " + eventSource.data + " <br>"; + } + // Otherwise, the agent is NOT found + else + { + // So set all the icons accordingly + // > For the Radio status: + updateStatusIconRadio( "disconnected" ); + // > For the Battery level: + updateStatusIconBattery( "unavailable" ); + // > For the Flying state: + updateStatusIconFlyingState( "unavailable" ); + // > For the Instant controller: + updateStatusForInstantController( "none" ); + + // Call the function to clear the "measurement, + // setpoint, error" tables + // > For the Default controller: + clearDefaultMseTable(); + // > For the Student controller: + clearStudentMseTable(); + + // Call the function to clear the "debug values" table + clearStudentDebugValuesTable(); + + // DEBUGGING: print out the whole message + //document.getElementById("agentStatusDebuggingDiv").innerHTML += "Event: agent status, data: " + eventSource.data + " <br>"; + } + }); + +} // END OF: function severSentAgentStatus_start() + + + + + +function severSentAgentStatus_stop() +{ + // Check is server sent events are supported + if (typeof(EventSource) == "undefined") + { + // Server-sent events are NOT supported + // Display this to the user + document.getElementById("agentStatusDebuggingDiv").innerHTML = "Server Sent Events are not supported by this browser."; + return; + } + + // If the code makes it to here, then + // server sent events are supported + + // Close the "EventSource" variable + agentStatusEventSource.close(); + + // DEBUGGING: print out + //document.getElementById("agentStatusDebuggingDiv").innerHTML += "Closed. <br>"; + + // So set all the icons accordingly + // > For the Radio status: + updateStatusIconRadio( "disconnected" ); + // > For the Battery level: + updateStatusIconBattery( "unavailable" ); + // > For the Flying state: + updateStatusIconFlyingState( "unavailable" ); + // > For the Instant controller: + updateStatusForInstantController( "none" ); + + // Call the function to clear the "measurement, + // setpoint, error" tables + // > For the Default controller: + clearDefaultMseTable(); + // > For the Student controller: + clearStudentMseTable(); + + // Call the function to clear the "debug values" table + clearStudentDebugValuesTable(); + +} // END OF: function severSentAgentStatus_stop() + + + +function updateStatusIconRadio( status_string ) +{ + if ( typeof status_string !== "string" ) + { + // Default to disconnected + status_string = "disconnected"; + } + + switch ( status_string.toLowerCase() ) + { + case "connected": + document.getElementById("radio-icon").src = "img/rf_connected.png"; + break; + case "connecting": + document.getElementById("radio-icon").src = "img/rf_connecting.png"; + break; + case "disconnected": + document.getElementById("radio-icon").src = "img/rf_disconnected.png"; + break; + default: + document.getElementById("radio-icon").src = "img/rf_disconnected.png"; + } + +} // END OF: "function updateStatusIconRadio( status_string )" + + + +function updateStatusIconBattery( level_string ) +{ + if ( typeof level_string !== "string" ) + { + // Default to unavailable + level_string = "unavailable"; + } + + switch ( level_string.toLowerCase() ) + { + case "000": + document.getElementById("battery-icon").src = "img/battery_empty.png"; + break; + case "010": + document.getElementById("battery-icon").src = "img/battery_20.png"; + break; + case "020": + document.getElementById("battery-icon").src = "img/battery_20.png"; + break; + case "030": + document.getElementById("battery-icon").src = "img/battery_40.png"; + break; + case "040": + document.getElementById("battery-icon").src = "img/battery_40.png"; + break; + case "050": + document.getElementById("battery-icon").src = "img/battery_60.png"; + break; + case "060": + document.getElementById("battery-icon").src = "img/battery_60.png"; + break; + case "070": + document.getElementById("battery-icon").src = "img/battery_80.png"; + break; + case "080": + document.getElementById("battery-icon").src = "img/battery_80.png"; + break; + case "090": + document.getElementById("battery-icon").src = "img/battery_full.png"; + break; + case "100": + document.getElementById("battery-icon").src = "img/battery_full.png"; + break; + case "unknown": + document.getElementById("battery-icon").src = "img/battery_unknown.png"; + break; + case "unavailable": + document.getElementById("battery-icon").src = "img/battery_unavailable.png"; + break; + default: + document.getElementById("battery-icon").src = "img/battery_unavailable.png"; + } + +} // END OF: "function updateStatusIconBattery( level_string )" + + + +function updateStatusIconFlyingState( state_string ) +{ + if ( typeof state_string !== "string" ) + { + // Default to unavailable + state_string = "unavailable"; + } + + switch ( state_string.toLowerCase() ) + { + case "motorsoff": + document.getElementById("flying-state-icon").src = "img/flying_state_off.png"; + break; + case "takeoff": + document.getElementById("flying-state-icon").src = "img/flying_state_enabling.png"; + break; + case "flying": + document.getElementById("flying-state-icon").src = "img/flying_state_flying.png"; + break; + case "land": + document.getElementById("flying-state-icon").src = "img/flying_state_disabling.png"; + break; + case "unavailable": + document.getElementById("flying-state-icon").src = "img/flying_state_unavailable.png"; + break; + default: + document.getElementById("flying-state-icon").src = "img/flying_state_unavailable.png"; + } + +} // END OF: "function updateStatusIconRadio( status_string )" + + + +function updateStatusForInstantController( controller_string ) +{ + if ( typeof controller_string !== "string" ) + { + // Default to unavailable + controller_string = "none"; + } + + // Colours: + // #c43c35 Dark Red + // #f44336 Light Red + // #57a957 Green + + // Set all border colours to red + document.getElementById("control-tab-panel-default").style.borderColor = "#c43c35"; + document.getElementById("control-tab-panel-student").style.borderColor = "#c43c35"; + + switch ( controller_string.toLowerCase() ) + { + case "default": + document.getElementById("control-tab-panel-default").style.borderColor = "#57a957"; + break; + case "student": + document.getElementById("control-tab-panel-student").style.borderColor = "#57a957"; + break; + } + +} // END OF: "function updateStatusIconRadio( status_string )" + + +function updateDefaultMseTable( measurement_dict , setpoint_dict ) +{ + if ( (typeof measurement_dict !== "object") || (typeof setpoint_dict !== "object") ) + { + // Call function to set fields to blank + clearDefaultMseTable(); + return; + } + + document.getElementById("default-measurement-x").innerHTML = measurement_dict.x.toFixed(3); + document.getElementById("default-measurement-y").innerHTML = measurement_dict.y.toFixed(3); + document.getElementById("default-measurement-z").innerHTML = measurement_dict.z.toFixed(3); + document.getElementById("default-measurement-yaw").innerHTML = measurement_dict.yaw.toFixed(3); + document.getElementById("default-measurement-pitch").innerHTML = measurement_dict.pitch.toFixed(1); + document.getElementById("default-measurement-roll").innerHTML = measurement_dict.roll.toFixed(1); + + document.getElementById("default-setpoint-x").innerHTML = setpoint_dict.x.toFixed(3); + document.getElementById("default-setpoint-y").innerHTML = setpoint_dict.y.toFixed(3); + document.getElementById("default-setpoint-z").innerHTML = setpoint_dict.z.toFixed(3); + document.getElementById("default-setpoint-yaw").innerHTML = setpoint_dict.yaw.toFixed(1); + + document.getElementById("default-error-x").innerHTML = (measurement_dict.x -setpoint_dict.x ).toFixed(3); + document.getElementById("default-error-y").innerHTML = (measurement_dict.y -setpoint_dict.y ).toFixed(3); + document.getElementById("default-error-z").innerHTML = (measurement_dict.z -setpoint_dict.z ).toFixed(3); + document.getElementById("default-error-yaw").innerHTML = (measurement_dict.yaw-setpoint_dict.yaw).toFixed(1); + +} // END OF: "function updateDefaultMseTable( measurement_dict , setpoint_dict )" + +function clearDefaultMseTable() +{ + document.getElementById("default-measurement-x").innerHTML = "xx.xx"; + document.getElementById("default-measurement-y").innerHTML = "xx.xx"; + document.getElementById("default-measurement-z").innerHTML = "xx.xx"; + document.getElementById("default-measurement-yaw").innerHTML = "xx.xx"; + document.getElementById("default-measurement-pitch").innerHTML = "xx.xx"; + document.getElementById("default-measurement-roll").innerHTML = "xx.xx"; + + document.getElementById("default-setpoint-x").innerHTML = "xx.xx"; + document.getElementById("default-setpoint-y").innerHTML = "xx.xx"; + document.getElementById("default-setpoint-z").innerHTML = "xx.xx"; + document.getElementById("default-setpoint-yaw").innerHTML = "xx.xx"; + + document.getElementById("default-error-x").innerHTML = "xx.xx"; + document.getElementById("default-error-y").innerHTML = "xx.xx"; + document.getElementById("default-error-z").innerHTML = "xx.xx"; + document.getElementById("default-error-yaw").innerHTML = "xx.xx"; + +} // END OF: "function clearDefaultMseTable()" + + + +function updateStudentMseTable( measurement_dict , setpoint_dict ) +{ + if ( (typeof measurement_dict !== "object") || (typeof setpoint_dict !== "object") ) + { + // Call function to set fields to blank + clearStudentMseTable(); + return; + } + + document.getElementById("student-measurement-x").innerHTML = measurement_dict.x.toFixed(3); + document.getElementById("student-measurement-y").innerHTML = measurement_dict.y.toFixed(3); + document.getElementById("student-measurement-z").innerHTML = measurement_dict.z.toFixed(3); + document.getElementById("student-measurement-yaw").innerHTML = measurement_dict.yaw.toFixed(3); + document.getElementById("student-measurement-pitch").innerHTML = measurement_dict.pitch.toFixed(1); + document.getElementById("student-measurement-roll").innerHTML = measurement_dict.roll.toFixed(1); + + document.getElementById("student-setpoint-x").innerHTML = setpoint_dict.x.toFixed(3); + document.getElementById("student-setpoint-y").innerHTML = setpoint_dict.y.toFixed(3); + document.getElementById("student-setpoint-z").innerHTML = setpoint_dict.z.toFixed(3); + document.getElementById("student-setpoint-yaw").innerHTML = setpoint_dict.yaw.toFixed(1); + + document.getElementById("student-error-x").innerHTML = (measurement_dict.x -setpoint_dict.x ).toFixed(3); + document.getElementById("student-error-y").innerHTML = (measurement_dict.y -setpoint_dict.y ).toFixed(3); + document.getElementById("student-error-z").innerHTML = (measurement_dict.z -setpoint_dict.z ).toFixed(3); + document.getElementById("student-error-yaw").innerHTML = (measurement_dict.yaw-setpoint_dict.yaw).toFixed(1); + +} // END OF: "function updateStudentMseTable( measurement_dict , setpoint_dict )" + +function clearStudentMseTable() +{ + document.getElementById("student-measurement-x").innerHTML = "xx.xx"; + document.getElementById("student-measurement-y").innerHTML = "xx.xx"; + document.getElementById("student-measurement-z").innerHTML = "xx.xx"; + document.getElementById("student-measurement-yaw").innerHTML = "xx.xx"; + document.getElementById("student-measurement-pitch").innerHTML = "xx.xx"; + document.getElementById("student-measurement-roll").innerHTML = "xx.xx"; + + document.getElementById("student-setpoint-x").innerHTML = "xx.xx"; + document.getElementById("student-setpoint-y").innerHTML = "xx.xx"; + document.getElementById("student-setpoint-z").innerHTML = "xx.xx"; + document.getElementById("student-setpoint-yaw").innerHTML = "xx.xx"; + + document.getElementById("student-error-x").innerHTML = "xx.xx"; + document.getElementById("student-error-y").innerHTML = "xx.xx"; + document.getElementById("student-error-z").innerHTML = "xx.xx"; + document.getElementById("student-error-yaw").innerHTML = "xx.xx"; + +} // END OF: "function clearStudentMseTable()" + + + + +function updateStudentDebugValuesTable( values_dict ) +{ + if (typeof values_dict !== "object") + { + // Call function to set fields to blank + clearStudentDebugValuesTable(); + return; + } + + document.getElementById("debug-value1").innerHTML = values_dict.value1.toFixed(3); + document.getElementById("debug-value2").innerHTML = values_dict.value2.toFixed(3); + document.getElementById("debug-value3").innerHTML = values_dict.value3.toFixed(3); + document.getElementById("debug-value4").innerHTML = values_dict.value4.toFixed(3); + document.getElementById("debug-value5").innerHTML = values_dict.value5.toFixed(3); + document.getElementById("debug-value6").innerHTML = values_dict.value6.toFixed(3); + document.getElementById("debug-value7").innerHTML = values_dict.value7.toFixed(3); + document.getElementById("debug-value8").innerHTML = values_dict.value8.toFixed(3); + document.getElementById("debug-value9").innerHTML = values_dict.value9.toFixed(3); + document.getElementById("debug-value10").innerHTML = values_dict.value10.toFixed(3); + +} // END OF: "function updateStudentDebugValuesTable( values_dict )" + +function clearStudentDebugValuesTable() +{ + document.getElementById("debug-value1").innerHTML = "xx.xx"; + document.getElementById("debug-value2").innerHTML = "xx.xx"; + document.getElementById("debug-value3").innerHTML = "xx.xx"; + document.getElementById("debug-value4").innerHTML = "xx.xx"; + document.getElementById("debug-value5").innerHTML = "xx.xx"; + document.getElementById("debug-value6").innerHTML = "xx.xx"; + document.getElementById("debug-value7").innerHTML = "xx.xx"; + document.getElementById("debug-value8").innerHTML = "xx.xx"; + document.getElementById("debug-value9").innerHTML = "xx.xx"; + document.getElementById("debug-value10").innerHTML = "xx.xx"; +} // END OF: "function clearStudentDebugValuesTable()" \ No newline at end of file diff --git a/web_interface/html/killRosAgent.php b/web_interface/html/killRosAgent.php deleted file mode 100644 index 4d727404030fb6f1780a5cd411e9036950ef479e..0000000000000000000000000000000000000000 --- a/web_interface/html/killRosAgent.php +++ /dev/null @@ -1,4 +0,0 @@ -<?php - $output = shell_exec("./killRosAgent.sh"); - echo "$output"; -?> diff --git a/web_interface/html/launchRosAgent.php b/web_interface/html/launchRosAgent.php deleted file mode 100644 index 8b39f485a2e3756945a6906ef12c0271b9243099..0000000000000000000000000000000000000000 --- a/web_interface/html/launchRosAgent.php +++ /dev/null @@ -1,4 +0,0 @@ -<?php - $output = shell_exec("./launchRosAgent.sh"); - echo "<pre>$output</pre>"; -?> diff --git a/web_interface/html/page_header.html b/web_interface/html/page_header.html index a2377b8ca6218f171f9141aa73e1149366618421..92c815de57e633259c3d13f5dde29ac9a0bf94e4 100644 --- a/web_interface/html/page_header.html +++ b/web_interface/html/page_header.html @@ -27,7 +27,9 @@ <link rel="stylesheet" type="text/css" href="css/tabs_main.css?ver=0.1" /> <link rel="stylesheet" type="text/css" href="css/tabs_home.css?ver=0.1" /> <link rel="stylesheet" type="text/css" href="css/tabs_control.css?ver=0.1" /> - + <link rel="stylesheet" type="text/css" href="css/status_bar.css?ver=0.1" /> + <link rel="stylesheet" type="text/css" href="css/measurement_setpoint_error_table.css?ver=0.1" /> + <link rel="stylesheet" type="text/css" href="css/debug_values_table.css?ver=0.1" /> <!-- Link the JavaScript files --> <script src="js/general.js?ver=0.1"></script> diff --git a/web_interface/html/rosnodeList.php b/web_interface/html/rosnodeList.php deleted file mode 100644 index c0e0db444d6dcf9934b016d9bc9a2c193e4f06f3..0000000000000000000000000000000000000000 --- a/web_interface/html/rosnodeList.php +++ /dev/null @@ -1,4 +0,0 @@ -<?php - $output = shell_exec("./rosnodeList.sh"); - echo "<pre>$output</pre>"; -?> diff --git a/web_interface/html/sse_agentStatus.php b/web_interface/html/sse_agentStatus.php new file mode 100644 index 0000000000000000000000000000000000000000..60eeed050c0c046e9bd82d49ff6cc8b688679296 --- /dev/null +++ b/web_interface/html/sse_agentStatus.php @@ -0,0 +1,30 @@ + <?php + //date_default_timezone_set("America/New_York"); + header("Cache-Control: no-cache"); + header("Content-Type: text/event-stream"); + //header('Connection: keep-alive'); + + $event_id_counter = 0; + + while (true) { + // Every second, send a "ping" event. + + echo "event: agentstatus\n"; + + $output = shell_exec("./bashscripts/rosGetStatusJson_forAgent.sh " . $event_id_counter); + + //$curDate = date(DATE_ISO8601); + //echo 'data: {"time": "' . $curDate . '"}'; + + echo "data: $output"; + echo "\n\n"; + + // Send a simple message at random intervals. + + $event_id_counter++; + + ob_end_flush(); + flush(); + usleep(250000); + } +?> \ No newline at end of file diff --git a/web_interface/html/temp.html b/web_interface/html/temp.html deleted file mode 100644 index 35a7651986794ee20dedc5b6b320559ab65934ff..0000000000000000000000000000000000000000 --- a/web_interface/html/temp.html +++ /dev/null @@ -1,69 +0,0 @@ - <?php echo "hello world"; ?> - - <?php echo '<br>'; ?> - - <?php echo date('Y-m-d H:i:s'); ?> - - <?php echo '<br>'; ?> - - <!-- <?php phpinfo(); ?> --> - - - <?php - // outputs the username that owns the running php/httpd process - // (on a system with the "whoami" executable in the path) - echo exec('whoami'); - ?> - - <?php echo '<br>'; ?> - - - - <?php - $output = shell_exec("ls -lart"); - echo "<pre>$output</pre>"; - ?> - - <?php echo '<br>'; ?> - - <!-- - <?php - $output = shell_exec("./rosnode_list.sh"); - echo "<pre>$output</pre>"; - ?> - --> - - <?php echo '<br>'; ?> - - <!--$output = shell_exec("./roscore.sh");--> - <!--$output = shell_exec("nohup ./roscore.sh > /dev/null &");--> - - <?php echo '<br>'; ?> - - <!-- - <?php - $output = shell_exec("./rosnode_list.sh"); - echo "<pre>$output</pre>"; - ?> - --> - - <?php echo '<br>'; ?> - - <!-- - <?php - $output = shell_exec("source /opt/ros/melodic/setup.bash"); - echo "<pre>$output</pre>"; - $outputtwo = shell_exec("rosnode list"); - echo "<pre>$outputtwo</pre>"; - ?> - --> - - <?php echo '<br>'; ?> - - <!-- - <?php - exec("dir", $output, $return); - echo "Dir returned $return, and output:\n"; - var_dump($output); - ?> - -->