Introduction
To connect Arduino to internet, we need to use some kind of internet shield such as Ethernet shield, Wifi shield, PHPoC shield, or PHPoC Wifi shield.
The outstanding feature of PHPoC shield is that it not only provides Internet connection like Ethernet and Wifi shield, but also provides a web server which allows to control and monitor Arduino from a web browser. It also supports WebSocket, therefore we can control and monitor Arduino in real-time without reloading a webpage.
PHPoC Shield has some built-in web applications. Refer to this link https://www.hackster.io/phpoc_man/ar...bsocket-056f16 for more detail.
In this project, I changed UI (User Interface) of Web Remote Control/Slide web application, and wrote Arduino code to rotate servo motor angle according to angle received from web browser.
Things Used In This Project
- Arduino Uno
- USB cable for Arduino
- PHPoC shield or PHPoC Wifi Shield
- Servo motor
- Jumper wires
Wiring Diagram
- Stack PHPoC shield on Arduino
- Connect pin GND, VCC and signal of servo motor to GND, 5V and pin 9 of Arduino, respectively.
Data Flow
Web browser ---> PHPoC Shield ---> Arduino
Web app will calculates the angle based on touch or mouse event, send it to PHPoC shield via websocket. When receiving this data, PHPoC shield passes it to Arduino. Arduino rotates servo motor according to the angle.
What Need to Do
- Set Wifi information for PHPoC shield (SSID and password)
- Upload new UI to PHPoC shield
- Write Arduino code
Setting Wifi information for PHPoC shield
See this instruction: http://www.phpoc.com/support/manual/...rk_first_setup
Upload new UI to PHPoC shield
- Create remote_rotate.php file with content
PHP Code:<!DOCTYPE html>
<html>
<head>
<title>PHPoC Shield - Web Remote Control for Arduino</title>
<meta name="viewport" content="width=device-width, initial-scale=0.7, maximum-scale=0.7">
<style>
body { text-align: center; font-size: 15pt; }
h1 { font-weight: bold; font-size: 25pt; }
h2 { font-weight: bold; font-size: 15pt; }
button { font-weight: bold; font-size: 15pt; }
</style>
<script>
var canvas_width = 400, canvas_height = 400;
var plate_radius = 160;
var click_state = 0;
var last_plate_angle = 0
var plate_angle = 0, last_angle = 0;
var ws;
function init()
{
var canvas = document.getElementById("remote");
canvas.addEventListener("touchstart", mouse_down);
canvas.addEventListener("touchend", mouse_up);
canvas.addEventListener("touchmove", mouse_move);
canvas.addEventListener("mousedown", mouse_down);
canvas.addEventListener("mouseup", mouse_up);
canvas.addEventListener("mousemove", mouse_move);
var ctx = canvas.getContext("2d");
ctx.translate(canvas_width / 2, canvas_height / 2);
rotate_plate(0);
}
function connect_onclick()
{
if(ws == null)
{
var ws_host_addr = "<?echo _SERVER("HTTP_HOST")?>";
var debug = document.getElementById("debug");
if((navigator.platform.indexOf("Win") != -1) && (ws_host_addr.charAt(0) == "["))
{
// network resource identifier to UNC path name conversion
ws_host_addr = ws_host_addr.replace(/[\[\]]/g, '');
ws_host_addr = ws_host_addr.replace(/:/g, "-");
ws_host_addr += ".ipv6-literal.net";
}
//debug.innerHTML = "<br>" + navigator.platform + " " + ws_host_addr;
ws = new WebSocket("ws://" + ws_host_addr + "/remote_slide", "text.phpoc");
document.getElementById("ws_state").innerHTML = "CONNECTING";
ws.onopen = ws_onopen;
ws.onclose = ws_onclose;
ws.onmessage = ws_onmessage;
}
else
ws.close();
}
function ws_onopen()
{
document.getElementById("ws_state").innerHTML = "<font color='blue'>CONNECTED</font>";
document.getElementById("bt_connect").innerHTML = "Disconnect";
}
function ws_onclose()
{
document.getElementById("ws_state").innerHTML = "<font color='gray'>CLOSED</font>";
document.getElementById("bt_connect").innerHTML = "Connect";
ws.onopen = null;
ws.onclose = null;
ws.onmessage = null;
ws = null;
}
function ws_onmessage(e_msg)
{
e_msg = e_msg || window.event; // MessageEvent
alert("msg : " + e_msg.data);
}
function rotate_plate(angle)
{
var canvas = document.getElementById("remote");
var ctx = canvas.getContext("2d");
ctx.clearRect(-canvas_width / 2, -canvas_height / 2, canvas_width, canvas_height);
ctx.rotate(angle / 180 * Math.PI);
ctx.strokeStyle="red";
ctx.fillStyle="red";
ctx.beginPath();
ctx.arc(0, 0, plate_radius, Math.PI, Math.PI * 1.5);
ctx.lineTo(0, 0);
ctx.lineTo(-plate_radius, 0);
ctx.fill();
ctx.stroke();
ctx.strokeStyle="blue";
ctx.fillStyle="blue";
ctx.beginPath();
ctx.arc(0, 0, plate_radius, 0, Math.PI / 2);
ctx.lineTo(0, 0);
ctx.lineTo(plate_radius, 0);
ctx.fill();
ctx.stroke();
ctx.strokeStyle="black";
ctx.arc(0, 0, plate_radius, 0, Math.PI * 2);
ctx.stroke();
ctx.rotate(-angle / 180 * Math.PI);
}
function mouse_down()
{
if(ws == null)
return;
var dist_min, dist_max, dist;
event.preventDefault();
if(event.offsetX)
{
x = event.offsetX - canvas_width / 2;
y = canvas_height / 2 - event.offsetY;
dist_min = 40;
dist_max = plate_radius;
}
else if(event.layerX)
{
x = event.layerX - canvas_width / 2;
y = canvas_height / 2 - event.layerY;
dist_min = 40;
dist_max = canvas_width / 2;
}
else
{
x = (Math.round(event.touches[0].pageX - event.touches[0].target.offsetLeft)) - canvas_width / 2;
y = canvas_height / 2 - (Math.round(event.touches[0].pageY - event.touches[0].target.offsetTop));
dist_min = 40;
dist_max = canvas_width / 2;
}
var dist = Math.round(Math.sqrt(x * x + y * y));
if((dist > dist_min) && (dist < dist_max))
{
click_state = 1;
last_angle = Math.round(Math.atan2(y, x) / Math.PI * 180);
}
}
function mouse_up()
{
if(ws == null)
return;
event.preventDefault();
click_state = 0;
}
function mouse_move()
{
if(ws == null)
return;
var dist_min, dist_max, angle, dist;
event.preventDefault();
if(!click_state)
return;
if(event.offsetX)
{
x = event.offsetX - canvas_width / 2;
y = canvas_height / 2 - event.offsetY;
dist_min = 40;
dist_max = plate_radius;
}
else if(event.layerX)
{
x = event.layerX - canvas_width / 2;
y = canvas_height / 2 - event.layerY;
dist_min = 40;
dist_max = canvas_width / 2;
}
else
{
x = (Math.round(event.touches[0].pageX - event.touches[0].target.offsetLeft)) - canvas_width / 2;
y = canvas_height / 2 - (Math.round(event.touches[0].pageY - event.touches[0].target.offsetTop));
dist_min = 40;
dist_max = canvas_width / 2;
}
angle = Math.round(Math.atan2(y, x) / Math.PI * 180);
dist = Math.round(Math.sqrt(x * x + y * y));
if((dist < dist_min) || (dist > dist_max))
{
click_state = 0;
return;
}
if((Math.abs(angle) > 90) && (angle * last_angle < 0))
{
if(last_angle > 0)
last_angle = -180;
else
last_angle = 180;
}
plate_angle += (angle - last_angle);
last_angle = angle;
if(plate_angle > 180)
plate_angle = 180;
if(plate_angle < 0)
plate_angle = 0;
rotate_plate(-plate_angle);
if(plate_angle != last_plate_angle)
{
if(ws && ws.readyState)
{
ws.send("C" + plate_angle.toString() + "\r\n");
last_plate_angle = plate_angle;
debug = document.getElementById("debug");
debug.innerHTML = plate_angle;
//console.log(plate_angle);
}
}
}
window.onload = init;
</script>
</head>
<body>
<p>
<h1>Web Remote Control / Rotate</h1>
</p>
<canvas id="remote" width="400" height="400"></canvas>
<h2>
<p>
WebSocket : <span id="ws_state">null</span><br>
Angle : <span id="debug">0</span>
</p>
<button id="bt_connect" type="button" onclick="connect_onclick();">Connect</button>
</h2>
</body>
</html> - Upload it to PHPoC shield using PHPoC debugger http://www.phpoc.com/common/download...are/PHPoCD.zip according to this instruction http://www.phpoc.com/support/manual/...d=major_upload
Write Arduino code
- Install library for Arduino on Arduino IDE (see the instruction http://www.phpoc.com/support/manual/...=library_setup ) and restart Arduino IDE
- On Arduino IDE, go to File -> Examples -> Phpoc -> WebRemoteSlide and File -> Examples ->Servo->sweep.
- Combine two examples into one, we have the code to control servo motor via webpage
Code:/* arduino web server - remote control (slide switch) */ #include "SPI.h" #include "Phpoc.h" #include <Servo.h> PhpocServer server(80); Servo myservo; // create servo object to control a servo char slideName; int slideValue; void setup() { Serial.begin(9600); while(!Serial) ; Phpoc.begin(PF_LOG_SPI | PF_LOG_NET); //Phpoc.begin(); server.beginWebSocket("remote_slide"); Serial.print("WebSocket server address : "); Serial.println(Phpoc.localIP()); myservo.attach(9); // attaches the servo on pin 9 to the servo object myservo.write(1); } void loop() { // wait for a new client: PhpocClient client = server.available(); if (client) { String slideStr = client.readLine(); if(slideStr) { slideValue = slideStr.substring(1).toInt(); myservo.write(slideValue); Serial.print("Angle: "); Serial.println(slideValue); } } }
Testing
- Click Serial button on Arduino IDE to see the IP address
- Open web browser, type http://replace_ip_address/remote_rotate.php
- Click connect button and test it
Function References