Arduino Examples

Below you will find some random project examples, shared on Youtube.



Some Ipson interface projects:

Timed Processes

When movement is detected, this thing needs to go on for three seconds after which it should not be triggered for ten seconds. But if nothing happens in two minutes, it should trigger by itself. How?

Question posed by a random colleague student

The global behaviour of an installation based on a microcontroller, often includes timed processes. For instance, after a trigger, the input is blocked for a certain amount of time; if nothing happens for a while, generate an event; if within a certain time span a second trigger is sensed, change the behaviour; etc.

The most fundamental blink example suggests that timing can be controlled with a delay() function. However, the delay() has a fundamental issue which renders it useless in all of the situations described above: the program will proceed to the next line of code only when the wait is finished. In other words, during a delay(), all processing comes to a standstill. The function delay() could as well have been called holiday(). Therefore, ditch the delay().

The blink without delay and debounce examples introduce an approach to timing using the millis() function. It is an approach in which the passing of time is measured based on an onboard clock. When multiple overlapping time units are involved, this approach tends to become complex and difficult to manage. An alternative solution can be found in using the millisDelay statement, which is part of an external library. This library can be found and installed through the Manage Libraries… menu option.

Detecting State Change

In order to connect an action to sensor input, it is important to be clear about what is the difference between a sensor measurement—e.g. a value from digitalRead()—and a state changement—e.g. when a button is pressed, while before it wasn’t. Sensor measurement produces a stream of values, while a state change should be able to detect the moment at which a button is pressed. A stream of values is what is produced in the Digital Read Serial example.

In order to detect a state change, the code needs to be extended in such a way that the current state can be compared with the previous. When considering that what is defined in the loop() routine represents a single lifespan of the loop, something needs to be handed to the collective unconsciousness—or, in terms of Arduino code, a global variable—before the current run of the loop dies in order to be retained.

Here the order of things can be explained as follows. At the moment the button is pressed—nowClosed is true—while before it wasn’t—beforeOpen is true as well—the if statement checking these two booleans will execute the first section. The LED turns on and the serial monitor prints “switch closed”. At the moment the button is released, momentarily the else if sees it’s conditions met and will execute the connected block. All other cases are neither of these two options and are disregarded.

The last line—beforeOpen = !nowClosed—although it appears a bit cryptic is the crucial bit of information that becomes available the next time the loop runs: beforeOpen will become true if nowClosed is not true. We could consider this the will of the current loop that dictates the heritage of the next loop.

const int ledPin = 13;
const int switchPin = 2;
bool beforeOpen = true;


void setup() {
  pinMode(switchPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);
}

void loop() { // loop is (re)born
  bool nowClosed = digitalRead(switchPin) == 0;
  if (nowClosed && beforeOpen) {
    digitalWrite(ledPin, HIGH);
    Serial.println("switch closed");
    delay(5); // lazy debounce
  }
  else if (!nowClosed && !beforeOpen) {
    digitalWrite(ledPin, LOW);
    Serial.println("switch open");
    delay(5); // lazy debounce
  }
  beforeOpen = !nowClosed; // update global variable for next loop
} // loop dies

Temporarily Block Sensor Input

The state change introduced in the previous example, will be used here to connect specific actions. When the button is pressed, it will activate a timer that blocks the detection of the on state for a certain amount of time. Releasing the button will have no meaning in this context and the action connected to that can be removed.

The timer is created using the millisDelay.h library, and a delay is created using the millisDelay ledDelay statement. This ledDelay becomes a reference to a mechanic that is running in the background, that can measure time. A trigger is sent using ledDelay.start(LED_time), where LED_time specifies the amount of milliseconds it will take before ledDelay returns the trigger, signaling the end of the delay. This end trigger needs to be queried using the ledDelay.justFinished() statement, which will become true when this is the case. Until this happens, input by the button will be blocked.

#include <millisDelay.h>

const int ledPin = 13;
const int switchPin = 2;
bool beforeOpen = true;
bool blocked = false;
int LED_time = 2000;
int switchCount = 0;

millisDelay ledDelay;

void setup() {
  pinMode(switchPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);
}

void loop() {
  bool nowClosed = digitalRead(switchPin) == 0;
  if (nowClosed && beforeOpen && !blocked) {
    Serial.print("switch closed ");
    switchCount += 1;
    Serial.println(switchCount);
    digitalWrite(ledPin, HIGH);
    ledDelay.start(LED_time);
    blocked = true;
//    delay(5);
  }
//  else if (!nowClosed && !beforeOpen) {
//    Serial.println("switch open");
//    delay(5);
//  }
  if (ledDelay.justFinished()) {
    digitalWrite(ledPin, LOW);
    blocked = false;
  }
  beforeOpen = !nowClosed;
}

Auto-Trigger

A second millisDelay is added in order to automatically trigger the process—following the requirements posed in the top section, although for testing the time for this is reduced to 10 seconds.

When the Arduino starts up, this second delay, which refers to the autoMode flag, is triggered. Now there are two options, either the button is pressed before ten seconds pass, or isn’t. In the first case the autoDelay will be stopped; only when the button was pressed autoDelay.isRunning() will be true. Since later on in the code we will check whether the autoDelay.justFinished(), the autoReset flag is used to indicate that a reset has happened because of an activation, instead of time running out.

In the second case, the autoMode flag is raised so an activation can take place. The overview below shows how these flags are raised and lowered either because of a button pressed or the ten seconds auto trigger.

#include <millisDelay.h>

const int ledPin = 13;
const int switchPin = 2;
bool beforeOpen = true;
bool blocked = false;
bool autoMode = false;
bool autoReset = false;
int LED_time = 2000;
int auto_time = 10000;
int switchCount = 0;

millisDelay ledDelay;
millisDelay autoDelay;

void setup() {
  pinMode(switchPin, INPUT_PULLUP);
  pinMode(ledPin, OUTPUT);
  Serial.begin(115200);
  autoDelay.start(auto_time);
}

void loop() {
  bool nowClosed = digitalRead(switchPin) == 0;
  if (nowClosed && beforeOpen && !blocked || autoMode) {
    digitalWrite(ledPin, HIGH);
    ledDelay.start(LED_time);
    if (autoDelay.isRunning()) {
      autoDelay.finish();
      autoReset = true;
    }
    switchCount += 1;
    if (Serial) {
      Serial.print("switch closed ");
      Serial.println(switchCount);
    }
    blocked = true;
    autoMode = false;
  }
  if (ledDelay.justFinished()) {
    digitalWrite(ledPin, LOW);
    blocked = false;
    autoDelay.start(auto_time);
  }
  if (autoDelay.justFinished()) {
    if (!autoReset) {
      autoMode = true;
    }
    autoReset = false;
  }

  beforeOpen = !nowClosed;
}

SuperCollider

SuperCollider + Arduino #1

In this page we will learn the basics of serial communication between SuperCollider and Arduino. To start off we’re going to control the brightness of LED from SuperCollider! First, our circuit:

Now, in Arduino upload:

unsigned char val = 0;

void setup() { 
  Serial.begin(9600);
  pinMode(11, OUTPUT); // use one of the ~ pwm pins!
} 

void loop() {
  if (Serial.available()) {
    val = Serial.read();
    analogWrite(11, val);
  }
}

Finally in SuperCollider:

// evaluate to find the name of your arduino
SerialPort.listDevices;
// see post window

// make sure serial monitor is not open in arduino IDE
// then open port
(
~port = SerialPort(
	"/dev/cu.usbmodem141101", // your arduino's name
	baudrate: 9600, // must match arduino rate
	crtscts: true
);
)

// send to arduino
// maximum brightness
~port.put(255);

// minimum
~port.put(0);

// random flicker
r = Routine { loop { ~port.put(1.exprand(255)); 0.3.wait } }.play;

// stop
r.stop;

// close before quitting
~port.close;

More than 1 LED?

When controlling more than 1 LED, we need to identify them. In Arduino:

unsigned char val = 0;
unsigned char id = 0;
  
void setup() { 
  Serial.begin(9600);
  // use 2 of ~ pwm pins
  pinMode(11, OUTPUT);
  pinMode(9, OUTPUT);
} 

void loop() {
  // need to wait till you get
  // more than 1 data
  if (Serial.available() > 1) {
    id = Serial.read();
    val = Serial.read();
    analogWrite(id, val);
  }
}

and in SuperCollider:

// evaluate to find the name of your arduino
SerialPort.listDevices;
// see post window

// make sure serial monitor is not open in arduino IDE
// then open port
(
~port = SerialPort(
	"/dev/cu.usbmodem141101", // your arduino's name
	baudrate: 9600, // must match arduino rate
	crtscts: true
);
)

// send id & brightness to arduino
// pin 11 maximum brightness
~port.putAll([11, 255]);

// pin 11 minimum
~port.putAll([11, 0]);

// or 2 in 1
// both pins max brightness
~port.putAll([11, 255, 9, 255]);

// both pins off
~port.putAll([11, 0, 9, 0]);

// close before quitting
~port.close;

SuperCollider + Arduino #2

In the examples above we controlled LEDs from SuperCollider. Here, however, we are going to do the opposite: using a push button and potentiometer on Arduino to control sounds in SuperCollider.

In Arduino:

int push = 0;
int pot0 = 0;
int pot1 = 0;

void setup() {
  Serial.begin(9600);
  pinMode(2, INPUT); // our push button
  waitForSuperCollider();
}

// a monitor function waiting to 'handshake' with supercollider
void waitForSuperCollider() {
  while (Serial.available() <= 0) {
    // send an initial string. must match the number of values you want to send
    Serial.println("0,0,0");
    delay(300);
  }
}

void loop() {
  if (Serial.available() > 0) {

    // read from supercollider
    Serial.read();

    // our readings in arduino
    push = digitalRead(2);
    pot0 = analogRead(A1);
    delay(10); // delay in between analog reads for stability
    pot1 = analogRead(A2);

    // below will serial print an array of values
    Serial.print(push);
    Serial.print(","); // adding comma!
    Serial.print(pot0);
    Serial.print(","); // adding comma!
    Serial.println(pot1); // finally, break line!
  }
}

In SuperCollider:

// evaluate to find the name of your arduino
SerialPort.listDevices;
// see post window

// make sure serial monitor is not open in arduino IDE
// then open port
(
~port = SerialPort(
	"/dev/cu.usbmodem141101", // your arduino's name
	baudrate: 9600, // must match arduino rate
	crtscts: true
);
)

// a loop for reading from arduino
(
~routine = Routine {
	var byte, str, val;
	inf.do { |i|
		if(~port.read == Char.nl.asInteger, {
			str = "";
			while(
				{ byte = ~port.read; byte != Char.ret.asInteger },
				{ str = str ++ byte.asAscii }
			);
			val = str.split(Char.comma).asInteger;
			
			// our sound 
			// triggered and controlled form arduino
			
			// push button = on/off sound
			// pot0 = freq
			// pot1 = amp
			
			if(val[0] == 1, { 
			{ SinOsc.ar(
				val[1].linexp(0, 1023, 400, 1600), 0, 
				val[2].linlin(0, 1023, -30, -16).dbamp
			) * Env.perc(0.01, 0.1).kr(2) }.play;
			});
		});
	};
}.play;
)

// this will kick off reading (handshaking with arduino)
~port.put(0);

// stop
~routine.stop; ~port.close;

Actuators

Wiki:
An actuator is a component of a machine that is responsible for moving and controlling a mechanism or system, for example by opening a valve. In simple terms, it is a “mover”.

Digital output: LED’s

LED’s can be driven by terminals in either digital or analog output modes. Digital output provides on/off, whereas analogue output provides a signal that looks like dimming the intensity of the light – we call this PWM, or Pulse Width Modulation.
For digital output connected like the figure on the right, D1 will light up when the terminal is 0V (Low) and D2 will light up when the terminal output is high (+5V).

If you want to change the intensity of the light, or the speed of a motor we use Pulse Width Modulation. An Arduino or any other interface is a digital device. And a digital device only knows two states: On/Off, Yes/No, One/Zero. So if analogue output is mentioned, this is not really “true”. 


PWM outputs

PWM is a method of changing the width of the pulse, so the average signal value will increase or decrease. In the Arduino language an ‘AnalogWrite(variable, xxx); creates a pulse width modulation signal.

The Arduino or any other microcontroller device is not capable of providing a lot of current – in other words, if you want to connect an (heavy) actuator that really needs lots of current to ‘move’, you have to interface it. In between the output of the microcontroller and the actuator extra electronics is needed to ‘amplify’ the current.

Below a few circuit examples.

Transistor (current) interface – driving a relay
FET (voltage) interface – driving a DC-motor

Protected: SAM Links

This content is password protected. To view it please enter your password below:

Artscience SAM

Sensors Actuators and Microcontrollers

The course will be given by Johan van Kreij and Lex van den Broek

The world of sensors and Actuators combined with Microcontrollers like Arduino / Teensy / ESP / Beagle / RaspBerryPie / is huge and can be very complex if you are a beginner or even an advanced user.

This SAM-course of 8 days will introduce you to the hybrid world of Analog- and Digital electronics. How to connect sensors to an Arduino and sending the measured data to miscellaneous software within your computer? How to drive (actuate) motors or lights?

The goal of the course is that you work on your own project and try to apply the techniques we show (analog, digital and code) into your own project. Subjects like ‘Serial communication, Operational Amplifiers, Max objects, Sensors, Field Effect Transistors, Com ports, Current, Actuators, Voltage, Resolution and much more subjects will be addressed. We will mainly work with Arduino boards. If you have one yourself already, great! If you do not have one, you can borrow one at the EWP – let us know.  

There will be 8 days in total, starting at 10:00 and ending at 16:00. We will start on Monday March 11 and end the course on Friday March 22 .

On Wednesdays there will be no lessons.


SAM course (23/24): March 11 2024 – March 22 2024






Arduino fundamentals

What is Arduino?

Arduino is an open-source electronics platform based on easy-to-use hardware and software. It’s intended for anyone making interactive projects.

An Arduino board as shown above (UNO revision3) is in fact a small sized computer that can be easily programmed by the user to do all kind of conversions. When we compare the Arduino with a real computer, it does not have the general input and output devices like the screen, keyboard or mouse. Instead it only has analog/digital voltage-inputs and voltage-outputs. For more extensive information about Arduino, visit their website: https://www.arduino.cc/


Inputs and Outputs

The standard Arduino Uno has 6 analog inputs (A0 – A5). These inputs are connected to a 10-bits Analog-Digital Convertor (ADC). The voltage changes between 0V and 5V can be applied to these 6 pins, are converted into a number that has a resolution of 10 bits ( 210 = 1024 steps).

Besides the special analog inputs, the Arduino Uno has 12 digital In/Outputs, from which 6 are defined to be PWM. The other half is only digital On/Off. In the software program (the patch) the user can define which pin of the Arduino will be input or output.

An Arduino is a digital device. This means it only deals with ‘0’ and ‘1’. An output that is called analog in this case is in fact a digital output, but with a very fast switching mechanism called Pulse Width Modulation. All the outputs that are marked with a ~ are ‘analog’ outputs, that will generate PWM.

Pulse Width Modulation equals the ‘Analogue’ output

Getting started

The first step in programming your own Arduino is to connect the Arduino-board to your computer using the right USB-cable. Your computer will recognize the board and no external drivers have to be installed. You will notice the small led (pin13) lighting up, indicating the board has power.

The next step is to download the Arduino software, which enables you to write your program and program the board. Check this link: https://www.arduino.cc/en/software to download the latest IDE. The open-source Arduino Software (IDE) makes it easy to write code and upload it to your board.


Simple Example – equipment test

The best way to test your Arduino/Computer setup, is to start with a simple example like the program ‘blink’. This program makes the onboard led ( = pin 13) light-up (ON) and Off with a time delay of 1 second.

File/Examples/Basics/Blink


Basically this program is not of any ‘practical’ use other then check the setup and getting to know the way the Arduino works. On the other hand, you create a rectangle wave-shape with a frequency of 0,5Hz on the output of the board = pin 13 (delay time ON=1000mS and delay time OFF is 1000mS). The blink-program also shows you the fundamental setup or configuration of a program or ‘patch’.

Blink patch. Led L on pin 13 switches On/Off with a delay of (in the picture 100mS)

The code in the picture above show the most fundamental setup of a program or patch. The tekst that is ‘grayed out’ or starts with //, is comment and not part of the code, other than documentation for you.

There are 3 parts in the code:

  • First you have the initialization, or definition of all the variables and pin(numbers) within the code. In the example above only the Integer variable “led” is defined.
  • Second is the void setup(). In this part of the code you can configure the Arduino. pinMode(Led, OUTPUT) is sets pin 13 to be an output. This piece of code will only run once during start. After that it only reloads when a hard reset is given.
  • The last part is the main loop of the code: void loop() All the code within this loop will run until shutdown.

In the Blink example there are 4 instructions that are looped:

DigitalWrite(Led, HIGH) – this sets pin 13 (= variable Led) to HIGH (= +5V)
Delay (100) – wait for 100 mili seconds
DigitalWrite(Led, LOW) – this sets pin 13 (= variable Led) to LOW (= 0V)
Delay (100) – wait for 100 mili seconds


After the last delay it loops until shutdown. The LED will blink:-). If you start with this blink example you can check, without connecting any extra electronics, the basic communication between your board and computer.


Basic Sensor reads and Serial Write

Since most of the users want to ‘measure’ something and then ‘do’ something based upon the outcome of the measurement, the next example is a good insight in how to make this work.

Open: Files/Examples/Analog/AnalogInOutSerial

This code reads the voltage on pin A0 ( analog input 0) and converts this data to PWM on output pin 9~. At the same time it will send data to its serial ports (Tx and Rx) so other software within your computer can work with it (SuperCollider, Max/Msp, PureData, Processing, … )

Potmeter (0-5V) on the input and PWM on pin 9~ as output

In the setup above we have a potentiometer connected between the +5V dc and the GND (0V). When we turn the knob of the pot we can make a voltage change between 0V and 5V as a continues signal. The wiper of the pot is connected to analog input A0, so the ADC will generate numbers between 0 and 1024 ( = 10 bit resolution or 210)

Pin 9~ is the Pulse Width Modulation output. It is connected to a led through a resistor (limit the current!). When the output PWM signal is 100% (AnalogWrite = 255) the led will light up with maximum intensity. The lower the output value, the less light the led will produce.

Let’s take a closer look at the code.

AnalogInOutSerial Arduino Patch

This AnalogInOutSerial code is also divided in three parts. First we have the definition of the variables used in the code: analogInPin, analogOutPin, SensorValue, outputValue. All these variables are defined defined to the type Integer (only whole numbers).

The next part is the void setup() where the speed of the serial port is set. This speed has to be the same within the software the Arduino is communicating with. If you for example want to read this data into PureData (Pd), then the communication port of Pd has to be set to the same speed – otherwise both devices do not understand each-other.

Then the loop part, called void loop()
First of all the value of the sensor is read on input A0. This is a value between 0 and 1024 (10bits). After that the variable ‘outputValue’ will be given the value of the sensor (sensorValue), but then remapped or divided by 4. This is because the output resolution is 8bit (0-255).
The analogWrite instruction generated PWM on the output pin number 9. The value measured at the input has now been transferred to the PWM output.

In the last part of the loop, the values are ‘printed’ to the output with the instruction Serial.print(value). The Serial.print() instruction sends the value (tekst or data) through the USB port (Tx) to your computer. More about this subject, click here. To make sure the processor does not go too fast, a delay of 2ms is embedded.


Serial communication

This section introduces serial communication from and to the Arduino. Its use here is explained from the perspective of using Max or Pd as interfaces. An examples of how to connect to Supercollider can be found here.

jump to: led brightness
jump to: three motors

Arduino and simple Serial Communication

In order to establish communication with the Arduino, a serial protocol is used. This communication occurs when a script or program is uploaded to the Arduino, but is also possible as part of an interaction scheme, for instance when sensor values need to be visualized in a user interface. The serial communication can be explained in its most basic form as a transport line of individual characters between the Arduino and a computer. It is possible to deviate from this basic form; that will be explained later.

This section explains how to set up such simple communication between the Arduino board and the applications Max and Pd. Since these platforms are rather similar, patches for Max and Pd look somewhat similar. The Arduino can send data to Max/Pd, or it can receive data from it. In either case, data is represented by individual characters that are sent one at a time. Rather than the actual character, the transport line expects a numerical representation of that character. These representations are stored in a so called ASCII (pronounce: askey) table, which binds e.g. the letter ‘A’ to the value 65, or the character ‘7’ to the value 55. When sending data from Arduino, those ASCII representations remain obscure. All that is required is using the Serial.println command.

Serial.println("az");
int x = 17;
Serial.println(x);

The three lines above represents Arduino code that first sends the letters ‘a’ and ‘z’ over the serial port, and after that the value for x, which is 17, is sent. As said before, when sending, nothing shows that println uses ASCII representations. But at the receiving end, is will be ASCII that is received. The objects used are serial in Max and comport in Pd. The comport object is not vanilla and needs to be installed. Here is a how-to.

Max (left) and Pd (right) — connecting to a serial port

The connection to the serial port is created by providing a port reference. In Max this is a letter, and in Pd a number. With a specific message the information on available ports and their references can be printed. Arduino’s serial port is typically listed as ‘usbmodem’. The next step is to provide this identifier as argument, as well as the speed at which the communication is set up. The patches below show just this. The Max object that reads ‘poll’ is an attrui and is the easiest way to get data from serial.

Serial data sent to Max or Pd

The numbers that are printed out are in order: 97, 122, 13, 10, 49, 55, 13 and 10. After one second the exact same sequence appears. These values represent characters according to the before mentioned ASCII table. According to this table, the values 97 and 122 represent the characters ‘a’ and ‘z’, the values 49 and 55 the characters ‘1’ and ‘7’—indeed, numerical values are sent as individual characters. It is easy to see how this accords with the messages sent from the Arduino code. Twice, a combination of 13 and 10 appears. The ASCI table names these values ‘line feed’ (LF) and ‘carriage return’ (CR) respectively—terminology that suggests printer activity. These two values are inherent to the Arduino ‘println’ command and can be used in our patches as indicators that a complete message has been received.

Printing interpreted data from the serial connection

Max and Pd can transform the ascii values to the characters they represent using either the atoi or fudiparse object. Copy the code below into a Max patcher window to create the patch above.


----------begin_max5_patcher----------
609.3ocwWF0biBBDG+Y8SgCO6kAQiwzuJc5zAS3xQGEbPrM85zu6GrDS8tSq
NNLIODMrA3O+XWV17QX.pTdl0hhdH5wnffOBCB.SVCAWZGfpomOTQagtgDr2
jkufhc+jlcVClaTbgt2pnqlKpXZXDIWL1P0G9EWb5YE6f1oXQ1FbbTJAdQ1Y
elTrAG8zWyirS2OQ3KV4GAEMqhejPPVaeFFZeDuPDnZspiitttTzZllodlIn
kUrgRMJH1gCyyQy6ogaeNvSJY3qooqe1clzu2vbSCBcc.C.OaMbacVkcZsTr
Z1GgybL38.eXVA7c7.JuFgbnR1xPixd5f9ZVb.jMrqqxZ4Q12uEE69XCAGa2
hfumgIMxpp4iSvtst7LuFmjr6dRdIs63rj6RB3cvyumf2xTMRkdV1ub1w2ru
cMrOQhctVRGMud5b40I6.FyvqEtoNNu2i38Skrt885RY0Ju7BC3sM2qdvBOR
3uq1bRI6ZFkOxrNwsvEWYIyvG4ayMOZRYOxXKqxjA0bK6JiTwtaulyIlNEjk
TwIKn8uGE3cdEXEmtxP1jBrKxcstTnRuox8LDRnCnJt3eKwDVaV6+M4sxN0g
dUbmChi9Z4cj0p4Bpl6pQ3wq0.BcZzM2kJjoBAydwbJ4AgLWHu.j7gP42Jg1
dqDZA5ryC5jci3Y+BzovC5rjHNhmzgbCzANqNqCxGQBjEHz9+SGWVOZSyqLU
6kNCRXxr+hDJPrHFZxEtl4PSE6Ude+gj3HpxjAWaRe2ofkE5bdFxMTyeIRIL
kpZ6anENijvsFBSIqsMTGGvkKgeF9GvJeZp5
-----------end_max5_patcher-----------

Important to take into account is that only a single application at a time can connect with the Arduino board over the serial connection. In order to allow one application to open the connection, another must close it.

Telling apart multiple sensor values

When reading out multiple sensor values in Max or Pd, another approach than simply using println() must be adopted. In order to know which value represents the first sensor and which the second, the values are better send in such a way that they create a list. In Max/Pd a list can be specified as values separated by a space. The Arduino code shows how to create the spacing. Only after the last value has been sent, a println() is used to create a flag for the receiving end.

void setup() {
  Serial.begin(115200);
}

void loop() {
  int sensorValueOne = analogRead(A0);
  int sensorValueTwo = analogRead(A1);
  Serial.print(sensorValueOne);
  Serial.print(" ");
  Serial.print(sensorValueTwo);
  Serial.println();
  delay(10);
}

Set the brightness of an LED

The section above explains how Max or Pd receive values from the Arduino. Communication in the other directions is possible too; from Max/Pd to Arduino. The dimmer example shows how this communication can be used to adjust the brightness of an LED by sending a changing value in the range from 0 to 255. This value is used to change the setting of a PWM value. Not much coding is Max/Pd is required to achieve this, simply connect a number box to the serial/comport object. The Arduino example even includes Max code that can directly be pasted into an empty patcher window.

Sending values over serial

Serial fading an LED with potmeter

The fade example automatically fades the brightness of an LED between minimum and maximum. Closer examination reveals that although the pwm values used to fade are linearly increasing and decreasing, the change of light intensity appears not to be linear at all. If the left image below shows the linear change of pwm, the right image represents what the light intensity actually looks like; jumping rather quickly to high intensity and then slowing down while it reaches maximum value.

If linear intensity change is desired, it would be better to adjust the pwm values. Max provides a fine environment to prototype this. An audio rate oscillator provides the source of values. A potentiometer connected to A0, can provide a value for the speed of this oscillator. The patch below is an example of how to connect everything together. By raising the oscillator value to the power of three, we achieve a change of brightness that appears to linear.

A Max patch for adjusting speed of brightness change
----------begin_max5_patcher----------
893.3ocwX00bhCBE8Y8WASl8g1csNAxmtOs+OZ6zAUToSRfgfs11o829RfjV
6VbCpn8EQthb3buWtbfWFNHXJaCoN.7av0fACdY3fAZSMFFz1ePPIdyrBbsd
XAUjGYSuOXj4mjjMRs4YqvUKIcloy0FUC7pnjNiUqKoUEDoddfeXjsV1YMp0
JGKmshVs7NAYlzr5fg4iCGARP5l3vlOgpuCts8+XlF4Sbh4ODDLBDPqjcMfa
aF2qCG17wniisjMbAPMoWfRR9Im83E+XA7laFEc4uBGmboEu.Zxd3Ef86EBi
07OB5favmDutByqWwjuARrwxbqrDcfrLNWGkSlzOIWTvv9MDKTXP3pAABswz
r8fondYZTTplootkU6UhJET0V2Bxa.UtK3OEL6DNwug1XcBbdV+DtltrBW3U
JyWgqYh2rQyX+RSTno4aglkR1BabD5oZQlXXTttAkclKE8bIlCBUdZTD3pzP
vVwtsHKzdg2jCkro5.5jjSEYmSUIAVnw6UV4XAtjHIh6HU3oEZzBa+sZ5y59
JeRyp0iG3fx25X2lOOIkhahsSWKkrpupunfUaSdAJzEGiUePybqPROSbx6PV
xlSNHEJ4sYHlitzdsvdqjeLhSvRoXM0V1R1A6TrmXzfjoxIqnH3+jsXp201f
RiOUaS1M0SOUTeJd879o9jzuMlmbpXdMQvYBY+jOCchI+NNJfJYXKdD6k9iN
zRfeT7qOx46qarPvJqepbJy1QC4d8lEsAOmTh50SyKFuTI4laqDuWkZiflBz
vuAo10jB0xPcsMKrLaORV6+ZxPyUmhcHLNUo9ugocsdlwhcHnYOxZ6OnBM4q
QNt27KrTO7fBZ0+9VHZHar+YpWyVKl0MicuxA3CTmSpkzJrjZzWb86bdqwTR
myYpUSKhPX13D0FujsRO+TGHxTV0LNcucDobcQ27nD8tn6X1wgTtCH0sbNNj
bIPzsbNNjxbAoXegDrujKe38fNEmx7ARtj6gf9v6E6BRdIKGdtxHbILA8RRt
C.4kssgtvHej30LGn9hQdBmvy.NtrOJ2WQHnamvcbUFxb+nziCnzyEPImKfb
.mutGxH9Ay4OPD0sCVCgRg28L8U.yGo6RqLc0udVff7.sa7ZEoAXgRelTINa
sPurB1jZdSN8ipHpT2asQj2vFxofTqdrRcU0ZN1vCsHyguN7uveNS3B
-----------end_max5_patcher-----------

Adjust the speed of three motors

Adjusting the brightness of an LED, as explained above, can be turned into adjusting the speed of a motor. But in order to extend this model to multiple motors, another approach needs to be taken. What we need to solve is how to connect multiple number boxes to equally as many PWM driven outputs.

The solution lies in creating a separate function for dealing with incoming serial data with serialEvent(). The Serial Event example demonstrates the use of this function. A Max or Pd patch now sends various values separated by spaces, using an ascii representation. In this representation the space and return values function as flags that trigger the pushing of values into an array and updating the values to be written to the outputs.

int motorPins[] = {9, 10, 11}; // pwm pins
int motorCount = 3;
byte motorSpeeds[3]; // reserve space for three bytes
int motorIndex = 0;
String inputString = "";
bool dataComplete = false;

void setup() {
  Serial.begin(115200);
  // declare all pins as outputs:
  for (int i=0; i<motorCount; i+=1) {
    pinMode(motorPins[i], OUTPUT);
  }
  inputString.reserve(3);
}

void loop() {
  if (dataComplete) {
    for (int i=0; i<motorCount; i+=1) {
      analogWrite(motorPins[i], motorSpeeds[i]);
    }
    dataComplete = false;
  }
}

void serialEvent() {
  while (Serial.available()) {
    char inChar = Serial.read();
    switch (inChar) {
      case 32: // space
        motorSpeeds[motorIndex] = inputString.toInt();
        motorIndex += 1; // increase index
        inputString = ""; // reset string
        break;
      case 13: // new line
        motorSpeeds[motorIndex] = inputString.toInt();
        dataComplete = true;
        motorIndex = 0; // reset index
        inputString = ""; // reset string
        break;
      default:
        inputString += inChar; // add character to string
    }
  }
}

The Pd patch below works with the above code. However, the fudiformat object generates additional data to the extent that a list selector is included in the ascii values. Although the ‘list trim’ object promises to strip off this selector, that appears not to work. In order to solve this issue, an object ‘list split 5’ is added.

Three values sent to the Arduino

Useful Links

Using Timers
Multitasking
Debounced Encoder

Arduino/Teensy

Some board layouts: