This project has grown a lot since original conception to become Light Share. Whilst building this smart system, our group figured out how to control, syndicate and automate systems remotely, in many locations simultaneously.
The outcome is fairly simple and clean. The process by which this system operates, however, is relatively complex (for beginners anyhow).
Check out some of the landmarks on the way to achieving communication between the physical, digital and cyber elements of Light Share in my previous posts.
--------------------------------------------------------------
Concept and Direction
We set out to design a smart system, which allows people to interact with others from multiple locations, using physical and digital programing to share resource and responsibility for decisions of energy consumption within the network.
Two key principles of this project are;
- We affect others by our actions and the amount of resource we use day-to-day.
- We don't have enough resource for every one in the world unless we share more fairly.
--------------------------------------------------------------
Start Up
Initially we were going to have buttons to request light and approve others to have light. This presented us with the first major battle - making two systems, in seperate locations talk to each other via the net.
We used http://www.pachube.com/ as our data host, each member of the team regestering thier own account and feeds.
We used 'Standard Firmata', 'servo_sweep', 'button' and 'FirstContact' (Tom Igoe) examples to get this working - First from my button to Judit's servo, then both controlling one-anothers servo's.
The problem we encountered here was that StandardFirmata didn't cooperate to control servo's and we couldn't figure out how to integrate the 'ServoFirmata' code.
First, we figured out how to communicate between Processing and Arduino, to send values from Arduino components and drive the servo;
//processing language;
import processing.serial.*;
Serial myPort;
//float bgcolor; // Background color
float fgcolor; // Fill color
float xpos, ypos; // Starting position of the ball
boolean firstContact = false;
boolean controlServo = false;
void setup() {
size(640,480);
println(Serial.list());
myPort = new Serial(this, Serial.list()[0], 9600);
myPort.bufferUntil('\n');
}
void draw() {
background(255);
fill(fgcolor);
// Draw the shape
ellipse(xpos, ypos, 20, 20);
}
bufferUntil()
void serialEvent(Serial myPort) {
String myString = myPort.readStringUntil('\n');
if (myString != null) {
myString = trim(myString);
if (firstContact == false) {
if (myString.equals("hello")) {
myPort.clear();
firstContact = true;
myPort.write('A');
println(firstContact);
}
}
else {
int sensors[] = int(split(myString, ','));
for (int sensorNum = 0; sensorNum <>
println(); if (sensors.length > 1) {
xpos = map(sensors[0], 0,400,0,width);
ypos = map(sensors[1], 0,400,0,height);
fgcolor = sensors[2] * 255;
if (sensors[2] == 1){
myPort.write("B");
} else {
myPort.write("C");
}
}
}
myPort.write("A");
}
}
Processing sends a button state reading (0 = 'off', 1 = on) to pachube.com, reads the state value from another feed, then sends an ASCII value to Arduino to control the position of the servo/switch.
Below is the arduino version of our FirstContact sketch variation;
int analogOne = 0; // analog input
int analogTwo = 1; // analog input
int digitalOne = 2; // digital input
int sensorValue = 0; // reading from the sensor
int servoControl;
#include
Servo myservo;
//int pos = 0;
void setup() {
// configure the serial connection:
Serial.begin(9600);
// configure the digital input:
pinMode(digitalOne, INPUT);
myservo.attach(9);
establishContact();
}
void loop() {
if (Serial.available() > 0) {
int inByte = Serial.read();
sensorValue = analogRead(analogOne);
Serial.print(sensorValue, DEC);
Serial.print(",");
sensorValue = analogRead(analogTwo);
Serial.print(sensorValue, DEC);
Serial.print(",");
sensorValue = digitalRead(digitalOne);
Serial.println(sensorValue, DEC);
if(inByte == 66){
myservo.write(180);
}
if(inByte == 67){
myservo.write(0);
}
}
}
void establishContact() {
while (Serial.available() <= 0) { Serial.println("hello"); // send a starting message delay(300); } }
------------------------------------------------------------
Pachube Drama
A big block in the road came in the form of pachube's upload/download resrictions. You can access or upload data once every 3.5 seconds aprox with a single API key. This meant that when it came to updating 1 stream and listening for others we had to have massive delays to prevent pachube from freezing our accounts (which happened many times anyway).
As we wanted multiple info streams to intergate all members of the group into the system, we had to find a way to circumvent this issue.
We discovered two possible solutions so we split the group in 2;
Judit and I worked by building onto our adaptation of FirstContact, intergating an LDR as a control device, into what we had already achieved so far in previous versions.
Jacques found a sketch called Pachuino on the net.
The Pachuino code proved to be concise but unstable when trying to use multiple feeds, due to Pachubes feed usage cap.
Below is a copy of Mine and Judit's code. This allowed us to achieve the goal of simultaneously controlling one-anothers servo's;
import processing.serial.*;
Serial myPort;
boolean firstContact = false
boolean controlServo = false;
//setup for pachube recieving
import eeml.*;
DataIn dIn;
float myVariable;
//setup for pachube sending
DataOut dOut;
float lastUpdate;
int buttonState =0;
void setup() {
println(Serial.list());
myPort = new Serial(this, Serial.list()[0], 9600);
myPort.bufferUntil('\n');
// set up DataIn object; indicate the URL you want, your Pachube API key, and how often you want it to update
dIn = new DataIn(this,"http://www.pachube.com/api/feeds/7584.xml",
"YourAPIcodegoeshere", 7000);
// set up DataOut object; requires URL of the EEML you are updating, and your Pachube API key
dOut = new DataOut(this, "http://www.pachube.com/api/feeds/7472.xml",
"YourAPIcodegoeshere");
dOut.addData(2,"button");
dOut.addData(3,"ldr");
}
void draw() {
background(255);
}
bufferUntil()
void serialEvent(Serial myPort) {
// read the serial buffer:
String myString = myPort.readStringUntil('\n');
// if you got any bytes other than the linefeed:
if (myString != null) {
myString = trim(myString);
// if you haven't heard from the microncontroller yet, listen:
if (firstContact == false) {
if (myString.equals("hello")) {
myPort.clear(); // clear the serial port buffer
firstContact = true; // you've had first contact from the microcontroller
myPort.write('A'); // ask for more
println(firstContact);
}
}
// if you have heard from the microcontroller, proceed:
else {
int sensors[] = int(split(myString, ','));
// print out the values you got:
for (int sensorNum = 0; sensorNum <> 1) {
if (myVariable == 1){
myPort.write("B");
} else {
myPort.write("C");
}
println(sensors[0]);
//send data to pachube
if ((millis() - lastUpdate) > 7000){
if(sensors[0] < response =" dOut.updatePachube();" lastupdate =" millis();" myvariable =" d.getValue(2);">
}
--------------------------------------------------------------
Remote Communication During the Project
Skype was very handy for extra communication when working from different locations. This became most evident when we had finalised the code and we're ready to implement the system from our homes, via the web.
Also, we were able to do troubleshooting from home, walking each other through possible solutions. We even encountered our lecturer in the computer lab whilst doing a remote troubleshooting session. Awesome.
-----------------------------------------------
Concept and Operation Refinement
Once we had the button/LDR/pachube/servo sketches working we spotted a flaw in our logic, which stemmed from the conceptual roots of our project.
The issue came to the surface when we started trying to describe the meaning behind what was taking palce in our system. To sort this we wrote out 6 or 7 diagram variations of the logic and interactions we were trying to achieve, then eliminated possibilities as we discovered blocks.
Finally we reached a solution that would make sense to the user, be possible to code, was practical, could be built upon and applied to different applications, and have strong conceptual grounding...
float timer, LDRvalue, scaledLDR;
void setup(){
Serial.begin(9600);
timer = 0;
}
void loop() {
LDRvalue = analogRead(1);
if (LDRvalue > 100){
scaledLDR = LDRvalue/100;
timer = timer + scaledLDR;
Serial.println(timer);
delay(1000);
}
}
-----------------------------------------------
Working eeml/FirstContact/Serial Code
import processing.serial.*;
Serial myPort;
boolean firstContact = false;
boolean controlServo = false;
//setup for pachube recieving
import eeml.*;
DataIn dIn;
float myVariable;
//setup for pachube sending
DataOut dOut;
float lastUpdate;
int buttonState =0;
void setup() {
println(Serial.list());
myPort = new Serial(this, Serial.list()[1], 9600);
myPort.bufferUntil('\n');
dIn = new DataIn(this,"http://www.pachube.com/api/feeds/7344.xml",
"YourAPIcodehere", 7000);
dOut = new DataOut(this, "http://www.pachube.com/api/feeds/7472.xml",
"YourAPIcodehere");
dOut.addData(4,"musValue");
}
void draw() {
background(255);
}
void serialEvent(Serial myPort) {
// read the serial buffer:
String myString = myPort.readStringUntil('\n');
// if you got any bytes other than the linefeed:
if (myString != null) {
myString = trim(myString);
// if you haven't heard from the microncontroller yet, listen:
if (firstContact == false) {
if (myString.equals("hello")) {
myPort.clear(); // clear the serial port buffer
firstContact = true; // you've had first contact from the microcontroller
myPort.write('A'); // ask for more
println(firstContact);
}
}
// if you have heard from the microcontroller, proceed:
else {
float recievedData = new Float(myVariable);
float myData = new Float (myString);
println ("mine = "+myData);
println ("judit = "+recievedData);
if (myData > recievedData){
myPort.write("B");
} else {
myPort.write("C");
}
//send data to pachube
if ((millis() - lastUpdate) > 7000){
println("ready to POST: ");
dOut.update(0, myString); // update the datastream
int response = dOut.updatePachube(); // updatePachube() updates by an authenticated PUT HTTP request
println(response); // should be 200 if successful; 401 if unauthorized; 404 if feed doesn't exist
lastUpdate = millis();
}
}
}
myPort.write("A");
}
void onReceiveEEML(DataIn d){
myVariable = d.getValue(2); // get the value of the stream 1
// println(myVariable);
}
Arduino;
float timer, LDRvalue, scaledLDR;
int sensorValue = 0; // reading from the sensor
int servoControl;
#include
Servo myservo;
//int pos = 0;
void setup() {
// configure the serial connection:
Serial.begin(9600);
// configure the digital input:
myservo.attach(9);
establishContact();
}
void loop() {
// read the sensor:
LDRvalue = analogRead(1);
if (LDRvalue > 100){
scaledLDR = LDRvalue/100;
timer = timer + scaledLDR;
delay(1000);
}
if (Serial.available() > 0) {
// read the incoming byte:
int inByte = Serial.read();
Serial.println(timer);
if(inByte == 66){
myservo.write(180);
}
if(inByte == 67){
myservo.write(0);
}
}
}
void establishContact() {
while (Serial.available() <= 0) { Serial.println("hello"); // send a starting message delay(300); } }
.
These sketches only have only has two users in the system but shows how the Processing and Arduino work together.
No comments:
Post a Comment