Solar Fractal Plant: Update 2
Over the last week I have made considerable of progress on my Solar powered fractal tree.
Enclosure
The bamboo plywood from Inventables arrived! Mai Claro, Daniel Ryan, Benjamin Moll, and a number of other ITP students helped to get me up and running for my first time on the laser cutter. I cut initially out of cardboard to test the design and was able to make a few adjustments before the final cut in 1/8 inch Bamboo plywood.
I’m really happy with how the final enclosure came out and feel that the wood grain is a nice complement to the fractal tree. With some more time I may design a hinge or magnet system to connect the solar panel to the back of the enclosure.
L-Systems
After Dan Shiffman shared L-System examples with me during office hours I became fascinated with their subtle variation and determined to integrate this method of rendering a fractal tree.
L-Systems, or Lindenmayer systems, are quite different from the recursive method I used previously and operate using an initial axiom and series of production rules for growth to generate a sentence that the fractal tree is rendered from. While I initially thought I could build an L-System on the work I had already done to port this fractal tree example from the Coding Train to Arduino, I realized quickly that L-Systems would require additional functions and research.
Push() and Pop()
The push() and pop() functions in P5.js are not available by default in the Arduino IDE so I made use of a custom library called StackArray. Using the StackArray library I was able to push and pop points to stacks to facilitate the turtle rendering function.
Memory
Limited memory on Arduino is an issue so I had to limit the sentence length of the String variable to stay under 2048 bytes.
Growth
As much as possible I wanted to mimic the growth of a real plant. The L-System implementation from The Coding Train does a great job at generating still images, but when running the rules to generate an update to the sentence there is a noticeable jump in the growth of the fractal tree at the start of each new generation (above left time-lapse). To generate smoother growth I added an additional production rule for new growth, “N”, that over the course of a generation grows from 0 to the full length of a branch (above right time-lapse).
/* // Based on 2D Tree from Aesthetic Beauty of Plants float angle = 0.33; String axiom = "X"; String sentence = axiom; float len = 70; // starting branch length int generations = 4; // Maximum 4 generations before memory overflow char charRules[] = "XF"; String * stringRules[2]; int ruleCount = 2; String a = "F-[[X]+X]+F[+FX]-X"; // charRules[0] converts to this String b = "FF"; // charRules[1] converts to this */ // Experimental float angle = 0.33; String axiom = "X"; String sentence = axiom; float len = 70; // starting branch length int generations = 4; // Maximum 4 generations before memory overflow char charRules[] = "XNF"; String * stringRules[3]; int ruleCount = 3; String a = "N-[[X]+X]+N[+NX]-X"; // charRules[0] converts to this String b = "FN"; // charRules[1] converts to this String c = "FN"; // charRules[2] converts to this
Another behavior I implemented is for the shape of the fractal tree to respond to light. When enough light is present on the panel to charge the battery the fractal tree responds by gradually extending the angle of its branches (above left time-lapse). When no light is present the fractal tree closes the angle of its branches in an attempt to reach further upward.
Below is my turtle function for reference:
void turtle() { // Set background color display.fillScreen(bgColor); // Rotation Rotation R1, R2; R1.RotateZ(angle + sunlight); // used for a "+" in the sentence R2.RotateZ(-angle - sunlight); // used for a "-" in the sentence // Calculate the branch length Point v1; Point newBranch; // used for a "F" or full length branch newBranch.X() = branchLength; v1 = newBranch; float growthFactor = fmod((growth * generations), 1); // used for an "N" or new branch that multiplies a percentage of the current growth cycle to smooth generational growth for (int i = 0; i < sentence.length(); i++) { char current = sentence.charAt(i); // get the current char from the sentence if (current == 'F') { b2 = b1 + v1; display.drawLine(b1.X(), b1.Y(), b2.X(), b2.Y(), plantColor); b1 += v1; } else if (current == 'N') { b2 = b1 + (v1 * growthFactor); display.drawLine(b1.X(), b1.Y(), b2.X(), b2.Y(), plantColor); b1 += (v1 * growthFactor); } else if (current == '+') { v1 = R1 * v1; // rotate clockwise } else if (current == '-') { v1 = R2 * v1; // rotate counter-clockwise } else if (current == '[') { // push coordinates and push "vector" stackP.push(b1); stackV.push(v1); } else if (current == ']') { // pop push coordinates and pop "vector" b1 = stackP.pop(); v1 = stackV.pop(); } } }