Week Zero - Final Project tracker

Final Project Process

Keeping track of my thought process on my final project on evolvable robots

First things first. What does evolvable robots even mean? Lets start with the definitions of each word


ev·o·lu·tion

- the gradual development of something, especially from a simple to a more complex form.


ro·bot

- a machine capable of carrying out a complex series of actions automatically, especially one programmable by a computer.


So, to create evolvable robots, I must make robots that are capable of a gradual development from something simple to more complex. Initial ideas of evolvable robots that I have been thinking about have involved many small simple robots that have the ability to to induce changes in behavior in other robots. I image this system as a selection system that if a robot changes another robot, this is suppose to be similar to an organism dying. Thus, robots that change behavior and survive longer are more suited for the current interactions occurring in the current environment.


The previous idea mentioned, seemed too complicated and would requires making too many individual robots. Thus, I decided to no longer pursue this idea. To simplify things, I've decided to focus on a single robot. In this idea, I am interested in having a robot gradually learn how to move more efficiently over time.

To simplify things even more, I want to having the system that the robot moves as simple as possible. I.E., there are a minimal amount of parameters that the robot can change to enhance it's ability to move. Also, I need to have a way for the system to know if it is moving in the correct direction.

To simplify things even more, I want to having the system that the robot moves as simple as possible. I.E., there are a minimal amount of parameters that the robot can change to enhance it's ability to move. Also, I need to have a way for the system to know if it is moving in the correct direction.

For the simple moving system, I am interested in just using a motored wheel that can turn and adjust the direction of movement. To provide cues that the device is going in the correct direction, I will play a tone from a source that that device can detect with a microphone. The tone intensity will provide insight on whether the device is closure or not.

Method of learning

To allow the device to learn, I am interested in using small artificial neural networks to guide navigation.

If I am capable of completing this task, I would be interested in adding more features to the device that the device also needs to learn. For example, how to not go over an edge. I think it would be interesting to see how I can connect another neural network to the initial sound guidance network that allows the system to be optimized on both parameters.

Micro controllers controling strips of Flexinol

So decided to change the project completely. Now, I am going to create something similar to that of LED strips but instead strips that give the user the ability to move things around their house.

Thinking of using Flexinol to cause the strips to bend since flexinol wires are small and easily hideable. Here are some videos of cool uses of flexinol.

I want to have this device be able to communicate with another board across the room. So that two things can move in a coordinated fashion. To do so, I am interested in added bluetooth devices. Thus, in week 12, I made a bluetooth networking from a computer connected blutooth device to a bluetooth to a board. Here when any key is press other than 1, it will lead to a single blink; however, if 1 is press, then it will blink twice. As you can see in the video below.



Also, I am interested in communicating these devices to a phone. So interested in learning how to create an app on the phone for this sort of communication. Will be following this tutorial. The example is demoed at the end of the tutorial.

So I finally recieved the flexinol test wire of varying diameters ranging from 100 - 325 um. Since I didn't know which would be ideal for my precise needs, a sample package seemed ideal. Found here.

For the testing phase, I read through vairous tutorials on muscle wire training, and decided what was probably best for my needs. Out of the box, Flexinol can shrink in size when heated. There are various examples online that show flexinol being used as a lever system. Alternatively, you can tran flexinol to form particular shapes..

Since I wanted to make my plant bend, I decided to train the wire by wrapping it around a screw. The idea here, is that when I straighten it, it will want to curl back into itself causing a bending motion

Based of survarying the various methods of training, I decided to traing my wire at 500*C for 5 min in a oven.


Following heating for 5 min. I rapidly cooled in room temp water. Use heat gloves and tongs since everything is very very hot!!


Next, I straightened the wire and placed it in thin tape so that it will maintain being straight. I made sure to uncurl the wire from the screw keeping the internal side of the wire to be in the same direction on the tape. If you dont do this, the wire will bend in different directions losing out on the force to bend in one direction.

Then, I used a DC motor controller I made in a previous week to control the flexinol.



As the video indicates, it works pretty well!

I also wanted to make sure it was enough force to bend the leaves of a plant. So I used double sidded tape to attach it to a leaf.



This also seemed to work pretty well with my higher guage wires. Only wires from 150 - 250 um were able to create enough force to bend the leaves. Even higher guage wire, such as 325um, was able to bend the leaf, but for some reason the H-bridge would not supply current through the wire. I could power these cables directly from a DC power supply, but the mosfet H-Bridge A4950 and A4953 both decided to not function to power larger flexinol wires.

I tried troubleshooting this issue a lot and came to the conclusion that these mosfets will only provide a certain amount of power. If the mosfet detects a system when low resistance and high current, as found with higher flexinol wire thickness, it cuts off before supplying current. Maybe some sort of a safety system. Thus, if interested in more movement my using thicker muscle wires, I would recommend using other mosfets that can supply very high voltages and currents.

I decided to use the 150 and 250 sample wires that I have for the movement of the plant. I ordered more of these wires, but looks like I wont get these on time to implement into the final project.

Since I was interested in controlling two sets of muscle wires independently. I decided to make a board with two H-bridges. I also made two of these boards since I wanted to have two systems move in a coordinated fasion.

Here is a video of controlled two wires independently from the same board.



I had ab out 5 of these wries fromt the test kit that was able to move the plant. Originally, I wanted to attach all of them, but when connecting all the muscle wires togther in parallel, it led to the same issue with the thicker diameter wires - the H-bridge wouldnt want to power it. Thus, I had to remove 2 of the 5 and kept only 3. Then I attached this to the plant. The two that I cut off was the thicker flexinol wires that created the more dramatic movement. I figured those would have to go since they were more so responsible for passing too much current.

When flexing the leaves of the plant, it was clear that the movements were so slow that it was difficult to even see if the plant was moving. I decided to do rapid pulsing of the wires at 200ms on off rates to make the plan pulse rather than slowly curly. As seen in the video, you can see the movement. Also, since this movement is also pretty minimal, I decided to also incorporate a DC motor to shuffle the branches of the leaves.



In this video, I'm controlling the board with the a bluetooth device that I made from the networking week. When the board recieves a 1, it causes the DC motor to move, and a 2 causes the muscle wires to contract.

Originally, I wanted two plants to be in sync with one another; however, since I didnt have enough musle wire, I decided to scrap that idea. Instead, I adapted the movement of the plant to be a naturalistic notification system. For non-urgent matters, the plant will pulse twitch with the muslce wirese, but when things are more urgent, the DC motor will activate to more vigorously shuffle the plant.

Working with the parts that exist in the section, I decided to use a motion detection system for the front door. That is, if there is someone at the door, the system will intially pulse the plant, but if they are there for a long period of time (such as longer than 1 min), it will turn on the DC-motor. Thus I made the below board.

I was able to program the board to output either a 1 or a 2 depending on how long something was moving infront of the board. I was able to read this with the FTDI cord, but when I tried connecting to a bluetooth device, it couldn't communicate correctly and would output gibersih. Since I worked on this all, night and was running out of time. I decided to omit this from the final project. Instead, the plant will have to be controlled by a bluetooth device that is connected to the FTDI port of my computer similar to the video above.

Here is the code for the motor and the flexinol stimulator board. This board is connected to a HM-11 bluetooth device.

// // // H-bridge.BLE.44.c // // H-bridge DC motor trigger by BLE input // contains a 20MHz crystal to communicate for better timing // need to set fuses to 0x5E:m // // Based on Neil Gershenfeld code hello.H-bridge.44.DC.c // adapted on 12/15/18 // // (c) Massachusetts Institute of Technology 2012 // This work may be reproduced, modified, distributed, // performed, and displayed for any purpose. Copyright is // retained and must be preserved. The work is provided // as is; no warranty is provided, and users accept all // liability. // #include <avr/io.h> #include <util/delay.h> #include <avr/pgmspace.h> #include <string.h> #define input(directions,pin) (directions &= (~pin)) // set port direction for input #define output(directions,pin) (directions |= pin) // set port direction for output #define set(port,pin) (port |= pin) // set port pin #define clear(port,pin) (port &= (~pin)) // clear port pin #define pin_test(pins,pin) (pins & pin) // test for port pin #define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set #define bit_delay_time 102 // bit delay for 9600 with overhead (changed from 500) #define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay #define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay #define PWM_count 20000 // number of PWM cycles #define cycle_count 5 // number of speed cycles #define bridge_portA PORTA // H-bridge port #define bridge_directionA DDRA // H-bridge direction #define bridge_portB PORTB // H-bridge port #define bridge_directionB DDRB // H-bridge direction #define IN1x (1 << PA4) // IN1x #define IN2x (1 << PA5) // IN2x #define IN1y (1 << PA7) // IN1y #define IN2y (1 << PB2) // IN2y #define led_delay() _delay_ms(100) // LED flash delay #define led_port PORTA #define led_direction DDRA #define led_pin (1 << PA3) //LED pin #define serial_port PORTA #define serial_direction DDRA #define serial_pins PINA #define serial_pin_in (1 << PA1) //Rx is PA0 #define serial_pin_out (1 << PA0) //Tx is PA1 #define motor_ID '1' #define plant_ID '2' #define plant_shake_amount 4 // amount of on off for plant #define plant_delay() _delay_ms(200) // LED flash delay void get_char(volatile unsigned char *pins, unsigned char pin, char *rxbyte) { // // read character into rxbyte on pins pin // assumes line driver (inverts bits) // *rxbyte = 0; while (pin_test(*pins,pin)) // // wait for start bit // ; // // delay to middle of first data bit // half_bit_delay(); bit_delay(); // // unrolled loop to read data bits // if pin_test(*pins,pin) *rxbyte |= (1 << 0); else *rxbyte |= (0 << 0); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 1); else *rxbyte |= (0 << 1); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 2); else *rxbyte |= (0 << 2); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 3); else *rxbyte |= (0 << 3); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 4); else *rxbyte |= (0 << 4); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 5); else *rxbyte |= (0 << 5); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 6); else *rxbyte |= (0 << 6); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 7); else *rxbyte |= (0 << 7); // // wait for stop bit // bit_delay(); half_bit_delay(); } void put_char(volatile unsigned char *port, unsigned char pin, char txchar) { // // send character in txchar on port pin // assumes line driver (inverts bits) // // start bit // clear(*port,pin); bit_delay(); // // unrolled loop to write data bits // if bit_test(txchar,0) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,1) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,2) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,3) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,4) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,5) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,6) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,7) set(*port,pin); else clear(*port,pin); bit_delay(); // // stop bit // set(*port,pin); bit_delay(); // // char delay // bit_delay(); } void put_string(volatile unsigned char *port, unsigned char pin, PGM_P str) { // // send character in txchar on port pin // assumes line driver (inverts bits) // static char chr; static int index; index = 0; do { chr = pgm_read_byte(&(str[index])); put_char(&serial_port, serial_pin_out, chr); ++index; } while (chr != 0); } void flash() { // // LED flash delay // clear(led_port, led_pin); led_delay(); set(led_port, led_pin); } int main(void) { // // main // static char chr; // // set clock divider to /1 // CLKPR = (1 << CLKPCE); CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0); // // Initialize outputs // set(serial_port, serial_pin_out); input(serial_direction, serial_pin_out); set(led_port, led_pin); output(led_direction, led_pin); // // initialize H-bridge pins // clear(bridge_portA, IN1x); output(bridge_directionA, IN1x); clear(bridge_portA, IN2x); output(bridge_directionA, IN2x); clear(bridge_portA, IN1y); output(bridge_directionA, IN1y); clear(bridge_portB, IN2y); output(bridge_directionB, IN2y); while (1) { get_char(&serial_pins, serial_pin_in, &chr); flash(); if (chr == motor_ID) { // turn on set 1 set(bridge_portA, IN1y); clear(bridge_portB, IN2y); ON_delay(); // turn off set 1 clear(bridge_portA, IN1y); clear(bridge_portB, IN2y); flash(); } if (chr == plant_ID) { int shake; for(shake=plant_shake_amount;shake>0;shake=shake-1) { //turn on set 2 clear(bridge_portA, IN1x); set(bridge_portA, IN2x); plant_delay(); // turn off set 2 clear(bridge_portA, IN1x); clear(bridge_portA, IN2x); flash(); plant_delay(); } } } }

Here is the code for the motion tracker device. This was meant to communicate with a HM-11 bluetooth device, but the output timing is incorrect, so unclear on the issue here

// // // motionBLE.c // // Based off Neil's HC-SR501 motion detector hello-world // 9600 baud Bluetooth H-11 // // Daniel Estandian 12/15/18 // Massachusetts Institute of Technology // // This work may be reproduced, modified, distributed, // performed, and displayed for any purpose. Copyright is // retained and must be preserved. The work is provided // as is; no warranty is provided, and users accept all // liability. // #include <avr/io.h> #include <util/delay.h> #include <avr/pgmspace.h> #include <string.h> #define input(directions,pin) (directions &= (~pin)) // set port direction for input #define output(directions,pin) (directions |= pin) // set port direction for output #define set(port,pin) (port |= pin) // set port pin #define clear(port,pin) (port &= (~pin)) // clear port pin #define pin_test(pins,pin) (pins & pin) // test for port pin #define bit_test(byte,bit) (byte & (1 << bit)) // test for bit set #define bit_delay_time 102 // bit delay for 9600 with overhead #define bit_delay() _delay_us(bit_delay_time) // RS232 bit delay #define half_bit_delay() _delay_us(bit_delay_time/2) // RS232 half bit delay #define char_delay() _delay_ms(10) // char delay #define led_delay() _delay_ms(100) // LED flash delay #define wait_delay() _delay_ms(1000) // LED flash delay #define motor_id 1 // temporary definition #define serial_port PORTA #define serial_direction DDRA #define serial_pins PINA #define serial_pin_in (1 << PA1) //Rx is PA0 #define serial_pin_out (1 << PA0) //Tx is PA1 #define led_port PORTA #define led_direction DDRA #define led_pin (1 << PA3) //LED pin #define out_pins PINA #define out_pin (1 << PA6) #define max_motion 30 //60 seconds of essentially continuous motion #define node_id '1' void get_char(volatile unsigned char *pins, unsigned char pin, char *rxbyte) { // // read character into rxbyte on pins pin // assumes line driver (inverts bits) // *rxbyte = 0; while (pin_test(*pins,pin)) // // wait for start bit // ; // // delay to middle of first data bit // half_bit_delay(); bit_delay(); // // unrolled loop to read data bits // if pin_test(*pins,pin) *rxbyte |= (1 << 0); else *rxbyte |= (0 << 0); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 1); else *rxbyte |= (0 << 1); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 2); else *rxbyte |= (0 << 2); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 3); else *rxbyte |= (0 << 3); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 4); else *rxbyte |= (0 << 4); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 5); else *rxbyte |= (0 << 5); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 6); else *rxbyte |= (0 << 6); bit_delay(); if pin_test(*pins,pin) *rxbyte |= (1 << 7); else *rxbyte |= (0 << 7); // // wait for stop bit // bit_delay(); half_bit_delay(); } void put_char(volatile unsigned char *port, unsigned char pin, char txchar) { // // send character in txchar on port pin // assumes line driver (inverts bits) // // start bit // clear(*port,pin); bit_delay(); // // unrolled loop to write data bits // if bit_test(txchar,0) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,1) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,2) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,3) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,4) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,5) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,6) set(*port,pin); else clear(*port,pin); bit_delay(); if bit_test(txchar,7) set(*port,pin); else clear(*port,pin); bit_delay(); // // stop bit // set(*port,pin); bit_delay(); // // char delay // bit_delay(); } void put_string(volatile unsigned char *port, unsigned char pin, PGM_P str) { // // send character in txchar on port pin // assumes line driver (inverts bits) // static char chr; static int index; index = 0; do { chr = pgm_read_byte(&(str[index])); put_char(&serial_port, serial_pin_out, chr); ++index; } while (chr != 0); } void flash() { // // LED flash delay // clear(led_port, led_pin); led_delay(); set(led_port, led_pin); } int main(void) { // // main // static char chr; // set clock divider to /1 // CLKPR = (1 << CLKPCE); CLKPR = (0 << CLKPS3) | (0 << CLKPS2) | (0 << CLKPS1) | (0 << CLKPS0); // // initialize serial pin // set(serial_port, serial_pin_out); input(serial_direction, serial_pin_out); set(led_port, led_pin); output(led_direction, led_pin); int motion_count=0; // // main loop // while (1) { // // wait for output high // flash(); if ((out_pins & out_pin) == 0 && motion_count<max_motion){ motion_count=motion_count+1; output(serial_direction, serial_pin_out); put_char(&serial_port,serial_pin_out,'1'); // send out a one to make plants kinda move 1 } if((out_pins & out_pin) == 0 && motion_count>=max_motion) { output(serial_direction, serial_pin_out); //put_char(&serial_port,serial_pin_out,'2'); // send out a two to make plants really move 2 } // // wait for output low and subtract // if ((out_pins & out_pin) != 0) { if(motion_count>=1){ motion_count=motion_count-1; //only subtract if its postive } if(motion_count>=1 && motion_count<max_motion) { output(serial_direction, serial_pin_out); put_char(&serial_port,serial_pin_out,'1'); // send out a one to make plants kinda move 1 } if(motion_count>=max_motion) { output(serial_direction, serial_pin_out); put_char(&serial_port,serial_pin_out,'2'); // send out a two to make plants really move 2 } } wait_delay(); // waits a second for next count if(motion_count>=max_motion+30) { motion_count=max_motion+30; } } }