Writing code for mechatronical prototypes

Often, it might not be the physical circuits and builds in mechatronics that users have trouble building, but more likely the code that has to be written for the microcontrollers that will cause frustration. Hence, the creation of this website!

In this following section we'll go through how 99% of mechatronical code is written across all .

Pre-setup, setup & loop

It needs to be stated that we, the authors of this website, aren't experts in programming. We're only mechatronical enthusiasts, and you should therefore not take our definitions and terms as an industry standard.

With that out of the way, we argue that almost all code written for mechatronical prototypes are build with a pre-setup, setup, and a main loop.

Pre-setup

The pre-setup will on some platforms be the same as the actual setup (such is the case on the raspberryPi and the Spike Prime). Before any functions is activated through the code, are imported and names are defined, as seen in the code below.

from library import LED
from time import sleep

led = LED(17)

The pre-setup is for the code that should run before anything else in the code, making sure that you have every tool ready at hand.

Setup

Specifically for the Arduino, the setup is the section in your code that should run once when the program starts. Normally, this could be to initialize the or to make sure a motor starts in an off-state as seen in the example below.

void setup() {
  Serial.begin(9600);
  pinMode(led, OUTPUT);
}

For the and , there's no specific section called setup(). Here, all the code that is not in the main loop will only be called once (unless the code is in an callback function, but that's a bit more complicated than what we care to explain on this website).

Main loop

Now the main loop is where the magic happens. Normally you would want a mechatronical prototype to do something continuously. It could be a robot that checks the soil moisture, and when the moisture gets too low, it will then go water the plants.

Either way, the main loop is something that gets repeated as long as the microcontroller is on, normally with some delays within each repeat. An example of a main loop can be found in the code below.

while True:
  # Print True when pushed
  if button.is_pressed():
    print('Pressed!')
    wait_for_seconds(1)
  else:
    print('Button is not being pressed')
    wait_for_seconds(1)

Inputs and outputs (digital & analog)

The previous section introduced the general code structure that is present in most scripts. In this section, we'll go a bit more into what actually happens within the main part of the script, i.e what comes in (input), what comes out (output) and what happens in between (processes).

Digital & analog values

Before getting into inputs and outputs, we quickly want to mention digital & analog values.

Digital values

Keeping it simple, digital values are the numbers 1 and 0, nothing more, nothing less. Normally you would see digital values as the answers "Yes" and "No" to questions in your code. In the code above, button.is_pressed() will give you either an 0 (the button is NOT pressed) or 1 (the button IS pressed). Sometimes you will also want to toggle something with a digital value, such as lighting up an LED as can be seen in the example below:

while True:
    #Blink LED with 1 second intervals
    LED.light_up_all(1)
    wait_for_seconds(1)
    LED.light_up_all(0)
    wait_for_seconds(1)

Here LED.light_up_all() takes either 0 or 1 as the values for off and on.

Analog values

Now instead of only taking the numbers 0 and 1, analog values includes a range of numbers, normally from 0 to 255. If 0 would be equal to the minimum value and 1 equal to maximum value for the digital values, then so would 0 and 255 be for analog values. The analog values are especially valuable (you're welcome) when you have to dial something up and down, or when working with percentages. Instead of using button.is_pressed(), one could use button.get_force_percentage() instead, which returns how much percentage wise, the button is pushed down (note, this is only the case for the Spike Prime button as it also serves as a force sensor). The code LED.light_up_all() actually also takes analog values from 0 - 100 to turn the light up from 0% - 100%.

Inputs

An input is something that comes into the microcontroller (duh), which is also called reading data. There's many different ways a microcontroller can gather inputs, from physical sensors such as a pushbutton, to weather data from an online website. In the code example above, button.is_pressed() is a digital input, while get_force_percentage() is an analog input and both is data being read.

Outputs

As you might have guessed, outputs are something that comes out of the microcontroller which is also called writing data (it's all coming together now). Looking back at the LED code LED.light_up_all(), that is an output, the microcontroller telling the LED to light up with a certain value.

Writing and reading manually

Code such as button.is_pressed() and LED.light_up_all() only works because a library enables it. However, sometimes there won't be a library for the specific component you're sitting with, and you'll have to tell the component manually how it needs to behave. Luckily, this is not too difficult as both Arduino and RaspberryPi has the commands digitalRead(), digitalWrite(), analogRead() and analogWrite(). As the name implies, you can write and read, both digitally and analog through the pins in the respective microcontrollers.

The code below shows an example of how a full script would look like. In this case, it an Arduino Uno that has an attached. Notice how there's both inputs, outputs, digitalWrite, setup, loop, etc.

const int trigPin = 9;
const int echoPin = 10;
float duration, distance;

void setup() {
  // put your setup code here, to run once:
  pinMode(trigPin, OUTPUT); // Set the trigger as an output
  pinMode(echoPin, INPUT); // Set the echo as an input
  Serial.begin(9600); // Starts the serial so you can read the messages
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(trigPin, LOW); // Sets the trigger to LOW
  delayMicroseconds(2); // Pauses for a brief moment
  digitalWrite(trigPin, HIGH); // Sets the trigger to HIGH
  delayMicroseconds(10); // Pauses for a brief moment
  digitalWrite(trigPin, LOW); // Sets the trigger to LOW
  duration = pulseIn(echoPin, HIGH); // Reads the duration of the sound to travel
  distance = (duration * .0343) / 2; // Converts speed of sound to cm
  Serial.print("Distance: ");
  Serial.print(distance);
  Serial.println("cm");
  delay(100);
}

Articles mentioning this page

Introductions