├── public ├── images │ ├── camera1.png │ ├── loading.png │ └── area coverage.png ├── js │ ├── control.js │ └── index.js └── css │ └── style.css ├── views ├── detection.ejs ├── footer.ejs ├── camera.ejs ├── selection.ejs ├── header.ejs ├── navbar_about.ejs ├── navbar_contact.ejs ├── manual.ejs ├── navbar.ejs ├── index.ejs ├── autonomous.ejs ├── contact.ejs ├── data analysis.ejs ├── status.ejs ├── sidebar.ejs └── about.ejs ├── package.json ├── README.md └── app.js /public/images/camera1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adititapariya/Web_Gui/HEAD/public/images/camera1.png -------------------------------------------------------------------------------- /public/images/loading.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adititapariya/Web_Gui/HEAD/public/images/loading.png -------------------------------------------------------------------------------- /public/images/area coverage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adititapariya/Web_Gui/HEAD/public/images/area coverage.png -------------------------------------------------------------------------------- /views/detection.ejs: -------------------------------------------------------------------------------- 1 |
2 |

Detection

3 |
4 | 5 | 6 |
-------------------------------------------------------------------------------- /views/footer.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webgui", 3 | "version": "1.0.0", 4 | "description": "It is Web Interface to control Bot.", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "author": "Sachin Vekariya", 10 | "license": "ISC", 11 | "dependencies": { 12 | "ejs": "^3.1.9", 13 | "express": "^4.18.1" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /views/camera.ejs: -------------------------------------------------------------------------------- 1 |
2 |

Camera

3 |
4 | 5 |
6 | 7 | 8 |
9 |
10 | -------------------------------------------------------------------------------- /views/selection.ejs: -------------------------------------------------------------------------------- 1 |
2 |

Task

3 |
4 |
5 |
6 |
7 | Manual 8 |
9 |
10 |
11 | 12 |
13 |
14 |
15 | Autonomous 16 |
17 |
18 |
19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /views/header.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | INNOVATION 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /views/navbar_about.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /views/navbar_contact.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /views/manual.ejs: -------------------------------------------------------------------------------- 1 |
2 |

Manual Control

3 |
4 |
5 | 6 |
7 | 8 | 9 | 10 |
11 | 12 |
13 |
14 | 15 | -------------------------------------------------------------------------------- /views/navbar.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /views/index.ejs: -------------------------------------------------------------------------------- 1 | <%- include ('header') %> 2 | <%- include ('navbar') %> 3 |
4 |
5 | <%- include('sidebar') %> 6 |
7 |
8 | <%- include('camera') %> 9 | <%- include('detection') %> 10 |
11 |
12 |
13 | <%- include('selection') %> 14 | <%- include('status') %> 15 | <%- include('data analysis') %> 16 |
17 |
18 |
19 | <%- include('manual') %> 20 | <%- include('autonomous') %> 21 |
22 |
23 |
24 | <%- include ('footer') %> -------------------------------------------------------------------------------- /views/autonomous.ejs: -------------------------------------------------------------------------------- 1 |
2 |

Autonomous Control

3 |
Area Coverage
4 |
5 | 6 |
7 | 8 | 9 | 10 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 24 | 25 | 26 |
Final Latitude 11 | 12 |
Final Longitude 19 | 20 | 22 | 23 |
27 |

Status - Closed

28 |
29 | 30 | 31 |
32 |
33 |
34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # WEB GUI
2 | Web GUI, which stands for Web Graphical User Interface, is a user interface designed to facilitate interaction with a robot. It aims to provide an intuitive and accessible interface enabling users to operate and manage the robot's functions effectively. It offers a versatile user interface that allows users to manually and autonomously control robots. Users can operate the robot manually by directly controlling its movements and mechanisms through the interface. Moreover, it facilitates autonomous navigation where users can guide the robot to autonomously cover the designated area by inputting the destination location through the interface. This interface communicates this location to the robot's control system, typically powered by a Raspberry Pi, and provides real-time feedback on the distance between the robot's current location and the destination. This comprehensive functionality empowers users to seamlessly switch between manual and autonomous control. It also includes a separate window for displaying real-time video from a stereo camera, providing visual feedback on the robot's surroundings. It also utilizes the camera to detect waste types, displaying resulting images in a detection section. The collected waste data, including category percentages, is organized and presented in a data analysis section. It additionally displays crucial data regarding the robot's operation. This includes information such as the robot's location and orientation. It provides user-friendly features to control various mechanisms, such as collection, vibration, conveyor movement, and segregation. Web GUI enables users to effectively monitor and manage the robot's operation, ensuring smooth and efficient performance of the robot in various scenarios. 3 | -------------------------------------------------------------------------------- /views/contact.ejs: -------------------------------------------------------------------------------- 1 | <%- include ('header') %> 2 | <%- include ('navbar_contact') %> 3 |
4 |

Contact

5 |

For setup procedure, kindly visit GitHub 6 | Page.

7 |
8 |

Contact Developer

9 |
10 |
11 | 12 | 13 |
14 |
15 | 16 | 17 |
18 |
19 | 20 |
21 | 22 |
23 |
24 | 25 | 26 |
27 |
28 |
29 | <%- include ('footer') %> -------------------------------------------------------------------------------- /views/data analysis.ejs: -------------------------------------------------------------------------------- 1 |
2 |

Data Analysis

3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 |
Sr. NoType of WastePlastic or Non-Plastic
1Organic WasteNon-Plastic
2Paper WasteNon-Plastic
3Plastic WastePlastic
30 | 31 | 34 | 35 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 |
Plastic Waste33%
Non-Plastic Waste67%
48 |
-------------------------------------------------------------------------------- /views/status.ejs: -------------------------------------------------------------------------------- 1 |
2 |

Status

3 |
4 |
5 |
6 |
7 |
Imu
8 |
9 |
10 |
11 | 12 |
13 |
14 |
15 |

Orientation: 0

16 |
17 |
18 |
19 |
20 |
GPS
21 |
22 |
23 |
24 | 25 |
26 |
27 |
28 |

Lat: 0

29 |

Long: 0

30 |
31 |
32 |
33 |
34 |
Collection
35 |
36 |
37 |
38 | 39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
Vibration
47 |
48 |
49 |
50 | 51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
Conveyor
59 |
60 |
61 |
62 | 63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
Segregation
71 |
72 |
73 |
74 | 75 |
76 |
77 |
78 |
79 |
-------------------------------------------------------------------------------- /views/sidebar.ejs: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const {exec,execFile} = require('child_process'); 3 | 4 | const app = express(); 5 | app.set('view engine','ejs'); 6 | app.use(express.static("public")); 7 | app.use(express.urlencoded({extended: true})); 8 | 9 | app.get('/', function(req, res){ 10 | res.render('index'); 11 | }) 12 | 13 | app.get('/about',function(req, res){ 14 | res.render('about'); 15 | }); 16 | 17 | app.get('/contact',function(req, res){ 18 | res.render('contact'); 19 | }); 20 | 21 | var websocket; 22 | app.post("/webSocket:id",function(req,res){ 23 | var id = req.params.id; 24 | if(id=="Start"){ 25 | websocket = execFile('roslaunch',['rosbridge_server','rosbridge_websocket.launch'],function(err,stdout,stderr){ 26 | if(err){ 27 | console.log(err); 28 | } 29 | }) 30 | console.log("Websocket started"); 31 | res.send("Connected"); 32 | 33 | } 34 | else if(id=="End"){ 35 | websocket.kill(); 36 | 37 | websocket.on('exit',function(code){ 38 | console.log(`Websocket exited with ${code}.`); 39 | res.send("Disconnected"); 40 | }) 41 | } 42 | 43 | }); 44 | 45 | var roscore; 46 | app.post('/roscore:id', function(req,res){ 47 | var id = req.params.id; 48 | if(id=="Start"){ 49 | 50 | roscore = execFile('roscore',function (err,stdout,stderr){ 51 | if(err){ 52 | console.log(err); 53 | } 54 | }); 55 | console.log("Roscore Started"); 56 | res.send("Connected"); 57 | } 58 | else if(id=="End"){ 59 | roscore.kill(); 60 | roscore.on('exit',function(code){ 61 | console.log(`Roscore exit with ${code}`); 62 | res.send("Disconnected"); 63 | }); 64 | } 65 | }); 66 | 67 | var gazebo; 68 | app.post('/gazebo:id',function(req,res){ 69 | var id = req.params.id; 70 | if(id=="Start"){ 71 | gazebo= execFile('roslaunch',['bot','simple_gazebo.launch'],function(err,stdout,stderr){ 72 | if (err) { 73 | console.log(err); 74 | } 75 | }); 76 | console.log("Gazebo Started"); 77 | res.send("Connected"); 78 | } 79 | else if(id=="End"){ 80 | gazebo.kill(); 81 | gazebo.on('exit',function(code){ 82 | console.log(`Gazebo exit with ${code}`); 83 | res.send("Disconnected"); 84 | }); 85 | 86 | } 87 | }); 88 | 89 | // var mapviz; 90 | // app.post('/mapviz:id',function(req,res){ 91 | // var id = req.params.id; 92 | // if(id=="Start"){ 93 | // mapviz= execFile('roslaunch',['mapviz','mapviz.launch'],function(err,stdout,stderr){ 94 | // if (err) { 95 | // console.log(err); 96 | // } 97 | // }); 98 | // console.log("Mapviz Started"); 99 | // res.send("Connected"); 100 | 101 | // } 102 | // else if(id=="End"){ 103 | // mapviz.kill(); 104 | 105 | // mapviz.on('exit',function(code){ 106 | // console.log(`Mapviz exit with ${code}`); 107 | // res.send("Disconnected"); 108 | // }); 109 | // } 110 | // }); 111 | 112 | var cam; 113 | app.post('/cam:id',function(req,res){ 114 | var id = req.params.id; 115 | if(id=="Start"){ 116 | cam= execFile('roslaunch',['usb_cam','usb_cam-test.launch'],function(err,stdout,stderr){ 117 | if (err) { 118 | console.log(err); 119 | } 120 | }); 121 | 122 | console.log("Camera Started"); 123 | res.send("Connected"); 124 | } 125 | else if(id=="End"){ 126 | cam.kill(); 127 | cam.on('exit',function(code){ 128 | console.log(`Camera exit with ${code}`); 129 | res.send("Disconnected"); 130 | }); 131 | } 132 | }); 133 | 134 | var autonomous; 135 | app.post('/autonomous:id',function(req,res){ 136 | var id = req.params.id; 137 | if(id=="Start"){ 138 | autonomous= execFile('roslaunch',['bot','autonomous.launch'],function(err,stdout,stderr){ 139 | if (err) { 140 | console.log(err); 141 | } 142 | }); 143 | console.log("Autonomous Task Started"); 144 | res.send("Connected"); 145 | } 146 | else if(id=="End"){ 147 | autonomous.kill(); 148 | autonomous.on('exit',function(code){ 149 | console.log(`Autonomous Task exit with ${code}`); 150 | res.send("Disconnected"); 151 | }); 152 | 153 | } 154 | }); 155 | 156 | 157 | 158 | app.listen(3000,function(){ 159 | console.log("Server running on 3000"); 160 | }) 161 | 162 | -------------------------------------------------------------------------------- /public/js/control.js: -------------------------------------------------------------------------------- 1 | $("#roscoreStart").click(function(event){ 2 | 3 | const Url = "http://localhost:3000/roscoreStart"; 4 | $.post(Url,function(data,status){ 5 | console.log(`${data} and Status is ${status}`); 6 | $("#roscoreStatus").text("Connected"); 7 | $("#roscoreStart").attr("disabled", true); 8 | $("#roscoreEnd").attr('disabled',false); 9 | }); 10 | 11 | event.preventDefault(); 12 | }); 13 | 14 | $("#roscoreEnd").click(function(event){ 15 | $("#roscoreEnd").attr('disabled',true); 16 | $("#roscoreEnd").attr('value','Disconnecting'); 17 | $("#roscoreStatus").text("Disconnecting..."); 18 | 19 | const Url = "http://localhost:3000/roscoreEnd"; 20 | $.post(Url,function(data,status){ 21 | console.log(`${data} and Status is ${status}`); 22 | $("#roscoreStatus").text("Closed"); 23 | $("#roscoreEnd").attr('value','End'); 24 | $("#roscoreStart").attr("disabled", false); 25 | }); 26 | event.preventDefault(); 27 | }); 28 | 29 | 30 | $("#gazeboStart").click(function(event){ 31 | 32 | const Url = "http://localhost:3000/gazeboStart"; 33 | $.post(Url,function(data,status){ 34 | console.log(`${data} and Status is ${status}`); 35 | $("#gazeboStatus").text("Connected"); 36 | $("#gazeboStart").attr("disabled", true); 37 | $("#gazeboEnd").attr('disabled',false); 38 | }); 39 | event.preventDefault(); 40 | }); 41 | 42 | $("#gazeboEnd").click(function(event){ 43 | $("#gazeboEnd").attr('disabled',true); 44 | $("#gazeboEnd").attr('value','Disconnecting'); 45 | $("#gazeboStatus").text("Disconnecting..."); 46 | const Url = "http://localhost:3000/gazeboEnd"; 47 | $.post(Url,function(data,status){ 48 | console.log(`${data} and Status is ${status}`); 49 | $("#gazeboStatus").text("Closed"); 50 | $("#gazeboEnd").attr('value','End'); 51 | $("#gazeboStart").attr("disabled", false); 52 | }); 53 | event.preventDefault(); 54 | }); 55 | 56 | $("#mapvizStart").click(function(event){ 57 | 58 | const Url = "http://localhost:3000/mapvizStart"; 59 | $.post(Url,function(data,status){ 60 | console.log(`${data} and Status is ${status}`); 61 | $("#mapvizStatus").text("Connected"); 62 | $("#mapvizStart").attr("disabled", true); 63 | $("#mapvizEnd").attr('disabled',false); 64 | }); 65 | event.preventDefault(); 66 | }); 67 | 68 | $("#mapvizEnd").click(function(event){ 69 | $("#mapvizEnd").attr('disabled',true); 70 | $("#mapvizEnd").attr('value','Disconnecting'); 71 | $("#mapvizStatus").text("Disconnecting..."); 72 | const Url = "http://localhost:3000/mapvizEnd"; 73 | $.post(Url,function(data,status){ 74 | console.log(`${data} and Status is ${status}`); 75 | $("#mapvizStatus").text("Closed"); 76 | $("#mapvizEnd").attr('value','End'); 77 | $("#mapvizStart").attr("disabled", false); 78 | }); 79 | event.preventDefault(); 80 | }); 81 | 82 | $("#camStart").click(function(event){ 83 | const Url = "http://localhost:3000/camStart"; 84 | $.post(Url, function(data, status){ 85 | console.log(`${data} and Status is ${status}`); 86 | $("#camStart").attr("disabled", true); 87 | $("#camEnd").attr('disabled', false); 88 | 89 | }); 90 | setTimeout(function(){ 91 | $("#video").attr("src", "http://localhost:8080/stream?topic=/usb_cam/image_raw"); 92 | $("#video").attr("src", "images/loading.png"); 93 | }, 2000); 94 | 95 | event.preventDefault(); 96 | }); 97 | 98 | $("#camEnd").click(function(event){ 99 | $("#camEnd").attr('disabled', true); 100 | $("#camEnd").attr('value', 'Disconnecting'); 101 | const Url = "http://localhost:3000/camEnd"; 102 | $.post(Url, function(data, status){ 103 | console.log(`${data} and Status is ${status}`); 104 | $("#camEnd").attr('value', 'End'); 105 | $("#camStart").attr("disabled", false); 106 | }); 107 | $("#video").attr("src", "images/camera1.png"); 108 | event.preventDefault(); 109 | }); 110 | 111 | $("#autonomousStart").click(function(event){ 112 | 113 | const Url = "http://localhost:3000/autonomousStart"; 114 | $.post(Url,function(data,status){ 115 | console.log(`${data} and Status is ${status}`); 116 | $("#autonomousStatus").text("Connected"); 117 | $("#autonomousStart").attr("disabled", true); 118 | $("#autonomousEnd").attr('disabled',false); 119 | }); 120 | event.preventDefault(); 121 | }); 122 | 123 | $("#autonomousEnd").click(function(event){ 124 | $("#autonomousEnd").attr('disabled',true); 125 | $("#autonomousEnd").attr('value','Disconnecting'); 126 | $("#autonomousStatus").text("Disconnecting..."); 127 | const Url = "http://localhost:3000/autonomousEnd"; 128 | $.post(Url,function(data,status){ 129 | console.log(`${data} and Status is ${status}`); 130 | $("#autonomousStatus").text("Closed"); 131 | $("#autonomousEnd").attr('value','End'); 132 | $("#autonomousStart").attr("disabled", false); 133 | }); 134 | event.preventDefault(); 135 | }); 136 | 137 | $(document).ready(function() { 138 | $('#switchTask').change(function() { 139 | if ($(this).is(':checked')) { 140 | enableManualControl(); 141 | } else { 142 | disableManualControl(); 143 | } 144 | }); 145 | }); 146 | 147 | function enableManualControl() { 148 | $('#autonomousStart, #autonomousEnd, #lat, #long, #autonomousReset, #enter').prop('disabled', false); 149 | $('#manual input').prop('disabled', true); 150 | } 151 | 152 | function disableManualControl() { 153 | $('#autonomousStart, #autonomousEnd, #lat, #long, #autonomousReset, #enter').prop('disabled', true); 154 | $('#manual input').prop('disabled', false); 155 | } 156 | 157 | 158 | -------------------------------------------------------------------------------- /public/css/style.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #ddf3e7; 3 | } 4 | 5 | .navbar { 6 | padding: .2% 5% .2% 5%; 7 | background-color: darkslategray!important; 8 | } 9 | 10 | .heading { 11 | font-size: 2.7rem; 12 | color: #ddf3e7!important; 13 | font-family:'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif; 14 | } 15 | 16 | .navbar-dark .navbar-nav .nav-link { 17 | font-family:'Gill Sans', 'Gill Sans MT', Calibri, 'Trebuchet MS', sans-serif!important; 18 | color: #ddf3e7!important; 19 | font-size: 1.3rem; 20 | } 21 | 22 | .navbar-dark .navbar-nav .nav-link:hover { 23 | color: #ddf3e7 !important; 24 | } 25 | 26 | .image_area{ 27 | border-color: darkslategray; 28 | border-style: solid; 29 | border-width: 2.5px; 30 | margin-right:40px!important; 31 | margin-left:40px!important; 32 | } 33 | 34 | .ctrlStatus { 35 | color: red; 36 | } 37 | 38 | .btn:hover { 39 | color: black; 40 | background-color: white; 41 | } 42 | 43 | .sidebar { 44 | background-color:darkslategray; 45 | } 46 | 47 | .nav { 48 | font-style: normal!important; 49 | font-display: rgb(184, 214, 204)!important; 50 | flex-wrap: nowrap; 51 | } 52 | 53 | .sidebarLi { 54 | margin-top: 6%; 55 | margin-bottom: 6%; 56 | } 57 | 58 | .rounded { 59 | border-radius: 1.25rem!important; 60 | } 61 | 62 | .btn-light { 63 | color: #000; 64 | background-color: #f8f9fa; 65 | border-color: #000000; 66 | border-style: solid; 67 | border-width: 2.5px; 68 | } 69 | 70 | .b-example-divider { 71 | flex-shrink: 0; 72 | width: 2.9rem; 73 | height: 92.7vh; 74 | background-color:linear-gradient(#967216,#A18232, #B19957, #C0AD79,#CDBE90)#ddf3e7; 75 | } 76 | 77 | main { 78 | display: flex; 79 | flex-wrap: nowrap; 80 | height: fit-content; 81 | height: -webkit-fill-available; 82 | overflow-x: auto; 83 | overflow-y: hidden; 84 | } 85 | 86 | .box { 87 | background-color: white; 88 | border-style: solid; 89 | border-color: darkslategray; 90 | border-radius: 0%; 91 | } 92 | 93 | #video { 94 | border-style: solid; 95 | border-radius: 0%; 96 | } 97 | 98 | .cam-btn { 99 | margin-top: 2%; 100 | text-align: center; 101 | } 102 | 103 | #camStart { 104 | margin-right: 5%; 105 | } 106 | 107 | #camEnd { 108 | margin-left: 5%; 109 | } 110 | 111 | .form-switch.form-switch-lg { 112 | padding-left: 6em; 113 | height: 0.5em; 114 | } 115 | 116 | .table_data{ 117 | background-color: #ddf3e7!important; 118 | border-style: solid!important; 119 | border-color: darkslategray!important; 120 | border-width: 2.5px!important; 121 | margin-right: 0px!important; 122 | margin-left: 0px!important; 123 | margin-top: 2.5px; 124 | margin-bottom:2.5px; 125 | } 126 | 127 | .form-switch.form-switch-lg .form-check-input { 128 | margin-left: -7em; 129 | height: 2em; 130 | width: 6em; 131 | border-color: darkslategray; 132 | border-style: solid; 133 | border-width: 2px; 134 | } 135 | 136 | img, svg { 137 | vertical-align: middle; 138 | border-color: darkslategray; 139 | border-style: solid; 140 | border-width: 2px; 141 | } 142 | 143 | .mt-4 { 144 | margin-top: 0.5rem!important; 145 | } 146 | 147 | .form-check-input:checked { 148 | background-color: darkslategray; 149 | border-color: darkslategray; 150 | } 151 | 152 | .pressed { 153 | box-shadow: 0 3px 4px 0 white; 154 | opacity: 0.3; 155 | } 156 | 157 | .auto-status-btn-left{ 158 | border-style: hidden; 159 | border-radius: 8% 0 0 8%; 160 | color:black; 161 | background-color:#eeeff0; 162 | padding:3%; 163 | } 164 | .auto-status-btn-right{ 165 | border-style: hidden; 166 | border-radius: 0 8% 8% 0; 167 | color:black; 168 | background-color:#eeeff0; 169 | padding:3%; 170 | } 171 | 172 | .auto-status-btn-active{ 173 | background-color:#0dcaf0; 174 | } 175 | 176 | .drawer{ 177 | margin-top: 10%; 178 | margin-bottom: 10%; 179 | } 180 | 181 | .btn-info { 182 | color: #000000; 183 | background-color: #60cd81; 184 | border-color: black; 185 | border-width: 2px; 186 | } 187 | 188 | .btn-info:disabled { 189 | color: #000000; 190 | background-color: #60cd81; 191 | border-color: black; 192 | border-width: 2px; 193 | } 194 | 195 | .btn-info:hover { 196 | color: rgb(0, 0, 0); 197 | background-color: rgb(195, 226, 240); 198 | border-color: #000000; 199 | border-width: 2px; 200 | } 201 | 202 | .btn-danger { 203 | color: #000000; 204 | background-color: #ff0000; 205 | border-color: black; 206 | border-width: 2px; 207 | } 208 | 209 | .btn-danger:disabled { 210 | color: #000000; 211 | background-color: #ff0000; 212 | border-color: black; 213 | border-width: 2px; 214 | } 215 | 216 | .btn-danger:hover{ 217 | color: #fff; 218 | background-color: #e9b597; 219 | border-color: black; 220 | border-width: 2px; 221 | } 222 | 223 | .contact1{ 224 | font-size: 3.5rem; 225 | color: darkslategray!important; 226 | } 227 | 228 | .about1{ 229 | font-size: 3.5rem; 230 | color: darkslategray!important; 231 | } 232 | 233 | .form-control { 234 | font-size: 1rem; 235 | color: #000000; 236 | border: 1px solid darkslategray; 237 | border-radius: 0rem; 238 | border-width: 2.5px; 239 | background-color: #ddf3e7 ; 240 | } 241 | 242 | .form-label{ 243 | margin:2.5px; 244 | } 245 | 246 | .about2{ 247 | font-size: 1.25rem; 248 | border: 2.5px solid darkslategray; 249 | padding: 15px; 250 | color: white; 251 | background-color: darkslategray; 252 | } 253 | 254 | 255 | .about3{ 256 | font-size: 1.25rem; 257 | border: 2.5px solid darkslategray; 258 | padding: 15px; 259 | color: white; 260 | background-color: darkslategray; 261 | } 262 | 263 | .about4{ 264 | font-size: 1rem; 265 | border: 2.5px solid darkslategray; 266 | padding: 15px; 267 | color: rgb(0, 0, 0); 268 | background-color: rgb(255, 255, 255); 269 | } 270 | 271 | .status{ 272 | margin-top: -0.5rem; 273 | margin-bottom: 0rem; 274 | } 275 | 276 | .reset{ 277 | padding: 0.4rem 0.65rem; 278 | font-size: 1rem; 279 | border-radius: 0.3rem; 280 | background-color: red; 281 | } -------------------------------------------------------------------------------- /views/about.ejs: -------------------------------------------------------------------------------- 1 | <%- include ('header') %> 2 | <%- include ('navbar_about') %> 3 | 4 |
5 |

About

6 |

7 | SWEEP provides an interface to operate ROS (Robot Operating System) based Bot from website. Interface 8 | provides two operating mode autonomous and manual control along with status of Bot in form of visual 9 | feed and sensor data. 10 |

11 |
12 |

Navigation Bar

13 | 29 |
30 |

Sidebar

31 | 63 |
64 |

Camera

65 |

66 | It provides video feed from Camera which is mounted on Bot. In backend, it runs MJPEG Server on your local machine and load 68 | image on web interface. 69 |

70 |
71 |

Detection

72 |

73 | It processes the image captured in camera and displays the image with description of waste using artifical intelligence and machine learning techniques. 74 |

75 |
76 |

Task Selection

77 |

78 | Default task is Manual Control which you can control from Manual Control and you can switch to Autonomous Control by activating switch. 79 |

80 |
81 |

Status

82 | 103 |
104 |

Data Analysis

105 |

106 | It tabulates the data obtained from detection process and give percentage of plastic and non plastic waste. 107 |

108 |
109 |

Manual Control

110 | 125 |
126 |

Autonomous Control

127 |

To operate in autonomous mode, we need to provide information about initial and final latitudes and longitudes. Then,you can start autonomous mode by pressing Start button. Bot strategically moves along the path shown in figure, maximizing area coverage to optimize waste collection. The robot autonomously navigates, skillfully avoiding obstacles to successfully complete its journey. 128 |

129 |
130 |
131 | <%- include ('footer') %> -------------------------------------------------------------------------------- /public/js/index.js: -------------------------------------------------------------------------------- 1 | window.onbeforeunload = function () { return 'Are you sure?' }; 2 | 3 | var ros; 4 | var twist; 5 | var cmdVel; 6 | var cmdVelAuto; 7 | var module_control_msg; 8 | var module_control_pub; 9 | 10 | var lat=[]; 11 | var long=[]; 12 | 13 | $("#webSocketStart").click(function () { 14 | var url = "http://localhost:3000/webSocketStart"; 15 | $.post(url, function (data, status) { 16 | console.log(`Data : ${data} and Status : ${status}`); 17 | $("#webSocketStart").attr('disabled', true); 18 | $("#webSocketEnd").attr('disabled', false); 19 | setTimeout(rosConnect(),2000); 20 | }) 21 | 22 | }); 23 | 24 | $("#webSocketEnd").click(function () { 25 | $("#socketStatus").text("Disconnecting..."); 26 | $("#webSocketEnd").attr('disabled', true); 27 | $("#webSocketEnd").attr('value', 'Disconnecting'); 28 | var url = "http://localhost:3000/webSocketEnd"; 29 | $.post(url, function (data, status) { 30 | console.log(`Data : ${data} and Status : ${status}`); 31 | $("#webSocketStart").attr('disabled', false); 32 | $("#webSocketEnd").attr('value', 'End'); 33 | }) 34 | 35 | }); 36 | 37 | function rosConnect() { 38 | ros = new ROSLIB.Ros({ 39 | url: 'ws://localhost:9090' 40 | }); 41 | 42 | ros.on('connection', function () { 43 | $("#socketStatus").text("Connected"); 44 | initVelocityPublisher(); 45 | initVelocitySubscriber(); 46 | initmodulevelocityPublisher(); 47 | console.log('Connected to websocket server.'); 48 | }); 49 | 50 | ros.on('error', function (error) { 51 | $("#socketStatus").text("Connecting..."); 52 | console.log('Error connecting to websocket server'); 53 | }); 54 | 55 | ros.on('close', function () { 56 | if(! $("#webSocketEnd").attr('disabled')){ 57 | setTimeout(rosConnect(),1000); 58 | } 59 | else{ 60 | $("#socketStatus").text("Closed"); 61 | $("#start").attr('disabled', false); 62 | console.log('Connection to websocket server closed.'); 63 | } 64 | }); 65 | }; 66 | 67 | 68 | var imuSub; 69 | $("#switchImu").change(function(){ 70 | let check = $("#switchImu").prop("checked"); 71 | if(check){ 72 | imuSub = new ROSLIB.Topic({ 73 | ros: ros, 74 | name: '/imu', 75 | messageType: 'sensor_msgs/Imu' 76 | }); 77 | 78 | imuSub.subscribe(function(msg) { 79 | let q = msg.orientation; 80 | let angle = Math.atan2(2.0*(q.w*q.z + q.x*q.y), 1 - 2.0*(q.y*q.y +q.z*q.z)); 81 | angle = angle*180/Math.PI +90; 82 | if(angle < 0 ){ 83 | angle += 360; 84 | } 85 | angle = Math.round(angle*100)/100; 86 | $("#imuData").text(angle); 87 | }); 88 | } 89 | else{ 90 | imuSub.unsubscribe(); 91 | $("#imuData").text(0.00); 92 | } 93 | }) 94 | 95 | var gpsSub; 96 | $("#switchGPS").change(function(){ 97 | let check = $("#switchGPS").prop("checked"); 98 | if(check){ 99 | gpsSub = new ROSLIB.Topic({ 100 | ros: ros, 101 | name: 'sensor_msgs/NavSatFix', 102 | messageType: 'sensor_msgs/NavSatFix' 103 | }); 104 | 105 | gpsSub.subscribe(function(msg) { 106 | $("#gpsLat").text(msg.latitude); 107 | $("#gpsLong").text(msg.longitude); 108 | }); 109 | } 110 | else{ 111 | gpsSub.unsubscribe(); 112 | $("#gpsLat").text(0); 113 | $("#gpsLong").text(0); 114 | } 115 | }) 116 | 117 | var autoStatusSub; 118 | $("#switchAuto").change(function(){ 119 | let check = $("#switchAuto").prop("checked"); 120 | if(check){ 121 | autoStatusSub = new ROSLIB.Topic({ 122 | ros: ros, 123 | name: '/gui_msg_topic', 124 | messageType: 'custom_msg/gui_msg' 125 | }); 126 | 127 | autoStatusSub.subscribe(function(msg) { 128 | console.log(msg) 129 | $("#goalDistance").text(msg.distance); 130 | $("#liveGoal").text(msg.goal_no); 131 | $("#gpsX").text(msg.location_x); 132 | $("#gpsY").text(msg.location_y); 133 | if(msg.flag_ob_avoid_or_g2g ==1 ){ 134 | $("#g2gTask").addClass("auto-status-btn-active"); 135 | $("#obaTask").removeClass("auto-status-btn-active") 136 | } 137 | else{ 138 | $("#obaTask").addClass("auto-status-btn-active"); 139 | $("#g2gTask").removeClass("auto-status-btn-active") 140 | } 141 | }); 142 | } 143 | else{ 144 | autoStatusSub.unsubscribe(); 145 | $("#goalDistance").text(0); 146 | $("#liveGoal").text(0); 147 | $("#gpsX").text(0); 148 | $("#gpsY").text(0); 149 | $("#g2gTask").removeClass("auto-status-btn-active"); 150 | $("#obaTask").removeClass("auto-status-btn-active") 151 | } 152 | }) 153 | 154 | 155 | $("#switchTask").change(function(){ 156 | let check = $("#switchTask").prop("checked"); 157 | if(check){ 158 | $(".controller").attr('disabled',true); 159 | $(".arm_controller").attr('disabled',true); 160 | navigator.keyboard.lock(); 161 | } 162 | else{ 163 | $(".controller").attr('disabled',false); 164 | $(".arm_controller").attr('disabled',false); 165 | navigator.keyboard.unlock(); 166 | } 167 | }); 168 | 169 | function initVelocityPublisher() { 170 | twist = new ROSLIB.Message({ 171 | linear: { 172 | x: 0.0, 173 | y: 0.0, 174 | z: 0.0 175 | }, 176 | angular: { 177 | x: 0.0, 178 | y: 0.0, 179 | z: 0.0 180 | } 181 | }); 182 | 183 | cmdVel = new ROSLIB.Topic({ 184 | ros: ros, 185 | name: '/cmd_vel', 186 | messageType: 'geometry_msgs/Twist', 187 | latch : true 188 | }); 189 | // cmdVel.advertise(); 190 | } 191 | 192 | function initVelocitySubscriber() { 193 | cmdVelAuto = new ROSLIB.Topic({ 194 | ros: ros, 195 | name: '/cmd_vel_auto', 196 | messageType: 'geometry_msgs/Twist', 197 | latch : true 198 | }); 199 | 200 | cmdVelAuto.subscribe(function(msg) { 201 | if($("#switchTask").prop("checked")){ 202 | twist.linear.x = Math.round(msg.linear.x*10000)/10000; 203 | twist.angular.z = Math.round(msg.angular.z*10000)/10000; 204 | if($("#switchSpeed").prop("checked")){ 205 | $("#cmdVelX").text(twist.linear.x); 206 | $("#cmdVelZ").text(twist.angular.z); 207 | } 208 | cmdVel.publish(twist); 209 | } 210 | }); 211 | } 212 | 213 | 214 | $("#switchSpeed").change(function(){ 215 | let check = $("#switchSpeed").prop("checked"); 216 | if(!check){ 217 | $("#cmdVelX").text(0); 218 | $("#cmdVelZ").text(0); 219 | } 220 | }); 221 | 222 | function speedPub(key) { 223 | if (key == "up" || key == "w" || key == "W") { 224 | animate("#up"); 225 | twist.linear.x = 1; 226 | twist.angular.z = 0; 227 | } 228 | else if (key == "down" || key == "s" || key == "S") { 229 | animate("#down"); 230 | twist.linear.x = -1; 231 | twist.angular.z = 0; 232 | } 233 | else if (key == "left" || key == "a" || key == "A") { 234 | animate("#left"); 235 | twist.angular.z = 1; 236 | twist.linear.x = 0; 237 | } 238 | else if (key == "right" || key == "d" || key == "D") { 239 | animate("#right"); 240 | twist.angular.z = -1; 241 | twist.linear.x = 0; 242 | } 243 | else if (key == "stop" || key == " ") { 244 | animate("#stop"); 245 | twist.linear.x = 0.0; 246 | twist.angular.z = 0.0; 247 | } 248 | twist.linear.x = Math.round(twist.linear.x*10000)/10000; 249 | twist.angular.z = Math.round(twist.angular.z*10000)/10000; 250 | if($("#switchSpeed").prop("checked")){ 251 | $("#cmdVelX").text(twist.linear.x); 252 | $("#cmdVelZ").text(twist.angular.z); 253 | } 254 | cmdVel.publish(twist); 255 | } 256 | 257 | $(document).on('keypress', function (event) { 258 | if($("#switchTask").prop("checked")==false){ 259 | speedPub(event.key); 260 | } 261 | }); 262 | 263 | $(".controller").click(function (event) { 264 | speedPub(this.id); 265 | }); 266 | 267 | function animate(currentBtn){ 268 | $(currentBtn).addClass("pressed"); 269 | setTimeout(function() {$(currentBtn).removeClass("pressed")},100); 270 | } 271 | 272 | 273 | $("#goalNumber").on('input',function (){ 274 | let num = $("#goalNumber").val(); 275 | if(num){ 276 | $("#goalBtn").attr('disabled',false); 277 | } 278 | else{ 279 | $("#goalBtn").attr('disabled',true); 280 | } 281 | }); 282 | 283 | $(".cordinates").on('input',function(){ 284 | let _lat = $("#lat").val(); 285 | let _long =$('#long').val(); 286 | 287 | if(_lat && _long){ 288 | $("#enter").attr('disabled',false); 289 | } 290 | else{ 291 | $("#enter").attr('disabled',true); 292 | } 293 | }); 294 | 295 | $("#enter").click(function(){ 296 | let currGoal = $('#currGoal').text(); 297 | let totalGoal = $("#goalNumber").val(); 298 | if(currGoal < totalGoal){ 299 | lat.push(parseFloat($("#lat").val())); 300 | long.push(parseFloat($('#long').val())); 301 | $("#lat").val(''); 302 | $('#long').val(''); 303 | $('#currGoal').text(parseInt(currGoal)+1); 304 | } 305 | else{ 306 | lat.push(parseFloat($("#lat").val())); 307 | long.push(parseFloat($('#long').val())); 308 | $("#lat").attr('disabled',true); 309 | $('#long').attr('disabled',true); 310 | $("#enter").attr('disabled',true); 311 | 312 | initLatPublisher(lat); 313 | initLongPublisher(long); 314 | $("#autonomousStart").attr("disabled",false); 315 | } 316 | 317 | }); 318 | 319 | function initLatPublisher(lat) { 320 | var latCord = new ROSLIB.Message({ 321 | data : [ ] 322 | }); 323 | 324 | var latPub = new ROSLIB.Topic({ 325 | ros: ros, 326 | name: '/goal_latitude', 327 | messageType: 'std_msgs/Float64MultiArray', 328 | latch : true 329 | }); 330 | latCord.data = lat; 331 | latPub.publish(latCord); 332 | } 333 | 334 | function initLongPublisher(long) { 335 | var longCord = new ROSLIB.Message({ 336 | data : [ ] 337 | }); 338 | 339 | var longPub = new ROSLIB.Topic({ 340 | ros: ros, 341 | name: '/goal_longitude', 342 | messageType: 'std_msgs/Float64MultiArray', 343 | latch : true 344 | }); 345 | longCord.data = long; 346 | longPub.publish(longCord); 347 | } 348 | 349 | 350 | $("#goalBtn").click(function(event){ 351 | event.preventDefault(); 352 | let num = $("#goalNumber").val(); 353 | $("#goalBtn").attr('disabled',true); 354 | $("#goalNumber").attr('disabled',true); 355 | $("#lat").attr('disabled',false); 356 | $('#long').attr('disabled',false); 357 | $('#currGoal').text(1); 358 | }); 359 | 360 | 361 | $("#autonomousReset").click(function(){ 362 | lat=[]; 363 | long=[]; 364 | $("#lat").val(''); 365 | $('#long').val(''); 366 | $('#currGoal').text(0); 367 | $("#goalNumber").attr('disabled',false); 368 | $("#goalNumber").val(''); 369 | }); 370 | 371 | 372 | function initmodulevelocityPublisher() { 373 | module_control_msg = new ROSLIB.Message({ 374 | layout:{ 375 | dim:[{},{},{}], 376 | data_offset:0 377 | },data:[0,0,0] 378 | }); 379 | 380 | module_control_pub= new ROSLIB.Topic({ 381 | ros: ros, 382 | name: '/Don', 383 | messageType: 'std_msgs/Int32MultiArray', 384 | latch : true 385 | }); 386 | // cmdVel.advertise(); 387 | } 388 | 389 | 390 | 391 | --------------------------------------------------------------------------------