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(); } }