---
author: Akbar Rahman (20386125)
date: \today
title: MMME3085---Lab 2 Coursework
tags: [ mmme, mmme3086 ]
documentclass: article
geometry:
    - margin=1in
---

\maketitle
\thispagestyle{empty}
\newpage

# Question 1

As you increase the proportional gain, you increase the responsiveness of the motor to error,
but it is easy to go too high and cause the motor to oscillate around the target position.
This is because the motor current is set proportional to the error.
This means that if the motor is spinning too quickly, the proportional control will not slow
down the motor in time to avoid overshoot.
Additionally, if the target position is set too close to the motor, the proportional control
maybe not push enough current to motor to actually get it spinning in some cases.

# Question 2

When derivative control is added at low levels (0.02) it reduces the oscillations.

This is because derivative control only considers the rate of change of of the error
and tries to bring the rate of change to zero.
This means that adds a *damping* effect to the controller, slowing it down when it's moving,
and thereby reducing/eliminating overshoot and oscillations.

# Question 3

There are two if statements in the loop function as the controller will work best and be able to respond
to changes faster if the control functions are run more frequently.
The faster the better.
However, the Arduino does not really need to print to serial every time as it is only used to ensure
the Arduino is running properly.

If `prevMillisControl` and `prevMillisPrint` was replaced with just one variable, the `printLoop` function
would never run as the variable would have been updated to equal `currentMillis` before the print loop's
if statement will check its condition.

# Question 4

First the library is `include`d on line 4:

```c
#include <PID_V1.h>
```

Then a PID object is created using the `myPID` function on line 48.
This object holds all the properties of the PID controller including values of $K_p$, $K_i$, and $K_d$,
as well as a pointers to variables with the current motor position, speed, and set point.

```c
PID myPID(&encoderPosnMeasured, &percentSpeed, &positionSetPoint, Kp, Ki, Kd, DIRECT);
```

Some initialisation is run in `setup` on lines 89 and 90:

```c
  myPID.SetOutputLimits(-100,100);
  myPID.SetMode(AUTOMATIC);
```

Then the main control loop starts.
The `loop` function runs the `controlLoop` function every 20 milliseconds (as defined by
`controlInterval`) on line 101.

The `controlLoop` function retrieves the current motor position and stores it in the variable
that the PID controller has a pointer to.

`myPID.Compute()` is then called to recompute the motor speed required to get to the set point
and this is stored in the `percentSpeed` variable as the controller has a pointer to it.
This new speed is passed to the `driveMotorPercent` function to update the motor's speed.

\newpage

# Question 5

The mathematically complex operations in `loop()` as it is run infrequently.
This is because it is inside an if statement with condition `convertNewNumber()`, which
returns `false` if there is no new data to convert (i.e. if there has not been any serial input
since the last loop).

Essentially, the complex operations only run once per serial input, meaning it is run very infrequently
compared to how many times the loop runs.

# Question 6

Complex operations in `computeNewSpeed()` have been avoided because this function runs very frequently
(on the order of microseconds).
Therefore it is important that the function does not consume too many processor cycles,
else the Arduino will be able to do little else.

# Question 7

If the stepper motor is run too quickly, steps will be skipped and it will not accelerate or
accelerate slowly.
It also makes a different noise to normal operation.

This is because the pole pairs of the motor will be activated too soon if attempting to spin
the motor too fast.
If they are activated too soon, they will not have the desired effect of speeding up the rotation
of the shaft, as the magnets of the motor will not be aligned as needed.

This is also why the steppers use a ramp function, so that the shaft has time accelerate to the
desired speed without skipping steps.

\newpage

# Question 8

```{ .matplotlib caption="A plot of velocity and acceleration for SimplisticRampStepper" dpi=300 }
import numpy as np
import matplotlib.pyplot as plt

TIME = 'Time_s'
SPEED = 'Speed_stepss'
ACCEL = 'Accel_stepss2'
POS = 'Positn_steps'
STEP = 'Step_time_ticks'

data = np.genfromtxt("csv/SimplisticRampStepper_out_50.csv",
                 delimiter=",", names=True, dtype=float)

fig, ax1 = plt.subplots()
ax2 = ax1.twinx()

lines1 = ax1.plot(data[TIME], data[SPEED], label='Speed [steps/s]', color='tab:blue')
lines2 = ax2.plot(data[TIME], data[ACCEL], label='Acceleration [steps/s^2]', color='tab:red')
ax1.set_ylabel('Speed [steps/s]')
ax2.set_ylabel('Acceleration [steps/s^2]')

lines = lines1 + lines2
ax1.legend(lines, [ l.get_label() for l in lines ])

ax1.set_xlabel("Time [s]")

fig.tight_layout()
```

```{ .matplotlib caption="A plot of velocity and acceleration for LeibRampStepper" dpi=300 }
import numpy as np
import matplotlib.pyplot as plt

TIME = 'Time_s'
SPEED = 'Speed_stepss'
ACCEL = 'Accel_stepss2'
POS = 'Positn_steps'
STEP = 'Step_time_ticks'

data = np.genfromtxt("csv/LeibRampStepper_out_50.csv",
                 delimiter=",", names=True, dtype=float)

fig, ax1 = plt.subplots()
ax2 = ax1.twinx()

lines1 = ax1.plot(data[TIME], data[SPEED], label='Speed [steps/s]', color='tab:blue')
lines2 = ax2.plot(data[TIME], data[ACCEL], label='Acceleration [steps/s^2]', color='tab:red')
ax1.set_ylabel('Speed [steps/s]')
ax2.set_ylabel('Acceleration [steps/s^2]')

lines = lines1 + lines2
ax1.legend(lines, [ l.get_label() for l in lines ], loc='upper right')

ax1.set_xlabel("Time [s]")

fig.tight_layout()
```
