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

Actuators_2021

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 / Beagle /RaspBerry / is huge and can be very complex if you are a beginner or even an advanced user. This SAM-course of 8 (maybe 7 this year) 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, 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 7 days in total, starting at 10:00 and ending at 16:00. We will start on Monday March 27th and end the course on Thursday April 6th . On Wednesdays there will be no lessons.


SAM course (22/23): March 27 2023 – April 6 2023


Day one ... blog ... content will come ...











	

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.

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.

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.

Useful Links

Using Timers
Multitasking

Arduino/Teensy

Some board layouts:

Sensors

Generic overview

Sensors exist in a lot of different shapes and types. They are all specially made to measure that specific ‘variable’ which they are designed for. A sensors ‘senses’ or measures a physical quantity (e.a. temperature, light, pressure etc) and converts this to electrical signals (resistance, voltage or current). A sensor interface like Arduino, Teensy or IpsonCompact, convert incoming voltage-change into a stream of digital numbers (midi or OpenSoundControl).

So if a sensor only has change of resistance, this has to be converted to voltage change. Or when a sensor generated a tiny little voltage change ( 100mV-200mV) than we have to amplify.

Actuators are the ‘opposite’ of a sensor. By generating “driving voltage” with a computer (sensor interface) external processes can be driven (e.a. dc motor) with an actuator.

Sensors_2021


Switches (digital input)

Switches provide a digital input (only 0V or 5V and nothing in between) and can be hooked up to the interface like the configurations shown below. The active low configuration on the left (the switch makes a connection to the ground if it is pushed – the figure on the left), is the preferred method for connecting switches. If you are using a normally open (N.O.) push-button switch, when the switch is pressed, it will send a low level (0V) to the terminal (thus the term “active low”).
On the right side the active-high’ configuration. At the moment the switch is pushed (makes contact), the signal to the input of the interface is pulled up. In other words it changes from 0V to 5V.


Potentiometers

A potentiometer (or “pot”) can be used to provide an analogue input (= continues changing voltage values) to an input terminal. Using the configuration below, a pot will vary the input voltage to the terminal from 0 – 5V. In other words, the full input range of the terminal. 10k is a typical value for use in this configuration, but anything from 1k to 1M should work fine.
On the right side of the figure below the equivalent circuit of a potentiometer is shown. In fact the potentiometer is the same as a voltage-divider circuit Rx and Ry, where the value of the both resistors depend of the position of the pot.


Resistive sensors

Resistive sensors, such as photo-resistors, force sensing resistors (FSR’s) or flex sensors, can be wired in either configuration shown below. Using the left configuration (active low), the terminal voltage will decrease with decreasing resistance. Using the right configuration, the terminal voltage will decrease with increasing sensor resistance. Use whichever configuration is most convenient for your application.

You will also need to select an appropriate value for the fixed resistor R based on the resistance range of your sensor. In general, it is best to select a value for R that gives the largest voltage range for the sensor. The optimal value is R = sqrt(Rmin * Rmax); that is, the square root of the sensor’s minimum resistance times the sensor’s maximum resistance. Once you compute the optimal value, select a standard resistance value that is closest to it. This will give the maximum voltage range for your sensor and thus the best resolution. Use the input min. and max. adjustments for the terminal to compensate for voltage offsets, as described above in the section Analogue input mode details

Passive Sensor Examples