The weekly assignment was:
To build my final project, i've tried to use the greatest number possible of processes that i've
learned during the whole FabAcademy. Actually i've used the following processes to develop different parts of the
project:
I've used Solid Works to design the wheels and the frame of the Snail. The following are the final models that i've used to build the robot (DOWNLOAD wheel - track - frame).
I was not able to design the shell using SolidWorks so i've used Rhinoceros (see week5 - 3D scanning and printing for more info) (DOWNLOAD Shell).
I've used also blender to make a boolean operation on the stl of the shell to make an holed of the dimension of the electronic board that hold
the electronic part of the project.
I've used PLA to print the wheels, the frame and the shell while i've used NinjaFlex filament (a rubber-like filament) to print the track.
I'm still not using the track because is really difficult to put it in tension between the wheels but i'm planning to use it in the final
project.
I've used a Particle Photon board for my final project.
It is supposed to cost $19 but my instructor Fiore stole it during a faire so i've stolen
it from him.
I've then builded a brackout board to integrate the photon with the circuit needed to read two sensors,a photoresistor and a thermistor,
with a switch to power on and off the board and with two connectors for two servomotors. I've also realized a very small piece of PCB for the smd thermistor. (DOWNLOAD photon.sch - photon.brd,
therm_adaptor.brd):
I've found that taking the power from the Vin pin of the photon instead that from the 3v3 pin, can result in continuos resets if you have other
components that absorbs electricity (in my case i had two servomotors).
This is the final result:
As said, i've used the Particle Photon board. This board, has an integrated WiFi and uses a cloud siystem for handling the data.
The documentation is really well written and this result
in an easy-to-use system. To be short, is possible to connect the board to any network and to publish variables and functions over the cloud.
The board has a unique address and a token which can be used to retrieve data and to identify it.
There are two IDEs, one online and one offline and is possible to write firmware and upload that to the board via WiFi.
I will describe better what i've done with the board in the next paragraphs but for now, i want to highlight the fact that
i've decided to integrated a WiFi based board to have more flexibility in the project and to control the funcionalities of the Snail
withouth the need of any cables.
I've used two sensors as input devices, a photoresistor and a thermistor. As explained here
and here, i've already used this two sensors during
the previous weeks of FabAcademy and i've decided to include them in my final project. Trying to be creative, i've soldered this sensor
on my board in a way that they can look like the antennas of the Snail:
I've used the two servomotors as output devices. I can control them directly from the web and i can move them separately.
In this way i can control the turning of the Snail; if i have to turn the robot left, i simply spin the right motor forward
and the left motor backward (and the other way around if i have to turn it right).
At the beginning, i wanted to use two continuos rotation servomotors but i did not have this kind of motors in the Lab. I've
then decided to modify two normal servos that are in the inventory. There are 10000 tutorials everywhere that explain how to
easily modify a servomotor:
To program the particle, i've used the ParticleDev IDE and this is the firmware that i wrote.
#include <math.h>
Servo myservoL;
Servo myservoR;
int led = D7; // This is where your LED is plugged in. The other side goes to a resistor connected to GND.
int photoresistor = A0; // This is where your photoresistor is plugged in. The other side goes to the "power" pin (below).
int ThermistorPIN = A1;
int power = A5; // This is the other end of your photoresistor. The other side is plugged into the "photoresistor" pin (above).
// The reason we have plugged one side into an analog pin instead of to "power" is because we want a very steady voltage to be sent to the photoresistor.
// That way, when we read the value from the other side of the photoresistor, we can accurately calculate a voltage drop.
int analogvalue; // Here we are declaring the integer variable analogvalue, which we will use later to store the value of the photoresistor.
int analogvalue2;
float res = 10000; //fixed resistance that i've used for the voltage divider
float resx; //variable resistance
float logresx;
float T;
float c1 = 1.009249522e-03, c2 = 2.378405444e-04, c3 = 2.019202697e-07;
double voltage;
double temp;
void setup() {
pinMode(power,OUTPUT); // The pin powering the photoresistor is output (sending out consistent power)
// write the power of the photoresistor so that we can use this for power.
digitalWrite(power,HIGH);
// We are going to declare a Particle.variable() here so that we can access the value of the photoresistor from the cloud.
Particle.variable("analogvalue", &analogvalue,INT);
Particle.variable("temp", &temp, DOUBLE);
// We are also going to declare a Spark.function so that we can turn the LED on and off from the cloud.
Spark.function("led",ledToggle);
// This is saying that when we ask the cloud for the function "led", it will employ the function ledToggle() from this app.
Serial.begin(115200);
delay(200);
}
// Next is the loop function...
void loop() {
// photoresistor and thermistor analogvalue
analogvalue = analogRead(photoresistor);
analogvalue2 = analogRead(ThermistorPIN);
//some maths for the voltage divider
resx = res*(4096/float(analogvalue2) - 1);
logresx = log(resx);
T = ( 1.0 / (c1 + c2*logresx + c3*logresx*logresx*logresx ) ) - 273.15;
temp = double(T);
//Serial debugging
Serial.print("RAW: ");
Serial.print(analogvalue2);
Serial.print(" resx: ");
Serial.print(resx);
Serial.print(" log: ");
Serial.print(logresx);
Serial.print(" temp: ");
Serial.println(T);
delay(200);
}
// Function definition. The integrated LED lights up when a command is recieved
//and the servos move accordingly to the commands recieved
int ledToggle(String command) {
if (command=="on_for") {
myservoL.attach(A4);
myservoR.attach(D0);
delay(10);
myservoL.write(0);
myservoR.write(0);
delay(150);
digitalWrite(led,HIGH);
return 1;
}
else if (command=="on_back") {
myservoL.attach(A4);
myservoR.attach(D0);
delay(10);
myservoL.write(180);
myservoR.write(180);
delay(150);
digitalWrite(led,HIGH);
return 1;
}
else if (command=="on_left") {
myservoL.attach(A4);
myservoR.attach(D0);
delay(10);
myservoL.write(180);
myservoR.write(0);
delay(150);
digitalWrite(led,HIGH);
return 1;
}
else if (command=="on_right") {
myservoL.attach(A4);
myservoR.attach(D0);
delay(10);
myservoL.write(0);
myservoR.write(180);
delay(150);
digitalWrite(led,HIGH);
return 1;
}
else if (command=="off") {
myservoL.attach(A4);
myservoR.attach(D0);
delay(10);
myservoL.write(90);
myservoR.write(90);
delay(150);
myservoL.detach();
myservoR.detach();
digitalWrite(led,LOW);
delay(200);
return 0;
}
else {
return -1;
}
}
I've decided to build a web interface for the Snail. I've used the bootstrap framework (the same that i've used
to build this website).From the interface, is possible to see the data coming from the two sensors of the robot and
to move it in 4 directions. The interface is accessible here.
For the complete code of the interface, just inspet the source code of the page.
The following code, is the core of the interface:
$(document).ready(function(){
var dps = []; // dataPoints
var dps2 = [];
var chart = new CanvasJS.Chart("chartContainer",{
title :{
text: "Snail Light"
},
data: [{
type: "line",
dataPoints: dps
}]
});
var chart2 = new CanvasJS.Chart("chartContainer2",{
title :{
text: "Snail Temperature"
},
data: [{
type: "line",
dataPoints: dps2
}]
});
var xVal = 0;
var yVal = 100;
var yVal2 = 40;
var updateInterval = 100;
var dataLength = 20; // number of dataPoints visible at any point
var token = "dcd4dec3651a29adefcd98da966dfe2987e6ad92";
var device_id = "37003e001447343338333633";
var prefix = "https://api.particle.io/v1/devices/"
//---------------FUNCTION TO READ SENSORS------------------------//
var poll = function(){
$.get(prefix + device_id + '/' + "analogvalue" +'?access_token=' +token, function(data){
if (data.result) {
var base = Number(data.result);
var reading = Math.min(100,Math.round(base/1024*100));
$('#analogvalue').html( reading + '%');
}
});
$.get(prefix + device_id + '/' + "temp" +'?access_token=' +token, function(data){
if (data.result) {
var base = Number(data.result);
var reading = Math.min(100,Math.round(base));
$('#temp').html( reading + '°C');
}
});
};
//-------------FUNCTION TO GENERATE THE GRAPHS-----------------//
var updateChart = function (count) {
$.get(prefix + device_id + '/' + "analogvalue" +'?access_token=' +token, function(data){
if (data.result) {
var base = Number(data.result);
var reading = Math.min(100,Math.round(base/1024*100));
count = count || 1;
// count is number of times loop runs to generate dataPoints.
for (var j = 0; j < count; j++) {
dps.push({
x: xVal,
y: reading
});
xVal++;
};
if (dps.length > dataLength)
{
dps.shift();
}
chart.render();
}
});
$.get(prefix + device_id + '/' + "temp" +'?access_token=' +token, function(data){
if (data.result) {
var base = Number(data.result);
var reading = Math.min(100,Math.round(base));
count = count || 1;
// count is number of times loop runs to generate dataPoints.
for (var j = 0; j < count; j++) {
dps2.push({
x: xVal,
y: reading
});
xVal++;
};
if (dps2.length > dataLength)
{
dps2.shift();
}
chart2.render();
}
});
};
//------------FUNCTION TO SEND COMMANDS------------------//
var sendCmd = function(cmd){
$("#loading").show();
$.post(prefix + device_id + '/led',
{
access_token: token,
params: cmd
},
function(data){
console.log(data);
$("#loading").hide();
});
};
//-----------------EVENTS TO DRIVE THE MOTORS-------------------//
$('#forward').mousedown(function(e){
e.preventDefault();
sendCmd("on_for");
});
$('#forward').mouseup(function(e){
e.preventDefault();
sendCmd("off");
});
$('#backward').mousedown(function(e){
e.preventDefault();
sendCmd("on_back");
});
$('#backward').mouseup(function(e){
e.preventDefault();
sendCmd("off");
});
$('#left').mousedown(function(e){
e.preventDefault();
sendCmd("on_left");
});
$('#left').mouseup(function(e){
e.preventDefault();
sendCmd("off");
});
$('#right').mousedown(function(e){
e.preventDefault();
sendCmd("on_right");
});
$('#right').mouseup(function(e){
e.preventDefault();
sendCmd("off");
});
updateChart(dataLength);
setInterval(updateChart,3000);
poll();
setInterval(poll,3000);
});
I want to make some improvements to the project before the end of the Fab Academy which are:
This is the archive containing all the files of my final project DOWNLOAD
In the end, it comes out that......she wants to be wild :)