design and build a wired &/or wireless network connecting at least two processors
With Francisco's recommendation, I installed Kokopelli this week to test it out. However it didn't went well. I copied the code in Week 13 but they did not work out of the box. Many variables and functions were undefined. I think I might miss some libraries.
Later Francisco told me it was a version issue.
Eventually I used my old friend Fritzing for this assignment. My design is to make an input board with sound sensor and an output board with a motor. When there is a short sound, the motor rotates; where is a long sound, the motor rotates in the opposite direction.
I drew a board for output device and another for input device. Both of them have a Attiny 45 and two pins reserved for I2C or TX/RX for networking. The output board has a 20 Mhz oscillator and a PWM pin for motor. Input device has two pins for two inputs.
You may download layout Fritzing file: week14_i2c_input.fzz, week14_i2c_output.fzz
Programming is my expertise and therefore it does not take me much time. The input board tells the output board which direction to rotate by sending a byte of either 0 or 180. The output board sends the same signal to the motor repeatedly for a second. The real gold here is how to differentiate short and long sounds. To do this, input board will set a boolean value when it receives the first sound, and then it delays 300ms to avoid a short sound to be detected more than once. And then it waits for a second sound for the next 800ms, In my practice, it checks 80 times with a delay of 10ms, which is crucial for timing. If there comes a second sound, it rotates. If not, it rotates reversely.
At first I tried to use TinyWireS, I2C libraries for attiny 45/85, but never succeeded. I spent many hours and eventually called for help on Fab Academy mail list. I got a friendly response from Till Cremer saying that the library was buggy. Also Neil and Bas Withagen provided alternative solutions with SoftwareSerial library. So I went with it.
There were a few different functions and optional arguments you could use in serial networking. I did not make clear how they worked and keep seeing wrongly-encoded text on my laptop. Here are some tips:
Thumb of rules: Always use Serial.write and unless the message is for humans to read. To test for connection, Arduino has a serial monitor that is very handy for debugging.
The following code is for Attiny45 to send signals to two processors when detecting sounds.
#include <SoftwareSerial.h>
//#include <TinyWireM.h>
#define FORWARD (byte)0
#define BACKWARD (byte)180
#define STOP (byte)90
SoftwareSerial mySerial0(1, 0); // RX, TX
SoftwareSerial mySerial2(4, 2); // RX, TX
int sensorPin_A = 3; //Microphone Sensor Pin on analog 3
int sensorValue_A = 0;
bool firstSound = false;
int counter = 0;
void setup() {
//TinyWireM.begin(); // TinyWireM library does not work.
mySerial0.begin(4800);
mySerial2.begin(4800);
mySerial0.write(FORWARD); //say hello
mySerial2.write(FORWARD); //say hello
}
void loop() {
sensorValue_A = (int)analogRead(sensorPin_A); // sensorValue_A ranges from 0 to 1023
if ( sensorValue_A > 30 ){ //The 'silence' sensor value is about 28 or 29
if (firstSound) { // if this is a second sound, move backward.
mySerial0.write(BACKWARD);
mySerial2.write(BACKWARD);
firstSound = false;
counter = 0;
delay(2000);
}
else { // if this is the first sound, wait and see if there is a second one.
firstSound = true;
counter = 0;
delay(300);
}
} else {
if (counter > 80 && firstSound) { // when there is a first sound followed by nothing, move forward
mySerial0.write(FORWARD);
mySerial2.write(FORWARD);
firstSound = false;
counter = 0;
delay(2000);
}
}
delay(10); // avoid repeat
counter++; // counter tells how many loops pass after the first sound.
}
The following code is for Attiny45 to receive signals and to rotate the servos.
#include <SoftwareServo.h>
#include <SoftwareSerial.h>
//#include <TinyWireS.h>
#define FORWARD (byte)0
#define BACKWARD (byte)180
#define STOP (byte)90
SoftwareServo myservo; // create servo object to control a servo
int pos = 0; // variable to store the servo position
byte inByte = STOP;
SoftwareSerial mySerial(0, 2); // RX, TX
void setup() {
// TinyWireS.begin(); // TinyWireS library does not work.
myservo.attach(1); // attaches the servo on pin 1 to the servo object
turn(15); // A 'Hello' to you
mySerial.begin(4800);
}
void loop() {
if (mySerial.available()) {
inByte = mySerial.read();
if (inByte == FORWARD) {
motorMove(15, FORWARD);
}
else if ( inByte == BACKWARD ) {
motorMove(15, BACKWARD);
}
mySerial.write(inByte);
}
}
void motorMove(int moveTime, byte moveDirection) {
//for(pos = moveDirection; pos != 90 ; pos < 90 ? pos ++ : pos -- )
int moveD=0;
for(pos = 0; pos < moveTime ; pos++ )
{
if(pos < 10) {
moveD = moveDirection > 90 ? STOP + pos : STOP - 10;
} else {
moveD = moveDirection;
}
myservo.write(moveDirection);
delay(10);
SoftwareServo::refresh();
}
}
void turn(int delayTime) {
for(pos = 0; pos < 180; pos++) // goes from 0 degrees to 180 degrees
{ // in steps of 1 degree
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(delayTime); // waits 15ms for the servo to reach the position
SoftwareServo::refresh();
}
for(pos = 180; pos>= 0; pos--) // goes from 180 degrees to 0 degrees
{
myservo.write(pos); // tell servo to go to position in variable 'pos'
delay(delayTime); // waits 15ms for the servo to reach the position
SoftwareServo::refresh();
}
}