Skip to content
This repository was archived by the owner on Jul 25, 2022. It is now read-only.

Commit 8ce6f8f

Browse files
committed
Finished outsourcing code out of main file.
2 parents 36870ed + a4e2c2e commit 8ce6f8f

File tree

7 files changed

+208
-120
lines changed

7 files changed

+208
-120
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,3 +63,4 @@ Software
6363

6464
The source code is written in C++. It is compiled and programmed with the [Arduino IDE](https://www.arduino.cc/en/Main/Software). The [board support package for the ESP8266 chip](https://github.com/esp8266/Arduino) must be installed.
6565
The [Arduino library VL53L1](https://github.com/stm32duino/VL53L1) must be installed.
66+
The [SimplyAtomic library](https://github.com/wizard97/SimplyAtomic) must be installed.

robot-control-src/Drives.hpp

Lines changed: 1 addition & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,24 +2,11 @@
22
#define DRIVES_HPP
33

44
#include "board.hpp"
5+
#include "EnvironmentRecord.hpp"
56
#include <algorithm>
67
#include <cstdint>
78
#include <Arduino.h>
89

9-
using Distance = std::int16_t; //!< in [mm]
10-
struct Position
11-
{
12-
Distance x, y;
13-
bool operator==(const Position& rhs) const
14-
{
15-
return x == rhs.x && y == rhs.y;
16-
}
17-
bool operator!=(const Position& rhs) const
18-
{
19-
return !(*this == rhs);
20-
}
21-
};
22-
2310
namespace drives
2411
{
2512

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
#include "EnvironmentRecord.hpp"
2+
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
#ifndef ROBOT_CONTROL_SRC_ENVIRONMENTRECORD_HPP_
2+
#define ROBOT_CONTROL_SRC_ENVIRONMENTRECORD_HPP_
3+
4+
#include <cstddef>
5+
#include <cstdint>
6+
7+
using Distance = std::int16_t; //!< in [mm]
8+
struct Position
9+
{
10+
Distance x, y;
11+
bool operator==(const Position& rhs) const
12+
{
13+
return x == rhs.x && y == rhs.y;
14+
}
15+
bool operator!=(const Position& rhs) const
16+
{
17+
return !(*this == rhs);
18+
}
19+
};
20+
21+
struct EnvironmentRecord {
22+
static constexpr std::size_t numberOfPositions = 50;
23+
Position positions[numberOfPositions] = { {0,0} };
24+
std::size_t positionIndex = 0;
25+
};
26+
27+
#endif /* ROBOT_CONTROL_SRC_ENVIRONMENTRECORD_HPP_ */

robot-control-src/WebserverHandle.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#include "WebserverHandle.hpp"
2+
#include "library_extension.hpp"
3+
#include "board.hpp"
4+
#include <assert.h>
5+
#include <cstddef>
6+
#include <SimplyAtomic.h>
7+
8+
static constexpr char htmlSourceTemplate[] =
9+
"<!DOCTYPE html>\n"
10+
"<html lang=\"en\">\n"
11+
" <head>\n"
12+
" <title>Robot Control</title>\n"
13+
" <meta charset=\"utf-8\" />\n"
14+
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.6\">\n"
15+
" <meta http-equiv=\"refresh\" content=\"5\">\n"
16+
" </head>\n"
17+
" <body>\n"
18+
" <main>\n"
19+
" <form method=\"post\" action=\"/\">\n"
20+
" <table>\n"
21+
" <tbody align=center valign=middle>\n"
22+
" <tr><td></td><td><button type=\"submit\" name=\"forwards\" value=\"10\" title=\"+37,70mm\">&#8593;</button></td><td></td></tr>\n"
23+
" <tr><td><button type=\"submit\" name=\"left\" value=\"5\" title=\"-86,4&deg;\">&#8634;</button></td><td>&#x1F916;</td><td><button type=\"submit\" name=\"right\" value=\"5\" title=\"+86,4&deg;\">&#8635;</button></td></tr>\n"
24+
" <tr><td></td><td><button type=\"submit\" name=\"backwards\" value=\"10\" title=\"-37,70mm\">&#8595;</button></td><td></td></tr>\n"
25+
" </tbody>\n"
26+
" </table>\n"
27+
" </form>\n"
28+
" <img style=\"max-width:90vw; max-height:100vh;\" src=\"https://david.hebbeker.info/robot-control.php?positions=%s\" />\n"
29+
" </main>\n"
30+
" </body>\n"
31+
"</html>";
32+
33+
void WebserverHandle::handleRoot() {
34+
TargetRequest newTarget;
35+
digitalWrite(board::debugLed, LOW);
36+
if(server.hasArg("forwards"))
37+
{
38+
newTarget.newDrive = server.arg("forwards").toInt();
39+
newTarget.forward = true;
40+
newTarget.isTargetNew = true;
41+
Serial.printf("Got forwards by %u!\n", newTarget.newDrive);
42+
}
43+
if(server.hasArg("backwards"))
44+
{
45+
newTarget.newDrive = server.arg("backwards").toInt();
46+
newTarget.forward = false;
47+
newTarget.isTargetNew = true;
48+
Serial.printf("Got backwards by %u!\n", newTarget.newDrive);
49+
}
50+
if(server.hasArg("left"))
51+
{
52+
newTarget.newRotate = server.arg("left").toInt();
53+
newTarget.clockwise = false;
54+
newTarget.isTargetNew = true;
55+
Serial.printf("Got left by %u!\n", newTarget.newRotate);
56+
}
57+
if(server.hasArg("right"))
58+
{
59+
newTarget.newRotate = server.arg("right").toInt();
60+
newTarget.clockwise = true;
61+
newTarget.isTargetNew = true;
62+
Serial.printf("Got right by %u!\n", newTarget.newRotate);
63+
}
64+
target = newTarget;
65+
const char * pointerToHtml = nullptr;
66+
ATOMIC()
67+
{
68+
pointerToHtml = htmlSourceFrontBuffer;
69+
}
70+
server.send(200, "text/html", pointerToHtml);
71+
digitalWrite(board::debugLed, HIGH);
72+
}
73+
74+
void WebserverHandle::loop() {
75+
updateHtmlSource();
76+
}
77+
78+
WebserverHandle::WebserverHandle(ESP8266WebServer& webserver,
79+
const EnvironmentRecord &environmentRecord) :
80+
htmlSourceFrontBuffer(htmlSourceTemplate), server(webserver), environment(
81+
environmentRecord) {
82+
}
83+
84+
WebserverHandle::TargetRequest WebserverHandle::flushTargetRequest() {
85+
TargetRequest oldTarget;
86+
ATOMIC()
87+
{
88+
oldTarget = target;
89+
}
90+
target = TargetRequest { };
91+
return oldTarget;
92+
}
93+
94+
void WebserverHandle::setup() {
95+
updateHtmlSource();
96+
}
97+
98+
void WebserverHandle::updateHtmlSource() {
99+
constexpr std::size_t maxCharPerPosition = (5+1)*2; // when serializing the position, the number of characters maximum used per position
100+
constexpr std::size_t positionsStringMaxLength = maxCharPerPosition*environment.numberOfPositions+1;
101+
102+
static char htmlSourceBackBufferA[size(htmlSourceTemplate) + positionsStringMaxLength] = {0};
103+
static char htmlSourceBackBufferB[size(htmlSourceTemplate) + positionsStringMaxLength] = {0};
104+
105+
char * const backBuffer = (htmlSourceFrontBuffer == htmlSourceBackBufferA) ? htmlSourceBackBufferB : htmlSourceBackBufferA;
106+
char positionStringBuffer[positionsStringMaxLength] = { 0 };
107+
std::size_t charPos = 0;
108+
for(std::size_t i=0; i<=environment.positionIndex; i++)
109+
{
110+
const int writtenCharacters = snprintf(&(positionStringBuffer[charPos]), maxCharPerPosition+1, "%i;%i;", environment.positions[i].x, environment.positions[i].y);
111+
assert(writtenCharacters>0);
112+
charPos += writtenCharacters;
113+
}
114+
const int writtenCharacters = snprintf(backBuffer, size(htmlSourceBackBufferA), htmlSourceTemplate, positionStringBuffer);
115+
assert(writtenCharacters>0);
116+
htmlSourceFrontBuffer = backBuffer;
117+
}

robot-control-src/WebserverHandle.hpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#ifndef ROBOT_CONTROL_SRC_WEBSERVERHANDLE_HPP_
2+
#define ROBOT_CONTROL_SRC_WEBSERVERHANDLE_HPP_
3+
4+
#include "Drives.hpp"
5+
#include "EnvironmentRecord.hpp"
6+
#include <ESP8266WebServer.h>
7+
8+
class WebserverHandle {
9+
public:
10+
11+
WebserverHandle(ESP8266WebServer& webserver, const EnvironmentRecord& environmentRecord);
12+
13+
/**
14+
* Does handle web client requests to root path.
15+
*/
16+
void handleRoot();
17+
18+
void setup();
19+
20+
/**
21+
* Should be called regularly.
22+
*/
23+
void loop();
24+
25+
struct TargetRequest
26+
{
27+
bool isTargetNew = false;
28+
drives::Counter newDrive = 0;
29+
bool forward = true;
30+
drives::Counter newRotate = 0;
31+
bool clockwise = true;
32+
};
33+
34+
TargetRequest flushTargetRequest();
35+
36+
private:
37+
/**
38+
* Does calculate the HTML source to be handled to the web client.
39+
*/
40+
void updateHtmlSource();
41+
42+
const char * htmlSourceFrontBuffer;
43+
TargetRequest target;
44+
ESP8266WebServer& server;
45+
const EnvironmentRecord& environment;
46+
};
47+
48+
#endif /* ROBOT_CONTROL_SRC_WEBSERVERHANDLE_HPP_ */

robot-control-src/robot-control-src.ino

Lines changed: 12 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -2,109 +2,16 @@
22
#include "Drives.hpp"
33
#include "wifi_ap.hpp"
44
#include "library_extension.hpp"
5+
#include "EnvironmentRecord.hpp"
6+
#include "WebserverHandle.hpp"
57
#include <assert.h>
68
#include <ESP8266WebServer.h>
7-
#include <atomic>
89
#include <algorithm>
10+
#include <functional>
911

12+
static EnvironmentRecord environmentRecord;
1013
static ESP8266WebServer server(80);
11-
12-
static struct
13-
{
14-
bool isTargetNew = false;
15-
drives::Counter newDrive = 0;
16-
bool forward = true;
17-
drives::Counter newRotate = 0;
18-
bool clockwise = true;
19-
} newTarget;
20-
21-
static constexpr std::size_t numberOfPositions = 50;
22-
static Position positions[numberOfPositions] = { {0,0} };
23-
static std::size_t positionIndex = 0;
24-
25-
static constexpr char htmlSourceTemplate[] =
26-
"<!DOCTYPE html>\n"
27-
"<html lang=\"en\">\n"
28-
" <head>\n"
29-
" <title>Robot Control</title>\n"
30-
" <meta charset=\"utf-8\" />\n"
31-
" <meta name=\"viewport\" content=\"width=device-width, initial-scale=1.6\">\n"
32-
" <meta http-equiv=\"refresh\" content=\"5\">\n"
33-
" </head>\n"
34-
" <body>\n"
35-
" <main>\n"
36-
" <form method=\"post\" action=\"/\">\n"
37-
" <table>\n"
38-
" <tbody align=center valign=middle>\n"
39-
" <tr><td></td><td><button type=\"submit\" name=\"forwards\" value=\"10\" title=\"+37,70mm\">&#8593;</button></td><td></td></tr>\n"
40-
" <tr><td><button type=\"submit\" name=\"left\" value=\"5\" title=\"-86,4&deg;\">&#8634;</button></td><td>&#x1F916;</td><td><button type=\"submit\" name=\"right\" value=\"5\" title=\"+86,4&deg;\">&#8635;</button></td></tr>\n"
41-
" <tr><td></td><td><button type=\"submit\" name=\"backwards\" value=\"10\" title=\"-37,70mm\">&#8595;</button></td><td></td></tr>\n"
42-
" </tbody>\n"
43-
" </table>\n"
44-
" </form>\n"
45-
" <img style=\"max-width:90vw; max-height:100vh;\" src=\"https://david.hebbeker.info/robot-control.php?positions=%s\" />\n"
46-
" </main>\n"
47-
" </body>\n"
48-
"</html>";
49-
50-
51-
constexpr std::size_t maxCharPerPosition = (5+1)*2; //!< when serializing the position, the number of characters maximum used per position
52-
constexpr std::size_t positionsStringMaxLength = maxCharPerPosition*numberOfPositions+1;
53-
54-
static char htmlSourceBackBufferA[size(htmlSourceTemplate) + positionsStringMaxLength] = {0};
55-
static char htmlSourceBackBufferB[size(htmlSourceTemplate) + positionsStringMaxLength] = {0};
56-
static std::atomic<const char *> htmlSourceFrontBuffer(htmlSourceTemplate);
57-
58-
void updateHtmlSource()
59-
{
60-
char * const backBuffer = (htmlSourceFrontBuffer.load() == htmlSourceBackBufferA) ? htmlSourceBackBufferB : htmlSourceBackBufferA;
61-
char positionStringBuffer[positionsStringMaxLength] = { 0 };
62-
std::size_t charPos = 0;
63-
for(std::size_t i=0; i<=positionIndex; i++)
64-
{
65-
const int writtenCharacters = snprintf(&(positionStringBuffer[charPos]), maxCharPerPosition+1, "%i;%i;", positions[i].x, positions[i].y);
66-
assert(writtenCharacters>0);
67-
charPos += writtenCharacters;
68-
}
69-
const int writtenCharacters = snprintf(backBuffer, size(htmlSourceBackBufferA), htmlSourceTemplate, positionStringBuffer);
70-
assert(writtenCharacters>0);
71-
htmlSourceFrontBuffer = backBuffer;
72-
}
73-
74-
static void handleRoot()
75-
{
76-
digitalWrite(board::debugLed, LOW);
77-
if(server.hasArg("forwards"))
78-
{
79-
newTarget.newDrive = server.arg("forwards").toInt();
80-
newTarget.forward = true;
81-
newTarget.isTargetNew = true;
82-
Serial.printf("Got forwards by %u!\n", newTarget.newDrive);
83-
}
84-
if(server.hasArg("backwards"))
85-
{
86-
newTarget.newDrive = server.arg("backwards").toInt();
87-
newTarget.forward = false;
88-
newTarget.isTargetNew = true;
89-
Serial.printf("Got backwards by %u!\n", newTarget.newDrive);
90-
}
91-
if(server.hasArg("left"))
92-
{
93-
newTarget.newRotate = server.arg("left").toInt();
94-
newTarget.clockwise = false;
95-
newTarget.isTargetNew = true;
96-
Serial.printf("Got left by %u!\n", newTarget.newRotate);
97-
}
98-
if(server.hasArg("right"))
99-
{
100-
newTarget.newRotate = server.arg("right").toInt();
101-
newTarget.clockwise = true;
102-
newTarget.isTargetNew = true;
103-
Serial.printf("Got right by %u!\n", newTarget.newRotate);
104-
}
105-
server.send(200, "text/html", htmlSourceFrontBuffer.load());
106-
digitalWrite(board::debugLed, HIGH);
107-
}
14+
static WebserverHandle webserverHandle(server, environmentRecord);
10815

10916
void setup()
11017
{
@@ -164,8 +71,8 @@ void setup()
16471

16572
server.begin();
16673
Serial.printf("webserver has IP %s\n", WiFi.localIP().toString().c_str());
167-
server.on("/", handleRoot);
168-
updateHtmlSource();
74+
server.on("/", std::bind(&WebserverHandle::handleRoot, &webserverHandle));
75+
webserverHandle.setup();
16976
}
17077

17178
static void printSensorStatus(VL53L1GpioInterface* const sensor)
@@ -215,24 +122,23 @@ void loop()
215122
if(drives::LeftDrive::isIdle && drives::RightDrive::isIdle)
216123
{
217124
const Position newPositionCandidate = drives::flushCurrentPosition();
218-
if(positions[positionIndex] != newPositionCandidate)
125+
if(environmentRecord.positions[environmentRecord.positionIndex] != newPositionCandidate)
219126
{
220-
positions[++positionIndex] = newPositionCandidate;
221-
positionIndex %= numberOfPositions;
222-
updateHtmlSource();
127+
environmentRecord.positions[++environmentRecord.positionIndex] = newPositionCandidate;
128+
environmentRecord.positionIndex %= environmentRecord.numberOfPositions;
129+
webserverHandle.loop();
223130
}
131+
const auto newTarget = webserverHandle.flushTargetRequest();
224132
if(newTarget.isTargetNew)
225133
{
226134
const bool bumperIsPressed = digitalRead(board::leftBumper) == LOW || digitalRead(board::rightBumper) == LOW;
227135
if(newTarget.newDrive!=0 && (!newTarget.forward || !bumperIsPressed))
228136
{
229137
drives::driveCounter(newTarget.newDrive, drives::cruiseSpeed, !newTarget.forward);
230-
newTarget = { };
231138
}
232139
else if(newTarget.newRotate!=0 && !bumperIsPressed)
233140
{
234141
drives::rotateCounter(newTarget.newRotate, drives::cruiseSpeed, newTarget.clockwise);
235-
newTarget = { };
236142
}
237143
}
238144
}

0 commit comments

Comments
 (0)