Fractals on Arduino
This week I reproduced a fractal tree on an e-paper display using an Arduino Nano 33 IoT .
Getting things working working in the Arduino IDE involved additional libraries including Geometry.h to allow working with points, rotations, and coordinate transformations.
The Waveshare 5.65″ 7-Color e-paper display took some effort to get working but was helped significantly with the GxEPD2 library by ZinggJM. The display uses an SPI interface, and pinouts vary from one microcontroller to another, so this took some time for me to wrap my head around. Because the Nano 33 IoT is an SAMD board which wasn’t included as a default setting I went ahead and wrote my own pinout:
// 7-color e-paper #define MAX_HEIGHT_7C(EPD) (EPD::HEIGHT <= (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2) ? EPD::HEIGHT : (MAX_DISPLAY_BUFFER_SIZE) / (EPD::WIDTH / 2)) // 2 pixel per byte GxEPD2_7C<GxEPD2_565c, MAX_HEIGHT_7C(GxEPD2_565c)> display(GxEPD2_565c(/*CS=10*/ SS, /*DC=*/ 7, /*RST=*/ 8, /*BUSY=*/ 6)); // Waveshare 5.65" 7-color
Learning about recursion this week was immensely helpful. On my own I had not previously thought to call a function within itself. Here is the core Arduino code I am using to draw the fractal trees in the images above:
// Library to enable geomtry #include <Geometry.h> // Point represents a coordinate in 3D space Point b1, b2; void setup() { Serial.begin(115200); delay(100); display.init(115200); // Branch coordinates b1.X() = 0; b1.Y() = display.height()/2; b2.X() = display.width()/3; b2.Y() = display.height()/2; drawTree(b1, b2, GxEPD_RED, GxEPD_YELLOW); // Draw fractal tree once. b1 = start point, b2 = end point, background color, branch color } void loop() { // Nothing happening here } // Recursive function to to draw tree void drawBranch(Point branchStart, Point branchEnd, uint16_t color2) { display.drawLine(branchStart.X(), branchStart.Y(), branchEnd.X(), branchEnd.Y(), color2); // Create new branches Point d1 = branchEnd - branchStart; Point newBranch = d1 * 0.65; if (newBranch.Magnitude() > 5){ // Rotation Rotation R1, R2; R1.RotateZ(0.25); R2.RotateZ(-0.25); // New branch 1 Point newEnd1 = R1 * newBranch; // rotated clockwise newEnd1 += branchEnd; //display.drawLine(branchEnd.X(), branchEnd.Y(), newEnd1.X(), newEnd1.Y(), color2); drawBranch(branchEnd, newEnd1, color2); // New branch 2 Point newEnd2 = R2 * newBranch; // rotated counter-clockwise newEnd2 += branchEnd; //display.drawLine(branchEnd.X(), branchEnd.Y(), newEnd2.X(), newEnd2.Y(), color2); drawBranch(branchEnd, newEnd2, color2); } } void drawTree(Point p1, Point p2, uint16_t color1, uint16_t color2) { display.setRotation(2); display.firstPage(); do { display.fillScreen(color1); drawBranch(p1, p2, color2); } while (display.nextPage()); display.hibernate(); }
I am planning to develop this further in my final project with a solar enclosure to turn this into a solar powered fractal plant. Using analog readings from solar panel could influence the growth of the plant over time.