Skip to content

Commit

Permalink
[Software][Cyclope controller] Added a watchdog timer that needs to b…
Browse files Browse the repository at this point in the history
…e cleared repeatedly by the opened web page to avoid stopping the robot.

This watchdog triggers when the web server connection is lost and immediately stops the robot.
  • Loading branch information
RICCIARDI-Adrien committed Dec 20, 2024
1 parent a68406e commit 2663a35
Showing 1 changed file with 51 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@
*/
#include <ArtificialIntelligenceProgramManager.hpp>
#include <Adc.hpp>
#include <cerrno>
#include <cstring>
#include <Lidar.hpp>
#include <Light.hpp>
#include <Log.hpp>
#include <microhttpd.h>
#include <Motor.hpp>
#include <signal.h>
#include <stdexcept>
#include <unordered_map>
#include <WebPageExecuteProgram.hpp>
Expand All @@ -20,15 +23,20 @@

namespace WebServer
{
/** The watchdog will fire if it is not cleared for this amount of time. */
constexpr unsigned int WATCHDOG_TIMEOUT_SECONDS = 3;
/** The watchdog is cleared at this rate, granting that it will never fire. */
constexpr unsigned int WATCHDOG_CLEAR_PERIOD = 1;

/** All available commands the user can send. */
typedef enum
{
WEB_SERVER_COMMUNICATION_PROTOCOL_COMMAND_SET_MOTION,
WEB_SERVER_COMMUNICATION_PROTOCOL_COMMAND_GET_BATTERY_VOLTAGE,
WEB_SERVER_COMMUNICATION_PROTOCOL_COMMAND_SET_LIGHT_ENABLED,
WEB_SERVER_COMMUNICATION_PROTOCOL_COMMAND_STOP_CURRENT_AI_PROGRAM,
WEB_SERVER_COMMUNICATION_PROTOCOL_COMMAND_SET_STREAMING_CAMERA_ENABLED,
WEB_SERVER_COMMUNICATION_PROTOCOL_COMMANDS_COUNT
WEB_SERVER_COMMUNICATION_PROTOCOL_COMMAND_CLEAR_WATCHDOG,
WEB_SERVER_COMMUNICATION_PROTOCOL_COMMAND_SET_STREAMING_CAMERA_ENABLED
} WebServerCommunicationProtocolCommand;

/** The server handle. */
Expand Down Expand Up @@ -92,7 +100,8 @@ namespace WebServer
" COMMUNICATION_PROTOCOL_COMMAND_SET_MOTION: '0',\n"
" COMMUNICATION_PROTOCOL_COMMAND_GET_BATTERY_VOLTAGE: '1',\n"
" COMMUNICATION_PROTOCOL_COMMAND_SET_LIGHT_ENABLED: '2',\n"
" COMMUNICATION_PROTOCOL_COMMAND_STOP_CURRENT_AI_PROGRAM: '3'\n"
" COMMUNICATION_PROTOCOL_COMMAND_STOP_CURRENT_AI_PROGRAM: '3',\n"
" COMMUNICATION_PROTOCOL_COMMAND_CLEAR_WATCHDOG: '4'\n"
" }\n"
"\n"
" const RobotMotion =\n"
Expand Down Expand Up @@ -122,6 +131,13 @@ namespace WebServer
" userInterfaceControl = document.getElementById(htmlElementId);\n"
" userInterfaceControl.innerHTML = text;\n"
" }\n"
"\n"
" function feedWatchdog()\n"
" {\n"
" command = CommunicationProtocol.COMMUNICATION_PROTOCOL_COMMAND_CLEAR_WATCHDOG;\n"
" communicationProtocolSendCommand(command);\n"
" }\n"
" setInterval(feedWatchdog, " + std::to_string(WATCHDOG_CLEAR_PERIOD * 1000) + ");\n"
" </script>\n";
}

Expand Down Expand Up @@ -232,6 +248,10 @@ namespace WebServer
ArtificialIntelligenceProgramManager::stopRunningProgram();
break;

case WEB_SERVER_COMMUNICATION_PROTOCOL_COMMAND_CLEAR_WATCHDOG:
alarm(WATCHDOG_TIMEOUT_SECONDS); // Reset the watchdog
break;

default:
LOG(LOG_ERR, "Unknown command '%c'.", pointerStringCommand[0]);
return -1;
Expand Down Expand Up @@ -394,8 +414,36 @@ namespace WebServer
return returnValue;
}

/** Called when the watchdog fires. */
static void _watchogSignalHandler(int)
{
LOG(LOG_WARNING, "The watchdog fired, stopping the robot.");

// Stop the currently running AI program (if any)
ArtificialIntelligenceProgramManager::stopRunningProgram();

// Stop the robot to be sure
Motor::setRobotMotion(Motor::ROBOT_MOTION_STOP);
Lidar::setEnabled(false);
Light::setEnabled(false);

// Stop the watchdog to avoid it retrigger itself continuously
int result = alarm(0);
if (result < 0) LOG(LOG_ERR, "Failed to disable the watchdog (%s).", strerror(errno));
}

int initialize()
{
// Create the event handler that will be called if the watchdog fires
struct sigaction signalAction{};
signalAction.sa_handler = _watchogSignalHandler;
int result = sigaction(SIGALRM, &signalAction, nullptr);
if (result < 0)
{
LOG(LOG_ERR, "Error : failed to install the SIGALRM handler (%s).", strerror(errno));
return -1;
}

// Start the web server daemon and configure it to accept connections from any IP
_pointerServerHandle = MHD_start_daemon(MHD_USE_THREAD_PER_CONNECTION, 80, NULL, NULL, _accessHandlerCallback, NULL, MHD_OPTION_END);
if (_pointerServerHandle == NULL)
Expand Down

0 comments on commit 2663a35

Please sign in to comment.