# Machine building week
For this week we needed to build a machine. We started brainstorming and came up with a few ideas. 

![alt text](<Adobe Scan 10 Apr 2025 (2)-1.png>)
Here are a few of our ideas
* In the top left we have the self driving trash can that comes to pick up your trash. 
* An automatic tea maker
* Some kind of machine that keeps on juggling something
* An introverted shy robot
* A machine that automatically shoots darts in the bullseye of a dart board
* An system to automatically refills the water in our coffee machines so it doesn't starts beeping loudly

We went with the idea of the Shy robot in the end. I thought the dart throwing robot was really cool. But we wen't with the Shy robot in the end because it is more realistic to make and democracy. 

![alt text](<Adobe Scan 10 Apr 2025 (1)-1.png>)

Here are the first few sketches of the shy robot. We wanted to give it eyes on strings that push but we wanted more mechanical stuff. So we decided on making his head a big lid and making the eyes pop out there. So we used more actuators and mechanical stuff.

![alt text](<Adobe Scan 10 Apr 2025-1.png>)

![alt text](image-9.png)
During our brainstorming session Henk also asked us to think about which sensor you are going to use and how many to see how many pins you need.


## Starting with the electronics
Starting the project we used last years prototype as our starting point.
![alt text](image-10.png)
(Our robot already strapped with an Ultrasonic and a Time of flight sensor)
Dylan and I wanted to do the coding and electronics of the robot and Patrick and Irja took the designing and building part of the robot.

We realized quickly that we only had 2 ports left over because all other where in use by the arduino motor drive hat. These 2 ports that where left over where the I2C port SDA and SCL. So I thought let's use ToF sensors since you can hook up multiple on I2C. After some digging in the datasheet I found out that wouldn't work because whenever you assign a I2C address to a VL53X1L it would forget it next power cycle. So I thought: what if I used a multiplexer connected to all the XSHUT pins of the ToF sensor to turn them on one by one and assign them each their own I2C address on startup.
![alt text](image-11.png)

Luckily we had the I2C multiplexer [PA9555](https://www.nxp.com/docs/en/data-sheet/PCA9555.pdf). So I used I2C for everything because I had limited pins. So I started designing a circuit.

![alt text](image-1.png)
With this board I wanted to make a breakout for 5 I2C devices. So I could hook up 5 time of flight sensors for example. The first attempt I gave up. I also asked henk for some feedback on how to do the connectors. He recommended using UDPI connectors and making breakout boards for every ToF sensor so I could connect them properly.

![alt text](image-3.png)
So my schematic wen't to this.
![alt text](image-2.png)
make because of all the bridges I needed to add in

![alt text](image-7.png)
This is the most recent design for now. It was a pain to make all the bridges and swapping back and forth.

This is the design for the breakout board. We are using pin headers since we already have soldered ToF sensors
![alt text](image-5.png)
![alt text](image-6.png)
![alt text](image-4.png)

### The end result:
![alt text](image-12.png)
This board could connect 5 ToF sensors together on one I2C bus.



## Chapter 2 Ultrasonic sensors
We didn't have enough ToF sensors for our robot. I asked Henk if I could order some for myself and use them in the project. But he told me no and to use ultrasonic sensors. And he told me to use the current board for that. But I said that wouldn't work because only one multiplexer pin goes to each breakout because I designed it for the ToF so now im going to do some solder hacking and try to wire it together myself.


??? Failure
    ```cpp
    int readUltrasonicSensor(int trig, int echo)
    {
    long duration, cm;

    // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
    // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
    ioex.write(PCA95x5::Port::P06, PCA95x5::Level::L);
    delayMicroseconds(5);
    ioex.write(PCA95x5::Port::P06, PCA95x5::Level::H);
    delayMicroseconds(10);
    ioex.write(PCA95x5::Port::P06, PCA95x5::Level::L);

    ioex.direction(PCA95x5::Port::P07, PCA95x5::Direction::IN);
    duration = pulseIn(ioex.read(PCA95x5::Port::P07), HIGH);
    // Convert the time into a distance
    cm = (duration / 2) / 29.1; // Divide by 29.1 or multiply by 0.0343
    Serial.print("Distance: ");
    Serial.print(cm);
    return (cm);
    // https://randomnerdtutorials.com/complete-guide-for-ultrasonic-sensor-hc-sr04/
    }
    ```
Here I tried measuring the signal myself but I didn't receive anything back from the multiplexer
??? Failure
    ```cpp
    // A0 trigger, A1 Echo
    int readUltrasonicSensor(int trig, int echo)
    {

    long duration, cm;

    // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
    // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
    ioex.write(PCA95x5::Port::P06, PCA95x5::Level::L);
    delayMicroseconds(5);
    ioex.write(PCA95x5::Port::P06, PCA95x5::Level::H);
    delayMicroseconds(10);
    long startTime = micros();
    ioex.write(PCA95x5::Port::P06, PCA95x5::Level::L);

    while (PCA95x5::Level::H == ioex.read(PCA95x5::Port::P07))
    {
        duration = micros() - startTime;
    }

    // Convert the time into a distance
    cm = (duration / 2) / 29.1; // Divide by 29.1 or multiply by 0.0343
    Serial.print("Distance: ");
    Serial.print(cm);
        return (cm);
    // https://randomnerdtutorials.com/complete-guide-for-ultrasonic-sensor-hc-sr04/
    }
    ```
Sort of works but it works super innacurate. I can move it around and it will display different values depending on how far it is from the table

![alt text](image-8.png)

For now I will plug the trigger into the multiplexer and the Echo pin into the arduino. Then I can measure the length of the signal to measure the distance.

### Optimization
We had the issue that the arduino didn't run fast enough to read from the sensors and to control the motors simultaneously even when shrinking down the code to this.
??? Old code
    ```cpp
    #include <AccelStepper.h>

    //=============================================================================================//
    //Stepper motor pins
    //=============================================================================================//

    #define MOTOR_X_ENABLE_PIN 8
    #define MOTOR_X_STEP_PIN 2
    #define MOTOR_X_DIR_PIN 5


    #define MOTOR_Y_ENABLE_PIN 8
    #define MOTOR_Y_STEP_PIN 3
    #define MOTOR_Y_DIR_PIN 6


    #define MOTOR_Z_ENABLE_PIN 8
    #define MOTOR_Z_STEP_PIN 4
    #define MOTOR_Z_DIR_PIN 7

    #define MOTOR_A_ENABLE_PIN 8
    #define MOTOR_A_STEP_PIN 12
    #define MOTOR_A_DIR_PIN 13

    //=============================================================================================//
    //Global object creations
    //=============================================================================================//

    AccelStepper motorX(1, MOTOR_X_STEP_PIN, MOTOR_X_DIR_PIN);
    AccelStepper motorY(1, MOTOR_Y_STEP_PIN, MOTOR_Y_DIR_PIN);
    AccelStepper motorZ(1, MOTOR_Z_STEP_PIN, MOTOR_Z_DIR_PIN);
    AccelStepper motorA(1, MOTOR_A_STEP_PIN, MOTOR_A_DIR_PIN);

    //=============================================================================================//
    // Function declarations
    //=============================================================================================//

    void moveForw(int speed);
    void moveBack(int speed);
    void moveStop();
    int readUltrasonicSensor(int trigPin, int echoPin);
    void rotateLeft();
    void stepperSetup();

    int mm = 0;

    void setup()
    {
    Serial.begin(9600);
    stepperSetup();
    pinMode(A2, INPUT);
    }

    void loop()
    {
    mm = readUltrasonicSensor(A1, A0) * 10; // Convert cm to mm
    Serial.println(mm); // Print distance in mm
    // Define distance thresholds
    const int SAFE_DISTANCE_FRONT = 2500;    // 500mm
    const int WARNING_DISTANCE_FRONT = 1250; // 250mm
    const int DANGER_DISTANCE_FRONT = 800;   // 100mm

    const int SAFE_DISTANCE_BACK = 400;   // 40cm
    const int DANGER_DISTANCE_BACK = 200; // 20cm

    moveForw(0);
    }

    void moveForw(int stepDelay)
    {
    motorX.move(3000);
    motorX.run();
    motorY.move(3000);
    motorY.run();
    motorZ.move(3000);
    motorZ.run();
    motorA.move(3000);
    motorA.run();
    
    }

    void moveBack(int speed)
    {
    motorX.move(-3000);
    motorX.run();
    motorY.move(-3000);
    motorY.run();
    motorZ.move(-3000);
    motorZ.run();
    motorA.move(-3000);
    motorA.run();
    }

    void moveStop()
    {
    motorX.move(0);
    motorX.run();
    motorY.move(0);
    motorY.run();
    motorZ.move(0);
    motorZ.run();
    motorA.move(0);
    motorA.run();
    }

    void rotateLeft()
    {
    motorX.move(3000);
    motorX.run();
    motorY.move(1500);
    motorY.run();
    motorZ.move(1500);
    motorZ.run();
    motorA.move(1500);
    motorA.run();

    }

    // A0 trigger, A1 Echo
    int readUltrasonicSensor(int trigPin, int echoPin) {
    int duration, cm;
    // The sensor is triggered by a HIGH pulse of 10 or more microseconds.
    // Give a short LOW pulse beforehand to ensure a clean HIGH pulse:
    digitalWrite(trigPin, LOW);
    delayMicroseconds(5);
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);
    
    // Read the signal from the sensor: a HIGH pulse whose
    // duration is the time (in microseconds) from the sending
    // of the ping to the reception of its echo off of an object.
    pinMode(echoPin, INPUT);
    duration = pulseIn(echoPin, HIGH);
    
    // Convert the time into a distance
    cm = (duration/2) / 29.1;     // Divide by 29.1 or multiply by 0.0343
    

    return cm;
    }

    void stepperSetup(){
    pinMode(MOTOR_X_ENABLE_PIN, OUTPUT);
    pinMode(MOTOR_Y_ENABLE_PIN, OUTPUT);
    pinMode(MOTOR_Z_ENABLE_PIN, OUTPUT);
    pinMode(MOTOR_A_ENABLE_PIN, OUTPUT);

    motorX.setEnablePin(MOTOR_X_ENABLE_PIN);
    motorX.setPinsInverted(false, false, true);
    motorX.setAcceleration(100);
    motorX.setMaxSpeed(100);
    motorX.setSpeed(100);
    motorX.enableOutputs();

    motorY.setEnablePin(MOTOR_Y_ENABLE_PIN);
    motorY.setPinsInverted(false, false, true);
    motorY.setAcceleration(100);
    motorY.setMaxSpeed(100);
    motorY.setSpeed(100);
    motorY.enableOutputs();

    motorZ.setEnablePin(MOTOR_Z_ENABLE_PIN);
    motorZ.setPinsInverted(false, false, true);
    motorZ.setAcceleration(100);
    motorZ.setMaxSpeed(100);
    motorZ.setSpeed(100);
    motorZ.enableOutputs();

    motorA.setEnablePin(MOTOR_Z_ENABLE_PIN);
    motorA.setPinsInverted(false, false, true);
    motorA.setAcceleration(100);
    motorA.setMaxSpeed(100);
    motorA.setSpeed(100);
    motorA.enableOutputs();
    }
    ```




Issue: The motors didn't have enough power

Solution find the maximum current for the motors and the stepsticks in the datasheet.


