Skip to content

Week 12 - Machine Week

Please refer to the group page to read about the machine we built.

Mechnical Design

Group Assignment:

  • Design a machine that includes mechanism + actuation + automation + application
  • Build the mechanical parts and operate it manually
  • Document the group projec

Individual Assignment:

  • Document your individual contribution

Machine design

Group Assignment:

  • Actuate and automate your machine
  • Document the group project

Individual assignment:

  • Document your individual contribution

Day 1 (Monday)

Because some preparation had already been done in advance of the machine week, we already had divided tasks between us. Today I could start right away with the following tasks:

  • finalize vertical drive 3D design
  • draft schematic for PCB
  • select electrical and mechanical components and develop circuits outside the PCB
  • make or add 3D drawings of components to Fusion

Note

One thing I had prepared prior to the machine week, was to create a shared workspace in Fusion, where we could all work together on different subassemblies and create a final assembly.

Today I finished the 3D design of the vertical drive of the plate in Fusion, with three main components saved to be 3D printed.

  • upper flange (holding the drive assembly in place, with seat for hall effect sensor and mounting for the motor)
  • lower flange (lower bearing seat for shaft)
  • drive shaft (with integrated gear, bearing seats and coupling)

We also went through the shelves of the FabLab to find suitable components for our machine and placed them in box. We selected the power supply an communication peripherals and decided to go for an external, used 12VDC 2A power supply that plugs into our enclosure and a USB-C port for easy programming (once the bootloader is burned).

Components

Day 2 (Tuesday)

Main tasks:

  • finish drawings of all purchased components in Fusion
  • 3D print dial knobs
  • finish KiCAD schematic
  • make PCB routing and production files
  • partially solder the components to the PCB

Today we finished the schematic drawing in KiCAD for the PCB that includes all the peripherals and components for our machine.

Here is a screenshot of the drawing:

Schematic

Then I made the routing of the PCB traces and finished the board.

First we ran into trouble because Ólöf and I were trying to cooperate on a shared KiCAD drawing in Git. Because we weren't using the same version of KiCAD and not exactly the same library version, we had some issues to get it working.

The next issue was, that when updating the PCB from schematic only some few ratnest, but no footprints appeared. The issue was, that almost all objects were hidden for some unknown reason. See the screenshot below:

Object visibbility

After having fixed that issue, the tracing was pretty straight forward, but I had to use some bridges and rearrange some pins for convenience.

Here is the result in KiCAD:

PCB drawing

And here are the production files:

Here you can see what the board looked like after milling:

Board milled

Here is one printed knob in front of the Fusion drawing on the screen. I printed four knobs in total (one spare).

Knob

I also soldered the microcontroller and later some other components to the PCB, so that task was finished in cooperation with Ólöf.

PCB with SAMD21

Because the pinout was now fixed, I could start setting up the program and worked on that in the evening.

Day 3 (Wednesday)

Today I printed the components for the vertical axis drive and now this subassembly is finished.

The fit for the bearings was very good and everything fit, except for the bearing seat in the upper flange. I made a mistake in the design and the seat was too shallow.

I could have printed a new upper flange, which takes about 4,5 h, but instead I decided to try and fix the seat in the lathe. Because it is a very small lathe, the chuck couldn't hold the hexagon on the outside. I had to make a small adaptor plate and hold the flange by mounting it with screws to the adptor plate. That was easy and took about 30 min.

Lathe

Lathe

After lunch it was time to assemble the drive.

Here I glued the Hall effect breakout board in place:

Drive assembly

And here is what the other side looks like (with a HX-711 motor driver):

Drive assembly

Gear printing

Spur gears with M 0,6 seem to be close to the lower limit of what a regular FDM printer with 0,4 mm nozzle can achieve.

Because Ólöf had already set up the bootloader on the SAMD21, I wanted to continue by testing the inputs and outputs of our PCB and get started with the program.

After uploading the first program via the USB I couldn't get any response in the serial monitor. Also the I2C didn't seem to work, because I tried displaying messages, but they didn't appear.

Failure

Unfortunately, the only logic analyzer that we have in our Lab was not available during the whole machine week, because one of our instructors took it with him to a business trip.

The later half of the day went into troubleshooting the USB connection and serial communication.

At one point we could program the board via SWD and receive an output on the serial monitor, but after that everything seemed to get worse. Our supervisor tried to assist, but in the end we had to give up - quite frustrated.

The status by the end of the day is a board that:

  • isn't recognized as USB-device
  • doesn't send any thing via USB
  • seems to be still programmable via SWD

Question

During the troubleshooting we found two potential issues, that we could fix by adding jumper wires and a capacitor for noise reduction close to the SAMD21 voltage supply. Will it help?

Day 4 (Thursday)

This day started with continuing issues with USB and serial communication. When I had tried sending the program to a development board and even the development board stopped responding, I started suspecting the code to be the issue.

That turned out to be right. I excluded the libaries from the code and now things started working. I started going through the peripherals testing them step by step:

  • the potentiometers
  • the end-switch and set-switch
  • the motor drivers

The LCD display didn't work so I started looking at the SERCOM functions of the SAMD21 and how to define the right pins for I2C.

If found a page that explains it, but I struggled to understand the instructions.

In the board manager core folder are files, that define the SERCOM mapping.

Variant files

However, even with trying all the possibilities and adjusting different setting we weren't able to get the I2C to work.

By the end of the day we started considering and discussing possibilites of using different microcontrollers and had several options, but eventually could narrow it down to one (possibly) feasable option that would be the AVR128DB32.

Our instructor Svavar started designing a breakout board for this microcontroller while I looked at the cutting files of the enclosure and made some fixes.

Day 5 (Friday)

Today I started by cutting most of the elements of the enclosure from 4 mm MDF sheets again, after Ólöf and I had fixed some mistakes.

Then it was time for finally assembling the front panel and back panel and adding some rubber feet to the bottom.

Base parts

Base parts

Because I accidentally damaged the I2C pins of our board and we were still hoping to get it running with the help from Mattermost and our instructors, I made a new board, with some improvements as two 4,9k pulldown resistors to SDA and SCL (as by recommendation of our instructor).

Then we did some more testing and debugging but without any major success. We tried defining the pins Wire.begin(8,9) and tried the Softwire.h library as well.

Below is an image of the different boards we tried (after desoldering some components we reused).

PCB prototypes

As nothing seemed to work, our instructor had made an AVR128DB32 development board in the meantime and we tried that with the LCD screen and it worked!

That gave us the final push to redesign the whole PCB and use the AVR128DB32 instead of the SAMD21E18A.

I did the redesign and production of the new board. It took two attempts to mill it, because there was a dull bit in the machine during the first attempt.

Here is a screenshot of the new PCB:

PCB with AVR128DB32

And the design files:

Traces Drill Outlines

After soldering and programming the new PCB it was a great relief, when we finally got the screen and some other peripherals working.

We used the DXCore for determining the pinout.

The rest of the day went into developing the different loops of the program and testing and debugging the inputs and outputs.

Day 6 (Saturday)

Today I spent most of the time programming and testing the new PCB and trying to get familiar with the settings and properties of the AVR128DB32 microcontroller in combination with the DXCore.

I wrote a homing procedure for the azimuth axis and tested and debugged it.

Additionally I made some improvements to the display and interface and tested all switches and the adjustment knobs.

Until this point I had been running the machine on USB power and hadn't connected the LED light either.

Bug

When connecting to 12V DC I realized that the machine wasn't working properly on it. The motor was quite weak and had issues turning the model and the display was very faint.

I found out, that the voltage regulator I used in the schematic was from the list of the Fab Inventory (NCV1117ST50T3G) and the one I used was marked "5V 1A voltage regulator" and had the same footprint, but was a different type and had not the same pinout!

After having fixed the board with some jumper wires and soldered new voltage regulators to it, the problem still existed.

I continued looking at the PWM control for the light and postponed the voltage regulator issue until next day.

However, the light also had an issue. It was constantly on, but the brightness changed a little bit when adjusting the PWM output.

I did some research on the Mosfet and found out (after a long while), that high-side switching with a P-Mosfet isn't a good idea, when the logic voltage and the source voltage differ. This was however, what I had drawn in the schematic.

P-Ch Mosfet

The solution to this is to change the circuit to a low-side switching N-Mosfet.

N-Ch Mosfet

After having drawn the changes in KiCAD I tweaked the traces and was able to rerout the 5V and GND and accomodate the N-Mosfet in a suitable loaction.

Now the light could be adjusted using the analogWrite(pin,pwm); command.

I also added a small pin to the landscape model to point out where our Lab is located exactly.

Our Lab pin

Learnings

  • Switching between power supplies on one PCB is more complicated than expected.
  • When switching devices on a different voltage level using Mosfet - it is best to use a low-side switching P-Mosfet.

Day 7 (Sunday)

Today I continued working on the issue with the voltage regulator.

I measured the voltage between the +5V and GND traces on the board and I only measured 4,1 V. When my instructor came by and we took a look together, we identified the voltage drop being caused by the diode I placed. I didn't realize that diodes have such a huge loss when forwarding power.

Next I tried a Schottky diode, but still the voltage drop was too high (0,5 V).

Now I learned, that there are special IC circuits, that work like an ideal diode and should be used for applications like this, but unfortunately this wasn't available in our Lab.

A suggestion from my instructor was to put a small SMD slide switch on the board, but then we realized, that the one from the inventory can only handle 100 mA - way less then required.

I ended up using a 2-pin socket header and a jumper wire in between.

Then I tried again and now it was working great - the voltage was stable at 5V and the display not faint at all.

After having tried the motors for a while, I noticed the screen starting to become faint again. The cause this time, was propably the voltage regulator (being fed by 12V) creating a lot of heat, that couldn't be dissipated by the small copper trace and it starting reducing the output power by itself as a protection mechanism.

Because I couldn't find a suitable heat sink and I had realized by now, that I could run the motors of a powerful USB power supply I changed my mind and removed the voltage regulator from the board and made a power cable with a barrel jack and USB-conector. That seems to work fine.

Then I organized the cables and placed the PCB with the motor drives inside the box and connected the power and other cables. The red tape indicates the orientation of the connectors.

Tidying up

Cables

Inside box view

Here is a video of the homing procedure after turning on the machine and selecting a date and time and having it move to the right azimuth.

Learnings

  • Diodes have a considerable forward voltage drop (and therefor power loss)
  • Schottky diodes have the lowest forward voltage drop
  • ICs are available that act like "ideal" diodes with no forward voltage drop
  • Voltage regulators create quite some heat and require a proper heat sink

Day 8 (Monday)

Today I painted the "ocean" on the 3D printed model. As all the fjords are quite detailed and I had to use a very fine paint brush, it took about two hours to get a satisfactory result.

Note

I used water based acrylic paint and painted directly on the PLA.

The picture shows how our atificial sun is casting shadows on the newly painted landscape model.

Landscape painted

I also worked on the program and made some improvements to the code and fixed some small bugs. Among other changes I now turn off the azimuth drive motor, when the position is reached to save energy and stop the coils from generating heat. I wonder if this will be possible for the elevation drive as well? Most likely not.

Day 9 (Tuesday)

This afternoon me and Högni met and we decided that he would need some support to finish the sun axis assembly. I made changes to the 3D design of the bracket to accomodate the support wheels in the right locations and make sure, that they can rotate freely. I improved overall strength and rigidity of the bracket and added a mount for the end switch. Then I printed all parts from black PETG.

Day 10 (Wednesday)

This morning I assembled the newly printed parts and did all the manual machining involved, as cutting bolts into exact length, countersink holes and so on. When I was happy with the arm and the bracket I added thread locker to the bolts on the arm, fastened and connected the end switch and made a trigger for it. Then I connected the motor and attached the bracket to the bottom of the enclosure.

Here are some pictures of the progress:

Arm

Bracket

Bracket

Bracket

After lunch I wrote the last procedures for the code and tested it on the machine. Now everything works smoothly.

Here is the program for the machine in it's full length:

/*  FABACADEMY 2025 - Machine Week (12)
 *  FabLab Ísafjörður
 *  
 *  DAYS OF DARKNESS
 *  
 *  A realistic landscape / solar model of Skutulsfjörður
 *  
 *  by Jóhannes Andrésson, Bjartur Leó Hlynsson, Ólöf Hannesdóttir, Högni Friðriksson
*/

#include <SolarCalculator.h>
#include <TimeLib.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 20, 4);

// Define Analog Inputs for poteniometer and hall effect sensor
const int ai_knob1 = 14;
const int ai_knob2 = 15;
const int ai_knob3 = 16;

const int ai_hall  = 18;

// Define Analog Output for PWM of light
const int ao_pwm   = 13;

// Define stepper motor constants and variables
const int steps = 48;                        // internal steps in motor
const float azratio = 97/10;                 // spur gear ratio
const float elratio = 834/10;                // spur gear ratio
const float azstepdeg = 360/(steps*azratio); // deg per step
const float elstepdeg = 360/(steps*elratio); // deg per step
int azstep = 1;                              // azimuth step counter
int elstep = 1;                              // elevation step counter
float azpos;                                 // az absolute position in deg
float elpos;                                 // el absolute position in deg

const int do_M1P1 = 11;
const int do_M1P2 = 10;
const int do_M1P3 = 9;
const int do_M1P4 = 8;

const int do_M2P1 = 7;
const int do_M2P2 = 6;
const int do_M2P3 = 5;
const int do_M2P4 = 4;

// Define Digital Inputs (switches)
const int di_set = 24;
const int di_end = 25;

// Define Variables for solar path
double lat = 66.07243;
double lon = -23.118711;
int time_zone = 0; //UTC offset

// Define Date and Time
int yr = 2025;
int dy = 25;
int mo = 3;
int hr = 15;
int mm = 0;

// Solar position
double az; //azimuth in degrees
double el; //elevation in degrees

// Define Status Variables
bool home_az = false;    // True when homing is complete
bool home_el = false;    // True when homing is complete
bool run_stat = false;   // True when model is running 
int spd = 10;            // Speed for constant operation in percentage


// Define Variables for display refresh
int lcddy;
int lcdmo;
int lcdyr;
int lcdaz;
int lcdel;

// run zenith stepper motor either forward or backward
int runel(unsigned long duration, bool dir){
  static unsigned long chrono = millis();
  if (millis() - chrono < duration) return;
  // check if desired elevation is reached with accuracy of 1 deg
  if (abs(elpos - el)< 1) return;
  chrono = millis();
  // make step
  switch (elstep){
  case 1:  
    digitalWrite(do_M1P1, HIGH);
    digitalWrite(do_M1P2, HIGH);
    digitalWrite(do_M1P3, LOW);
    digitalWrite(do_M1P4, LOW);
    break;
  case 2:
    digitalWrite(do_M1P1, LOW);
    digitalWrite(do_M1P2, HIGH);
    digitalWrite(do_M1P3, HIGH);
    digitalWrite(do_M1P4, LOW);
    break;
  case 3:
    digitalWrite(do_M1P1, LOW);
    digitalWrite(do_M1P2, LOW);
    digitalWrite(do_M1P3, HIGH);
    digitalWrite(do_M1P4, HIGH);
    break;
  case 4:
    digitalWrite(do_M1P1, HIGH);
    digitalWrite(do_M1P2, LOW);
    digitalWrite(do_M1P3, LOW);
    digitalWrite(do_M1P4, HIGH);
    break;
  }
  //forward or reverse operation
  if(dir == true){
    elpos = elpos+elstepdeg;
    if(elpos > 360)elpos=elpos-360;
    if(elstep < 4){
      elstep++;
    }else{
    elstep = 1;
    }
  }else{  //run motor cw
    elpos = elpos-elstepdeg;
    if(elpos < 0)elpos=elpos+360;
    if(elstep < 2){
      elstep=4;
    }else{
    elstep--;
    }    
  }   
}

// homing function for elevation stepper motor
int homeel(bool dir){
  // make step
  switch (elstep){
  case 1:  
    digitalWrite(do_M1P1, HIGH);
    digitalWrite(do_M1P2, HIGH);
    digitalWrite(do_M1P3, LOW);
    digitalWrite(do_M1P4, LOW);
    break;
  case 2:
    digitalWrite(do_M1P1, LOW);
    digitalWrite(do_M1P2, HIGH);
    digitalWrite(do_M1P3, HIGH);
    digitalWrite(do_M1P4, LOW);
    break;
  case 3:
    digitalWrite(do_M1P1, LOW);
    digitalWrite(do_M1P2, LOW);
    digitalWrite(do_M1P3, HIGH);
    digitalWrite(do_M1P4, HIGH);
    break;
  case 4:
    digitalWrite(do_M1P1, HIGH);
    digitalWrite(do_M1P2, LOW);
    digitalWrite(do_M1P3, LOW);
    digitalWrite(do_M1P4, HIGH);
    break;
  }
  //forward or reverse operation
  if(dir == true){
    if(elstep < 4){
      elstep++;
    }else{
    elstep = 1;
    }
  }else{  //run motor cw
    if(elstep < 2){
      elstep=4;
    }else{
    elstep--;
    }    
  }   
}

// run azimuth stepper motor either forward or backward
int runaz(unsigned long duration, bool dir){
  static unsigned long chrono = millis();
  if (millis() - chrono < duration) return;
  // check if desired azimuth is reached with accuracy of 1 deg
  if (abs(azpos - az)< 1) return;
  chrono = millis();
  // make step
  switch (azstep){
  case 1:  
    digitalWrite(do_M2P1, HIGH);
    digitalWrite(do_M2P2, HIGH);
    digitalWrite(do_M2P3, LOW);
    digitalWrite(do_M2P4, LOW);
    break;
  case 2:
    digitalWrite(do_M2P1, LOW);
    digitalWrite(do_M2P2, HIGH);
    digitalWrite(do_M2P3, HIGH);
    digitalWrite(do_M2P4, LOW);
    break;
  case 3:
    digitalWrite(do_M2P1, LOW);
    digitalWrite(do_M2P2, LOW);
    digitalWrite(do_M2P3, HIGH);
    digitalWrite(do_M2P4, HIGH);
    break;
  case 4:
    digitalWrite(do_M2P1, HIGH);
    digitalWrite(do_M2P2, LOW);
    digitalWrite(do_M2P3, LOW);
    digitalWrite(do_M2P4, HIGH);
    break;
  }
  //forward or reverse operation
  if(dir == true){
    azpos = azpos+azstepdeg;
    if(azpos > 360)azpos=azpos-360;
    if(azstep < 4){
      azstep++;
    }else{
    azstep = 1;
    }
  }else{  //run motor cw
    azpos = azpos-azstepdeg;
    if(azpos < 0)azpos=azpos+360;
    if(azstep < 2){
      azstep=4;
    }else{
    azstep--;
    }    
  }   
}

// homing function for azimuth stepper motor
int homeaz(bool dir){
  // make step
  switch (azstep){
  case 1:  
    digitalWrite(do_M2P1, HIGH);
    digitalWrite(do_M2P2, HIGH);
    digitalWrite(do_M2P3, LOW);
    digitalWrite(do_M2P4, LOW);
    break;
  case 2:
    digitalWrite(do_M2P1, LOW);
    digitalWrite(do_M2P2, HIGH);
    digitalWrite(do_M2P3, HIGH);
    digitalWrite(do_M2P4, LOW);
    break;
  case 3:
    digitalWrite(do_M2P1, LOW);
    digitalWrite(do_M2P2, LOW);
    digitalWrite(do_M2P3, HIGH);
    digitalWrite(do_M2P4, HIGH);
    break;
  case 4:
    digitalWrite(do_M2P1, HIGH);
    digitalWrite(do_M2P2, LOW);
    digitalWrite(do_M2P3, LOW);
    digitalWrite(do_M2P4, HIGH);
    break;
  }
  //forward or reverse operation
  if(dir == true){
    if(azstep < 4){
      azstep++;
    }else{
    azstep = 1;
    }
  }else{  //run motor cw
    if(azstep < 2){
      azstep=4;
    }else{
    azstep--;
    }    
  }   
}

void readai_stop (unsigned long duration) {
  static unsigned long chrono = millis();
  if (millis() - chrono < duration) return;
  chrono = millis();

  dy = int(float(analogRead(ai_knob1)) / 1023 * 30 + 0.5)+1;
  mo = int(float(analogRead(ai_knob2)) / 1023 * 11 + 0.5)+1;
  hr = int(float(analogRead(ai_knob3)) / 1023 * 23);
  mm = int((float(analogRead(ai_knob3)) / 1023 * 23 - hr) * 60 +0.5);
}


void setbutton(unsigned long duration) {
  static unsigned long chrono = millis();
  if (millis() - chrono < duration) return;
  chrono = millis();

  if(digitalRead(di_set) == LOW){
    run_stat = !run_stat;
  }
}

void updateoled (unsigned long duration){
  static unsigned long chrono = millis();
  if (millis() - chrono < duration) return;
  chrono = millis();
  // check if values have changed - if not, return
  if (lcddy == dy && lcdmo == mo && lcdyr == yr && lcdaz == int(az+0.5) && lcdel == int(el+0.5)) return;
  // update line 1
  lcd.clear();
  lcd.setCursor(0,0);
  if(dy<10)lcd.print("0");  
  lcd.print(dy);
  lcd.print(".");
  if(mo<10)lcd.print("0");  
  lcd.print(mo);
  lcd.print(".2025 ");
  if(hr<10)lcd.print("0");
  lcd.print(hr);
  lcd.print(":");
  if(mm<10)lcd.print("0");
  lcd.print(mm);
  //update line 2
  if(int(az+0.5)>=100)lcd.setCursor(0,1);
  if(int(az+0.5)< 100)lcd.setCursor(1,1);
  if(int(az+0.5)<  10)lcd.setCursor(2,1);
  lcd.print(int(az+0.5));
  lcd.print(char(223));
  if(int(el+0.5)>=10)lcd.setCursor(7,1);
  if(int(el+0.5)< 10)lcd.setCursor(8,1);  
  if(int(el+0.5)<  0)lcd.setCursor(7,1);
  if(int(el+0.5)< -9)lcd.setCursor(6,1);    
  lcd.print(int(el+0.5));
  lcd.print(char(223));

  lcddy = dy;
  lcdmo = mo;
  lcdyr = yr;
  lcdaz = az;
  lcdel = el;
}

void solarcalc (unsigned long duration){
  static unsigned long chrono = millis();
  if (millis() - chrono < duration) return;
  chrono = millis();

  //set new time according to poteniometer input
  setTime(hr,0,0,dy,mo,yr);
  time_t utc = now();  

  // Calculate solar position
  calcHorizontalCoordinates(utc, lat, lon, az, el);
}

// Adjust brightnes of the sun by elevation starting from -14°
void sunpwm (unsigned long duration){
  static unsigned long chrono = millis();
  if (millis() - chrono < duration) return;
  chrono = millis();
  int bright;
  bright = int(3.6563*el+71.2);
  if(bright > 254) bright = 254;
  if(bright < 0) bright = 0;
  analogWrite(ao_pwm,bright);
}

// Turn of motor to save energy
void stopaz (unsigned long duration){
  static unsigned long chrono = millis();
  if (millis() - chrono < duration) return;
  chrono = millis();
  digitalWrite(do_M2P1, LOW);
  digitalWrite(do_M2P2, LOW);
  digitalWrite(do_M2P3, LOW);
  digitalWrite(do_M2P4, LOW);
}  

void setup() {
  analogWrite(ao_pwm,124);
  Wire.begin();
  lcd.begin(16,2);         // Set the LCD size (16 columns and 2 rows)
  lcd.backlight();         // Turn on backlight
  lcd.setCursor(0,0);
  lcd.print(" FABACADEMY 25");
  lcd.setCursor(0,1);
  lcd.print("DAYS OF DARKNESS");

  // set switches with internal pullup
  pinMode(di_set, INPUT_PULLUP);
  pinMode(di_end, INPUT_PULLUP);

  delay(2000);

  analogWrite(ao_pwm,0);

}

void loop() {

  // check if homing needs to be done
  if(home_az == false){
    //Homing azimuth axis
    lcd.clear();
    lcd.setCursor(1,0);
    lcd.print("Homing azimuth");
    int hall_last = analogRead(ai_hall);
    lcd.setCursor(0,1);
    lcd.print(hall_last);
    // when close to magnet reverse a bit
    while(analogRead(ai_hall) < 500){
      homeaz(false); 
      lcd.clear();
      lcd.setCursor(1,0);
      lcd.print("Homing azimuth");
      lcd.setCursor(0,1);
      lcd.print(analogRead(ai_hall));
      delay(30);
    // when close to magnet
    }
    // approach magnet fast and stop
    while(analogRead(ai_hall) > 400){
      homeaz(true); 
      lcd.clear();
      lcd.setCursor(1,0);
      lcd.print("Homing azimuth");
      lcd.setCursor(0,1);
      lcd.print(analogRead(ai_hall));
      delay(30);
    } 

    // find minimum value for magnet - compare with value from step before
    // run until minimum has passed
    do{
      hall_last = analogRead(ai_hall);
      homeaz(true);   
      lcd.clear();
      lcd.setCursor(1,0);
      lcd.print("Homing azimuth");
      delay(500);     
    }while(hall_last > analogRead(18));

    // back one step
    homeaz(false);
    lcd.clear();
    lcd.setCursor(1,0);
    lcd.print("Homing azimuth");
    lcd.setCursor(5,1);
    lcd.print("DONE");
    home_az = true;
    azpos = 180;          // Home position is with sun from the south
    delay(2000);
  }
  if(home_el == false){
    lcd.clear();
    lcd.setCursor(1,0);
    lcd.print("Homing zenith"); 
    lcd.setCursor(0,1);
    lcd.print(digitalRead(di_end));

    while(digitalRead(di_end)==HIGH){
      lcd.clear();
      lcd.setCursor(1,0);
      lcd.print("Homing zenith"); 
      lcd.setCursor(0,1);
      lcd.print(digitalRead(di_end));    
      homeel(false);
      delay(30);  
    }
    home_el = true;
    elpos = 0;        //End switch is at around 0° elevation
    lcd.clear();
    lcd.setCursor(1,0);
    lcd.print("Homing zenith"); 
    lcd.setCursor(5,1);
    lcd.print("DONE");  
    delay(1000);
  }

  // Update solar position
  solarcalc(100);  

  // Check if set button is pressed
  setbutton(200);

  // Check if model is running or stop
  if(run_stat == true){ 
    if(abs(azpos - az)> 0.8)runaz(30,true);
    if(abs(elpos - el)> 0.8){
      if(el<elpos && digitalRead(di_end == HIGH))runel(30,false);
      if(el>elpos)runel(30,true);
    }
    //set brightness
    sunpwm(1000);
    // when position is reached, turn off
    if (abs(azpos - az)< 1 && abs(elpos - el)<1)run_stat = false;

  }else{   
    stopaz(400);                
    readai_stop(500);
  }

  // Display update
  updateoled(200);

}

Here is a final picture of the machine and the group assignemnt is finished.

Final picture