Roomba Controller Dashboard 1
A GUI and TCP client application that is used to control a Roomba for Computer Engineering 2880 @ Iowa State
Loading...
Searching...
No Matches
main.cpp
Go to the documentation of this file.
1#include "../include/imgui/imgui.h"
2#include "../include/imgui/backends/imgui_impl_glfw.h"
3#include "../include/imgui/backends/imgui_impl_opengl3.h"
4#include <GLFW/glfw3.h>
5#include "Pose2D.hpp"
6#include "Node.hpp"
7#include "Pillar.hpp"
8#include "Hole.hpp"
9#include "Field.hpp"
10#include <vector>
11#include <netinet/in.h>
12#include <chrono>
13#include <sys/socket.h>
14#include <unistd.h>
15#include <arpa/inet.h>
16#include <fstream>
17#include <iostream>
18#include <thread>
19#include <queue>
20#include <condition_variable>
21#include <atomic>
22#include <sstream>
23
24#define BOT_CONNECT 0
25#if BOT_CONNECT
26 #define ADDRESS "192.168.1.1"
27 #define PORT 288
28#else
29 #define ADDRESS "127.0.0.1"
30 #define PORT 65432
31#endif
32
40
41std::queue<std::string> sendQueue;
42std::mutex queueMutex;
43std::condition_variable sendCondition;
44
45struct Move {
46 double quantity;
48};
49
50std::atomic<bool> stopClient(false);
51
56void addToQueue(const std::string& message) {
57 // std::cout << message << std::endl;
58 queueMutex.lock();
59 std::cout << message << std::endl;
60 sendQueue.push(message);
61 queueMutex.unlock();
62}
63
68void sendAngleToQueue(int16_t angle) {
69 char buff[8];
70 sprintf(buff, "t%03d", angle);
71 // std::cout << std::string(buff) << std::endl;
72 sendQueue.emplace(buff);
73}
74
79void sendDistanceToQueue(uint16_t distance) {
80 char buff[8];
81 sprintf(buff, "r%03d", distance);
82 sendQueue.emplace(buff);
83}
84
90void pathToRoutine(std::vector<Pose2D> path, std::vector<Move>& routine) {
91 // start at 1 so that we can gurantee that we can look back.
92 double previousEndHeading = path[0].getHeading();
93 for (size_t move = 1; move < ((path.size() - 1)*2); move += 2) {
94 // for every point we want to point and move
95 Pose2D pointOld = path[move / 2];
96 Pose2D pointNew = path[(move / 2) + 1];
97 // angle to turn to
98 double newHeading = pointNew.angleTo(pointOld);
99 double angle = newHeading - previousEndHeading;
100 previousEndHeading = newHeading;
101
102 // magnitude
103 double magnitude = pointNew.distanceTo(pointOld);
104 routine.push_back((Move) {.quantity = angle, .type = TURN_TO_ANGLE});
105 routine.push_back((Move) {.quantity = magnitude, .type = MOVE_FORWARD_SMART});
106 }
107}
108
114std::string parsePathIntoRoutine(const std::vector<Pose2D>& path) {
115 std::stringstream toSend;
116 std::vector<Move> routine;
117 // std::cout << "routine length: " << routine.size() << std::endl;
118 pathToRoutine(path, routine);
119
120 toSend << "R";
121
122 for (uint8_t i = 0; i < routine.size(); i++) {
123 static char buffer[50];
124 // sprintf(buffer, "p %0.3f %0.3f " , path[i].getX(), path[i].getY());
125 // // routine[i] is all 0
126 sprintf(buffer, " %0.3f %c ", routine[i].quantity, routine[i].type + 'a');
127 toSend << std::string(buffer);
128 }
129
130 toSend << "R";
131
132 return toSend.str();
133}
134
142void readAndLog(int socket, std::mutex& fieldMutex, Field& field, std::vector<Pose2D>& path) {
143 const uint16_t BUFF_SIZE = 1024;
144
145 static char name_buff[50];
146 time_t now = time(0);
147 strftime(name_buff, sizeof(name_buff), "log/%Y%m%d_%H%M%S.log", localtime(&now));
148 std::string str_name(name_buff);
149
150 std::ofstream logFile(str_name);
151
152 while (!(stopClient.load())) {
153
154 char buff[BUFF_SIZE];
155
156 // expect a "Handshake" response to be echoed
157 size_t bytesRead = read(socket, buff, BUFF_SIZE);
158
159 std::string response(buff, bytesRead);
160
161 if (bytesRead > 0) {
162 logFile << response;
163 }
164
165 std::istringstream stream(response);
166 char tag;
167 while (stream >> tag) {
168 switch(tag) {
169 case 'F':
170 // send the routine
171 {
172 // generate path and return it
173 fieldMutex.lock();
174
175 field.discretizeGraph();
176 field.weightGraph();
177
178 path.clear();
179 std::vector<Pose2D> pathOne = field.makePath();
180 for (uint16_t i = 0; i < pathOne.size(); i++) {
181 path.push_back(pathOne[i]);
182 }
183
184 /*
185 Pose2D oldCenter = field.getDesiredDestination();
186 if (path.empty()) {
187 // try a new desired position until its not empty
188 for (uint8_t i = 0; i < 10; i += 5) {
189 for (double j = 0; j < 2 * M_PI; j += M_PI * 1/4) {
190 Pose2D newDesired = Pose2D::fromPolar(i, j);
191 newDesired.plus(oldCenter);
192 if (!Field::outOfBounds(newDesired)) {
193 field.updateDesired(newDesired);
194 field.discretizeGraph();
195 field.weightGraph();
196 path = field.makePath();
197 if (!path.empty()) {
198 sendQueue.push(parsePathIntoRoutine(path));
199 break;
200 }
201 }
202 }
203 }
204 }
205 */
206
207 fieldMutex.unlock();
208 }
209 break;
210 case 'o':
211 {
212 fieldMutex.lock();
213 Pillar toAdd = Pillar::parseFromStream(stream);
214 // std::cout << "x: " << toAdd.getX() << " y: " << toAdd.getY() << " radius: " << toAdd.getRadius() << std::endl;
215 toAdd.getPose().transformForPose(field.getBotPose().getPose());
216 field.addPillar(toAdd);
217 fieldMutex.unlock();
218 }
219 break;
220 case 'd':
221 {
222 Pose2D other = Pose2D::parseFromStream(stream);
223 field.updateDesired(other);
224 }
225 break;
226 case 'E':
227 {
228 double m;
229 char cardinality;
230 if (stream >> m >> cardinality) {
231 field.addEdgeMeasurement(m, (Cardinality) cardinality);
232 }
233 // first term is the raw X or Y value next value is the direction
234 }
235 break;
236 case 'h':
237 {
238 fieldMutex.lock();
239 // data is coming in the format " X Y Theta "
240 Pose2D holeMeasurment = Pose2D::parseFromStream(stream);
241 holeMeasurment.plus(field.getBotPose().getPose());
242 field.getManager().addPoint(holeMeasurment);
243 fieldMutex.unlock();
244 }
245 break;
246 case 'H':
247 {
248 // data is coming in the format " X1 Y1 X2 Y2 "
249 fieldMutex.lock();
250 double x1, y1, x2, y2;
251 if (stream >> x1 >> y1 >> x2 >> y2) {
252 Pose2D one(x1, y1);
253 Pose2D two(x2, y2);
254 one.plus(field.getBotPose().getPose());
255 two.plus(field.getBotPose().getPose());
256 Hole hole(one, two, one.distanceTo(two) / sqrt(2));
257 field.getManager().addHole(hole);
258 }
259 fieldMutex.unlock();
260 }
261 break;
262 case 'b':
263 {
264 fieldMutex.lock();
266 std::cout << "recieved bot pose: " << field.getBotPose().getPose() << std::endl;
267 fieldMutex.unlock();
268 }
269 break;
270 default:
271 logFile << tag;
272 break;
273 }
274 }
275
276 std::this_thread::sleep_for(std::chrono::milliseconds(5));
277 // no matter what we are going to log this in a file, however we should also update certain fields
278
279 }
280
281 logFile.close();
282
283}
284
291void connectTCP(Field& field, std::mutex& fieldMutex, std::vector<Pose2D>& path) {
292 int clientSocket = socket(AF_INET, SOCK_STREAM, 0);
293 sockaddr_in serverAddress{
294 .sin_family = AF_INET,
295 .sin_port = htons(PORT),
296 .sin_addr = inet_addr(ADDRESS)
297 };
298
299 // https://beej.us/guide/bgnet/html/#blocking
300 // fcntl(clientSocket, F_SETFL, O_NONBLOCK);
301 bool connected = false;
302 while (!connected) {
303 try {
304 if(connect(clientSocket, (struct sockaddr*)& serverAddress, sizeof(serverAddress))) {
305 throw std::exception();
306 }
307 connected = true;
308 }
309 catch (std::exception& e) {
310 std::this_thread::sleep_for(std::chrono::milliseconds(500));
311 connected = false;
312 }
313
314 }
315
316 // spawn read and log thread here
317 std::thread readThread(readAndLog, std::ref(clientSocket), std::ref(fieldMutex), std::ref(field), std::ref(path));
318
319 while(!stopClient.load()) {
320 if (!sendQueue.empty()) {
321 std::string message = sendQueue.front();
322 if (message.compare("q") == 0) {
323 stopClient.store(true);
324 }
325 sendQueue.pop();
326 send(clientSocket, message.c_str(), message.length(), 0);
327 }
328
329 std::this_thread::sleep_for(std::chrono::milliseconds(20));
330 }
331
332
333 readThread.join();
334 close(clientSocket);
335}
336
341void setupImGui(GLFWwindow* window) {
342 IMGUI_CHECKVERSION();
343 ImGui::CreateContext();
344 ImGuiIO& io = ImGui::GetIO(); (void)io;
345 ImGui::StyleColorsDark();
346 ImGui_ImplGlfw_InitForOpenGL(window, true);
347 ImGui_ImplOpenGL3_Init("#version 130");
348}
349
357void DrawCircle(ImDrawList* drawList, const ImVec2& center, float radius, ImU32 color) {
358 drawList->AddCircle(center, radius, color, 0, 0.2f);
359}
360
368Pose2D ScreenToCoords(ImVec2 coords, ImVec2 offset, ImVec2 scaling) {
369 double x = (coords.x - offset.x) / scaling.x;
370 double y = MAX_Y - (coords.y - offset.y) / scaling.y;
371 return {x, y};
372}
373
383ImVec2 coordsToScreen(ImVec2 offset, ImVec2 scaling, double x, double y) {
384 double xN = offset.x + (scaling.x * x);
385 double yN = offset.y + (scaling.y * (MAX_Y - y));
386 return ImVec2(xN, yN);
387}
388
396ImVec2 coordsToScreen(ImVec2 offset, ImVec2 scaling, const Pose2D& position) {
397 return coordsToScreen(offset, scaling, position.getX(), position.getY());
398}
399
408void ShowPillarOnWindow(ImDrawList* drawList, Pillar pillar, ImU32 color, ImVec2 offset, ImVec2 scaling) {
409 ImVec2 center = coordsToScreen(offset, scaling, pillar.getPose());
410 float radius = pillar.getRadius() * 2.5;
411 // std::cout << "haven't drawn yet" << std::endl;
412 DrawCircle(drawList, center, radius, color);
413}
414
423void drawBotPose(ImDrawList* drawList, const Pose2D& botPose, ImVec2 offset, ImVec2 scaling) {
424 ImU32 color = IM_COL32(144, 238, 144, 200);
425
426 // calculate the position of the first point
427 // should be botPose + (botRadius * 1.5 @ bot heading)
428 double scaleAmount = 2;
429 Pose2D lineOutOfCenter = Pose2D::fromPolar(BOT_RADIUS * 1.5 * scaleAmount, 0);
430 lineOutOfCenter.transformPose(botPose);
431 const ImVec2 p1 = coordsToScreen(offset, scaling, lineOutOfCenter);
432 Pose2D sideLine = Pose2D::fromPolar(scaleAmount * BOT_RADIUS * 0.75, Pose2D::degreesToRadians(120));
433 sideLine.transformPose(botPose);
434 const ImVec2 p2 = coordsToScreen(offset, scaling, sideLine);
435 Pose2D otherSide = Pose2D::fromPolar(BOT_RADIUS * scaleAmount * 0.75, Pose2D::degreesToRadians(240));
436 otherSide.transformPose(botPose);
437 const ImVec2 p3 = coordsToScreen(offset, scaling, otherSide);
438
439 drawList->AddTriangle(p1, p2, p3, color);
440}
441
450void drawRectangle(ImDrawList* drawList, ImVec2 offset, ImVec2 scaling, const Pose2D& p1, const Pose2D& p2) {
451 // const Pose2D MinPosition = Pose2D(std::min(p1.getX(), p2.getX()), std::min(p1.getY(), p2.getY()));
452 // const Pose2D MaxPosition = Pose2D(std::max(p1.getX(), p2.getX()), std::max(p1.getY(), p2.getY()));
453 // fun math time
454 const double xCenter = (p1.getX() + p2.getX()) / 2;
455 const double yCenter = (p1.getY() + p2.getY()) / 2;
456 const double xDiagonal = (p1.getX() - p2.getX()) / 2;
457 const double yDiagonal = (p1.getY() - p2.getY()) / 2;
458
459 const Pose2D p3(xCenter - yDiagonal, yCenter + xDiagonal);
460 const Pose2D p4(xCenter + yDiagonal, yCenter - xDiagonal);
461
462 const ImVec2 m1 = coordsToScreen(offset, scaling, p1);
463 const ImVec2 m2 = coordsToScreen(offset, scaling, p2);
464 const ImVec2 m3 = coordsToScreen(offset, scaling, p3);
465 const ImVec2 m4 = coordsToScreen(offset, scaling, p4);
466 // std:: cout << "p2 position: " << p2.getY() << std::endl;
467
468 drawList->AddQuadFilled(m1, m3, m2, m4, IM_COL32(255, 165, 0, 170));
469}
470
479void ShowFieldWindow(std::mutex* pillarsMutex, std::vector<Pose2D>& path, Field& field, std::atomic<bool>& showNodes, std::atomic<bool>& showEdges) {
480 ImGui::Begin("Field");
481
482 ImDrawList* drawList = ImGui::GetWindowDrawList();
483 ImVec2 windowSize(MAX_X * 2.5, MAX_Y * 2.5);
484 ImGui::SetWindowSize(windowSize);
485 ImVec2 windowPos = ImGui::GetWindowPos();
486 windowPos.x += windowSize.x / 100;
487 windowPos.y += windowSize.y / 100;
488 ImVec2 offset = ImVec2(windowPos.x + windowSize.x / 50, windowPos.y - windowSize.y / 50);
489 ImVec2 scalingFactor = ImVec2(windowSize.x / MAX_X, windowSize.y / MAX_Y);
490
491 pillarsMutex->lock();
492
493 std::vector<Pillar> pillars = field.getCopyPillars();
494
495 for (const Pillar& pillar: pillars) {
496 ShowPillarOnWindow(drawList, pillar, IM_COL32(255, 0, 0, 200), offset, scalingFactor);
497 }
498
499 std::vector<Hole> holes = field.getManager().getHoles();
500// std::cout << "size: " << holes.size() << std::endl; // output 1
501 for (Hole hole: holes) {
502 // std::cout << "X1 Y1 X2 Y2: {" << hole.getOneSquareCorner().getX() << " " << hole.getOneSquareCorner().getY() << " " << hole.getSecondSquareCorner().getX() << " " << hole.getSecondSquareCorner().getY() << std::endl;
503 if (hole.isFoundHole()) {
504 drawRectangle(drawList, offset, scalingFactor, hole.getOneSquareCorner(), hole.getSecondSquareCorner());
505 }
506 else {
507 std::vector<Hole> subHoles = hole.getSubHolesCopy();
508 for (Hole holer: subHoles) {
509 drawRectangle(drawList, offset, scalingFactor, holer.getOneSquareCorner(), holer.getSecondSquareCorner());
510 }
511 }
512 }
513
514 drawBotPose(drawList, field.getBotPose().getPose(), offset, scalingFactor);
515
516 if (showNodes.load()) {
517 std::vector<Node<Pose2D> *> nodes = field.getGraph().getNodes();
518
519 for (Node<Pose2D> *&node: nodes) {
520 Pose2D position = node->getData();
521
522 ImVec2 center = coordsToScreen(offset, scalingFactor, position.getX(), position.getY());
523 float radius = BOT_RADIUS * 2.5;
524 DrawCircle(drawList, center, radius, IM_COL32(120, 120, 0, 200));
525 // draw a line from every node to the adjacent yes we will double count draws with this
526 // std::vector<Node<Pose2D>*> adjacent = getAdj(nodes[nodeIndex]);
527
528 }
529 }
530
531 if (showEdges.load()) {
532 std::vector<Node<Pose2D> *> nodes = field.getGraph().getNodes();
533 for (Node<Pose2D> *&node: nodes) {
534 std::vector<Node<Pose2D> *> adjacent = field.getGraph().getAdj(node);
535 for (Node<Pose2D> *&adj: adjacent) {
536 ImVec2 p1 = coordsToScreen(offset, scalingFactor, node->getData());
537 ImVec2 p2 = coordsToScreen(offset, scalingFactor, adj->getData());
538 drawList->AddLine(p1, p2, IM_COL32(100, 100, 100, 100), 2);
539 }
540 }
541 }
542
543
544 for (uint8_t i = 0; i < path.size(); i++) {
545 if (i > 0) {
546 ImVec2 p1 = coordsToScreen(offset, scalingFactor, path[i - 1].getX(), path[i - 1].getY());
547 ImVec2 p2 = coordsToScreen(offset, scalingFactor, path[i].getX(), path[i].getY());
548 drawList->AddLine(p1, p2, IM_COL32(100, 100, 100, 100), 2);
549 }
550
551 ImVec2 center = coordsToScreen(offset, scalingFactor, path[i].getX(), path[i].getY());
552 float radius = BOT_RADIUS * 2.5;
553 DrawCircle(drawList, center, radius, IM_COL32(30, 120, 220, 150));
554 }
555
556 pillarsMutex->unlock();
557
558 ImVec2 mousePos = ImGui::GetMousePos();
559// std::string mousePosStr = std::to_string((int)mousePos.x) + ", " + std::to_string((int)mousePos.y);
560 ImGui::Text("mouse: %d, %d", (int)mousePos.x, (int)mousePos.y);
561 Pose2D transformed = ScreenToCoords(ImVec2((int) mousePos.x, (int) mousePos.y), offset, scalingFactor);
562 ImGui::Text("Pose on field: %d, %d", (int) transformed.getX(), (int) transformed.getY());
563
564 ImGui::End();
565}
566
567
572int main() {
573 if (!glfwInit()) return -1;
574 GLFWwindow* window = glfwCreateWindow(1880, 900, "Roomba Dashboard", nullptr, nullptr);
575 if (!window) { glfwTerminate(); return -1; }
576 glfwMakeContextCurrent(window);
577 setupImGui(window);
578 Pose2D desired(0, 0);
579
580 // used to hold GUI slider values
581 float angleSend = 0;
582 int driveForward = 0;
583
584 std::atomic<bool> showNodes;
585 showNodes.store(false);
586 std::atomic<bool> showEdges;
587 showEdges.store(false);
588
589 char buffer[100];
590 size_t buffPtr = 0;
591
592 std::mutex pillarsMutex;
593 std::vector<Pose2D> path;
594
595 Field field;
596 // Pose2D toAdd(0, 0, 0);
597 // graph.addNode(new Node<Pose2D>(toAdd));
598 // connectTCP(pillars, pillarsMutex, desired);
599 std::thread tcpConnect(connectTCP, std::ref(field), std::ref(pillarsMutex), std::ref(path));
600
601 // Main loop
602 while (!glfwWindowShouldClose(window)) {
603 glfwPollEvents();
604
605 // Start the ImGui frame
606 ImGui_ImplOpenGL3_NewFrame();
607 ImGui_ImplGlfw_NewFrame();
608 ImGui::NewFrame();
609 // bool open;
610 // ImGui::ShowDemoWindow(&open);
611 ShowFieldWindow(&pillarsMutex, path, field, showNodes, showEdges);
612 // std::cout << "About to begin" << std::endl;
613
614 // Your ImGui code here
615 ImGui::Begin("Control Panel");
616 // std::cout << "began" << std::endl;
617 //ImGui::Text("This is some text");
618 {
619 if (ImGui::Button("Forward")) {
620 addToQueue("w");
621 }
622
623 if (ImGui::Button("Backward")) {
624 addToQueue("s");
625 }
626
627 if (ImGui::Button("Counter Clockwise")) {
628 addToQueue("a");
629 }
630
631 if (ImGui::Button("Clockwise")) {
632 addToQueue("d");
633 }
634
635 if (ImGui::Button("Stop")) {
636 addToQueue(" ");
637 }
638
639 if (ImGui::Button("Scan")) {
640 addToQueue("g");
641 }
642
643 if (ImGui::Button("Auton")) {
644 addToQueue("h");
645 }
646
647 if (ImGui::Button("Quit all")) {
648 addToQueue("q");
649 }
650
651 if (ImGui::RadioButton("Show nodes", false)) {
652 showNodes.store(!showNodes.load());
653 }
654
655 if (ImGui::RadioButton("Show edges", false)) {
656 showEdges.store(!showEdges.load());
657 }
658 }
659
660 if (ImGui::Button("Generate path")) {
661 pillarsMutex.lock();
662 /*
663 std::cout << "desire: " << desired << std::endl;
664 for (int i = 0; i < graph->getNodes().size(); i++) {
665 std::cout << "node: " << i << ". " << graph->getNodes()[i]->getData().getX() << std::endl;
666 }
667
668 std::cout << "Attempting to make a path between: " << graph->getNodes().front()->getData().getX() << ", " << graph->getNodes().front()->getData().getY() << std::endl;
669 std::cout << "To: " <<graph->getNodes().back()->getData().getX() << ", " << graph->getNodes().back()->getData().getY() << std::endl;
670 // Attempting to make a path between: 0, 0
671 // To: -100, -100
672 */
673 path = field.makePath();
674 pillarsMutex.unlock();
675 // std::cout << "PATH NODE SIZE: " << pathNodes.size() << std::endl;
676 // path.push_back(botPose.getPose());
677 }
678
679 if (ImGui::Button("send planned path")) {
680 // string message = parsePathIntoRoutine(path);
682 }
683
684 ImGui::SliderAngle("Turn angle", &angleSend);
685
686 ImGui::InputText("message: ", buffer, 100);
687
688 if (ImGui::Button("send component")) {
689 addToQueue(std::string(1, buffer[0]));
690 for (size_t i = 0; i < 99; i++) {
691 if (buffer[i] == 0) {
692 buffPtr = std::min((long) 0, (long) i - 1);
693 break;
694 }
695 std::swap(buffer[i], buffer[i + 1]);
696 }
697 buffer[buffPtr] = 0;
698 }
699
700 if (ImGui::Button("Send turn")) {
701 sendAngleToQueue((int16_t) (angleSend * 180 / M_PI));
702 }
703
704 ImGui::SliderInt("Drive x cm", &driveForward, 0, 999);
705
706 if (ImGui::Button("Drive x")) {
707 sendDistanceToQueue(driveForward);
708 }
709
710 if (ImGui::Button("Discretize")) {
711 // std::cout << "HUH: " << pillars[0].getX() << std::endl;
712 field.discretizeGraph();
713 }
714
715 if (ImGui::Button("Weight")) {
716 field.weightGraph();
717 }
718 // std::cout << "About to end" << std::endl;
719
720 ImGui::End();
721 // Render
722 ImGui::Render();
723 int display_w, display_h;
724 glfwGetFramebufferSize(window, &display_w, &display_h);
725 glViewport(0, 0, display_w, display_h);
726 glClearColor(0.1f, 0.1f, 0.1f, 1.0f);
727 glClear(GL_COLOR_BUFFER_BIT);
728 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
729
730 glfwSwapBuffers(window);
731
732 std::this_thread::sleep_for(std::chrono::milliseconds(16));
733 }
734
735 stopClient.store(true);
736
737 tcpConnect.join();
738
739 // Cleanup
740 ImGui_ImplOpenGL3_Shutdown();
741 ImGui_ImplGlfw_Shutdown();
742 ImGui::DestroyContext();
743 glfwDestroyWindow(window);
744 glfwTerminate();
745
746 return 0;
747}
Cardinality
Definition Field.hpp:30
#define MAX_X
Definition Field.hpp:20
#define MAX_Y
Definition Field.hpp:25
#define BOT_RADIUS
Definition Pose2D.hpp:17
void updateBotPose(const Pose2D &updatedPosition)
Definition Field.cpp:179
std::vector< Pillar > getCopyPillars()
Definition Field.cpp:191
void discretizeGraph()
Definition Field.cpp:32
Pillar getBotPose()
Definition Field.cpp:155
HoleManager & getManager()
Definition Field.cpp:134
void addPillar(Pillar &newPillar)
Definition Field.cpp:159
void updateDesired(const Pose2D &other)
Definition Field.cpp:265
std::vector< Pose2D > makePath()
Definition Field.cpp:109
void weightGraph()
Definition Field.cpp:75
void addEdgeMeasurement(double rawPosition, Cardinality cardinality)
Definition Field.cpp:203
Graph< Pose2D > & getGraph()
Definition Field.cpp:261
std::vector< Node< V > * > getAdj(Node< V > *next)
Definition Graph.cpp:172
std::vector< Node< V > * > getNodes()
Definition Graph.cpp:97
void addPoint(const Pose2D &position)
std::vector< Hole > getHoles()
void addHole(const Hole &hole)
Definition Hole.hpp:20
Definition Node.hpp:17
static Pillar parseFromStream(std::istringstream &stream)
Definition Pillar.cpp:50
double getRadius() const
Definition Pillar.cpp:41
Pose2D & getPose()
Definition Pillar.cpp:29
double angleTo(const Pose2D &other) const
Definition Pose2D.cpp:78
static Pose2D fromPolar(double magnitude, double angle)
Definition Pose2D.cpp:193
double x
Definition Pose2D.hpp:25
void transformForPose(const Pose2D &other)
Definition Pose2D.cpp:94
void plus(const Pose2D &other)
Definition Pose2D.cpp:100
static Pose2D parseFromStream(std::istringstream &stream)
Definition Pose2D.cpp:204
void transformPose(const Pose2D &modifier)
Definition Pose2D.cpp:142
double distanceTo(const Pose2D &other) const
Definition Pose2D.cpp:86
double getY() const
Definition Pose2D.cpp:151
static double degreesToRadians(double degrees)
Definition Pose2D.cpp:200
double getX() const
Definition Pose2D.cpp:147
void addToQueue(const std::string &message)
Definition main.cpp:56
#define ADDRESS
Definition main.cpp:29
ImVec2 coordsToScreen(ImVec2 offset, ImVec2 scaling, double x, double y)
Definition main.cpp:383
std::condition_variable sendCondition
Definition main.cpp:43
void drawBotPose(ImDrawList *drawList, const Pose2D &botPose, ImVec2 offset, ImVec2 scaling)
Definition main.cpp:423
#define PORT
Definition main.cpp:30
void drawRectangle(ImDrawList *drawList, ImVec2 offset, ImVec2 scaling, const Pose2D &p1, const Pose2D &p2)
Definition main.cpp:450
void ShowFieldWindow(std::mutex *pillarsMutex, std::vector< Pose2D > &path, Field &field, std::atomic< bool > &showNodes, std::atomic< bool > &showEdges)
Definition main.cpp:479
void readAndLog(int socket, std::mutex &fieldMutex, Field &field, std::vector< Pose2D > &path)
Definition main.cpp:142
std::string parsePathIntoRoutine(const std::vector< Pose2D > &path)
Definition main.cpp:114
std::mutex queueMutex
Definition main.cpp:42
void setupImGui(GLFWwindow *window)
Definition main.cpp:341
MovementType
Definition main.cpp:33
@ MOVE_BACKWARDS
Definition main.cpp:35
@ TURN_TO_ANGLE
Definition main.cpp:37
@ MOVE_FORWARD
Definition main.cpp:34
@ MOVE_FORWARD_SMART
Definition main.cpp:36
@ SCAN
Definition main.cpp:38
std::atomic< bool > stopClient(false)
void ShowPillarOnWindow(ImDrawList *drawList, Pillar pillar, ImU32 color, ImVec2 offset, ImVec2 scaling)
Definition main.cpp:408
std::queue< std::string > sendQueue
Definition main.cpp:41
Pose2D ScreenToCoords(ImVec2 coords, ImVec2 offset, ImVec2 scaling)
Definition main.cpp:368
void pathToRoutine(std::vector< Pose2D > path, std::vector< Move > &routine)
Definition main.cpp:90
void sendDistanceToQueue(uint16_t distance)
Definition main.cpp:79
void sendAngleToQueue(int16_t angle)
Definition main.cpp:68
int main()
Definition main.cpp:572
void connectTCP(Field &field, std::mutex &fieldMutex, std::vector< Pose2D > &path)
Definition main.cpp:291
void DrawCircle(ImDrawList *drawList, const ImVec2 &center, float radius, ImU32 color)
Definition main.cpp:357
Definition main.cpp:45
MovementType type
Definition main.cpp:47
double quantity
Definition main.cpp:46