Arduino · Home Automation · MIDI

MIDI Control of servo motors

Description

Following on from the MIDI post, the project I am working on has a need for 3 Servo Motors to be controlled in much the same way as the lights. The final project will include lights and servos all controlled using MIDI.

The project is a ‘kinetic photo’ (remember where you saw that term first 🙂 ), though the techniques could be applied to displays for museums, stage productions, and art projects requiring synchronised operation but with something different to another computer based display.

Construction

This isn’t really a DIY post, but I’ll include the main components I used

What you’ll need:

– Arduino Uno or equivalent
– MIDI shield or equivalent
– Arduino to Servo interface, could be an off the shelf one, I made my own, see this post : https://myiot97.wordpress.com/2018/01/12/build-a-low-cost-3-way-arduino-servo-interface-with-external-power/
– 6V 2A Power supply recommended, if you are using a single small servo, it may work from the Arduino board
– Servo motors, with my interface, up to 3. If you extend the interface, or have multiple ones you could drive up to 10.

How it works

The MIDI interface code is the same as for the RGB light, but to save linking to that post, I’ll quote:

About MIDI

MIDI is short for “Musical Instrument Digital Interface”, it’s a simple control standard for musical instruments that was developed in the 1980s, but has become a very widely used standard for synchronisation and control of electronic musical instruments, effects unit and other equipment, for example scenery or effects queues on stage.

I’m not going to go into the full details as this project only uses a subset of MIDI’s capabilities, but I will briefly describe the elements relevant to this project. The standard defines three aspects, the physical interface, the data communication standard, and the data format.

The physical interface is an optically isolated current loop connected using 5 pin DIN connections, each connector is uni-directional (ie can only send or receive, but not both), with most devices having an “input” connector, and an “output” connector. Some devices also have a “through” connector which passes the data on the input connector to the next device, thus allowing devices to be cascaded. In the audio world, the optical isolation helps avoid earth loop problems, it also helps prevent accidentally frying equipment as you plug it in and unplugging it.

The data communication standard is asynchronous, 31250 bps, 8 bits, no parity, 1 stop, which, may seem like an odd bit rate, the historical reason is it is simple to generate with a 1MHz processor clock which was common when MIDI was developed, the Arduino’s inbuilt USART does it with ease.

The data format consists of commands and data, distinguishable by the MSB of bytes sent over the link, so:

Byte            Type
0x00-0x7F Data
0x80-0xFF Command

Commands can be followed by one or two data bytes.

Between 0x80 and 0xEF, the low order Hex character is called the MIDI Channel, and is typically used to select the device that the command is directed at, so the MIDI standard permits up to 16 devices to be addressed, though more devices may be present if they share the same Channel number, but that will affect how they interact. For the purpose of this post, I will be referring to commands as 0x0n to 0xEn, where n is the Channel.

Commands numbered 0xF0 to 0xFF do not have a MIDI channel, and therefore apply to all devices, although how each device interprets them may be different, so that is getting into the murky, dirty secret of MIDI, and that’s the last I will mention it.

For this project, there are only two commands of interest, called “Note On” and “Note Off”, each of which is followed by two data bytes, Note and Velocity.

Note is fairly self-explanatory, it refers to the note on the keyboard.

Velocity is the speed or force that the key was pressed or released, for musical instruments it is used to provide expression, how loud, or in the case of piano, also how harsh the note plays. For control systems, eg a light, it can determine the brightness or other parameters depending on the application.

Action     Command    Note           Velocity
Note on         0x90        0x00-0x7F 0x00-0x7F
Note off         0x80        0x00-0x7F 0x00-0x7F

For full details, please refer to https://en.wikipedia.org/wiki/MIDI.

What this project does

This project allows one of ten servo motors to be controlled by MIDI. Each motor is assigned a different note, though chords allow combinations of the motors. The velocity of each note determines the angle that the servo moves to from 0 to 180

If that seems a bit hard to get your head around, I have produced a video to demonstrate it:

Connecting it up

The MIDI shield I used does not pass-through the connections from the Arduino base board, instead it routes them to a set of headers. If yours does the same, you will need to work out which pins to use to connect to the servo.

The MID shield shares the serial port used for programming the Arduino, in order to prevent conflicts, it should have an on-off switch, or a header. When programming the Arduino, this will need to be in the off position. When using the MIDI interface, it will need to be on.

About the code

The MIDI portion of the program is the same as for the RGB LED, but the motor control changes.

I started by trying to use the pulse width modulation outputs as for the tri-colour LED. The low torque servos worked reasonably well, but the high torque one went a bit crazy.

I switched to using the Arduino Servo Library (See https://www.arduino.cc/en/Reference/Servo)

As a bonus, the servo library can make any digital pin drive a servo, not just the PWM pins, with the MIDI interface, that means it could control up to 10 servos, as two pins are used by the MIDI interface. Of course you can still use the PWM pins to control LEDs, with the other digital pins controlling servo motors. But a pin can’ be used for both servo and the inbuilt PWM at the same time.

The code

/*
* MIDI Servo core code.
*/

#include <Servo.h>

// MIDI Command codes, note, the low order 4 bits are 0
#define MIDI_Note_Off 0x80
#define MIDI_Note_On 0x90

// MIDI in read actions
#define WAIT 1 // Waiting for a valid MIDI command.
#define Note_Off 2 // MIDI_Note_Off was received.
#define Note_On 3 // MIDI_Note_On was received.

// Output pins
#define Servo1 9
#define Servo2 10
#define Servo3 11

Servo myservo1; // create servo object to control a servo
Servo myservo2; // create servo object to control a servo
Servo myservo3; // create servo object to control a servo

int pos = 0; // variable to store the servo position

//
// MIDI Reception variables
byte IncomingByte; // Byte from serial port
byte MIDI_Command; // undecoded MIDI command (0xn0, where n=0x8 to 0xF)
byte MIDI_Channel; // MIDI Channel (0x00 to 0x0F)

int action = WAIT; // Decoded MIDI Command
byte note = 0x80; // Initialised to invalid note.
byte velocity = 0; //

void setup() {
// Configure the serial port for MIDI, which is 31250 bps, 8 bits, no parity, 1 stop.
Serial.begin(31250);

// Configure the output pins
myservo1.attach(Servo1); // attaches the servo on pin 9 to the servo object
myservo2.attach(Servo2); // attaches the servo on pin 9 to the servo object
myservo3.attach(Servo3); // attaches the servo on pin 9 to the servo object

// Initial servo test, full rotation test for each servo
for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo1.write(pos); // tell servo to go to position in variable ‘pos’
delay(15); // waits 15ms for the servo to reach the position
}
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
myservo1.write(pos); // tell servo to go to position in variable ‘pos’
delay(15); // waits 15ms for the servo to reach the position
}

for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo2.write(pos); // tell servo to go to position in variable ‘pos’
delay(15); // waits 15ms for the servo to reach the position
}
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
myservo2.write(pos); // tell servo to go to position in variable ‘pos’
delay(15); // waits 15ms for the servo to reach the position
}

for (pos = 0; pos <= 180; pos += 1) { // goes from 0 degrees to 180 degrees
// in steps of 1 degree
myservo3.write(pos); // tell servo to go to position in variable ‘pos’
delay(15); // waits 15ms for the servo to reach the position
}
for (pos = 180; pos >= 0; pos -= 1) { // goes from 180 degrees to 0 degrees
myservo3.write(pos); // tell servo to go to position in variable ‘pos’
delay(15); // waits 15ms for the servo to reach the position
}
myservo1.write(90);
myservo2.write(90);
myservo3.write(90);
}

void loop() {
if (Serial.available() > 0) {
// read the incoming byte:
IncomingByte = Serial.read();

MIDI_Command = IncomingByte & 0xF0;
MIDI_Channel = IncomingByte & 0x0F;

// Was it a MIDI command (bit 7 = 1)?
if (bitRead(MIDI_Command, 7) == 1) {
// If so, need to save the decoded action & reset note and velocity
switch (MIDI_Command){
case MIDI_Note_On:
action = Note_On;
break;
case MIDI_Note_Off:
action = Note_Off;
break;
}
note = 0x80;
velocity = 0;
}
else {
// Process data byte
if (note == 0x80 && action != WAIT) // note on, wait for note value
{
note = IncomingByte;
}
else if (note != 0x80 && action != WAIT) // velocity
{
velocity = IncomingByte;
// All elements of the command have been received, now process it.
if (action == Note_On) {
Set_Servo(MIDI_Channel, note, velocity);
}
else if (action == Note_Off) {
Reset_Servo(MIDI_Channel, note);
}
note = 0x80;
velocity = 0;
action = WAIT;
}
}
}
}

 
void Set_Servo(byte MIDI_Channel, byte Note, byte Velocity) {
// This function is the one you will most likely need to change to adapt this project to different applications.
//
// As this is test code, I have avoided making it too fancy, so Bit 0 drives servo1, Bit 1 drives servo2 and Bit 2 drives servo3.
// The Velocity value determines the value.
// As the approach is bitwise, a single key may set more than one of the servos
//
pos = map(Velocity, 1, 127, 0, 179);
if((Note & 1)!=0){
myservo1.write(pos);
}
if((Note & 2)!=0){
myservo2.write(pos);
}
if((Note & 4)!=0){
myservo3.write(pos);
}
}

 

void Reset_Servo(byte MIDI_Channel, byte Note) {
// This function is one you will most likely need to change to adapt this project to different applications.
//
// When the midi key is released, this function is called and may be used to reset the servo to it’s home.
//
pos = 89; //By default, home is the servo’s 90degree mark.
if((Note & 1)!=0){
myservo1.write(pos);
}
if((Note & 2)!=0){
myservo2.write(pos);
}
if((Note & 4)!=0){
myservo3.write(pos);
}
}

 

Arduino · Internet of Things

Build a low cost 3-way Arduino servo interface with external power

Description

This board provides a low cost and simple way to interface servo motors to Arduino or other micro-controllers.

As shown it interfaces to 3 servo motors, but you may choose to extend it to as many as your power supply will permit.

It is designed to allow an external supply, like a bench supply, to power the motors independant of the logic supply, which allows for use of higher power servo motors.

Construction

What you’ll need:

Parts:
– single-row pin header, at least 13 pins
– 0.01µF Ceramic capacitor
– 100µF 16v Electrolytic capacitor
– Strip-board 9×17 (ie 9 strips by 17), plus whatever you need for mounting, suggest at least 16×17.
– 2 way board mounted screw terminals, eg ( https://www.jaycar.com.au/2-way-pcb-mount-screw-terminals-5mm-pitch/p/HM3172 )
– Single strand wire for inter-strip links

Tools:
– Soldering iron
– Solder
– Something to cut strips on the stripboard, I usually use a drill bit by hand.
– 1mm drill bit & drill

Construction

The layout is:

Servo Board Layout

– Before inserting the components, I suggest marking up the board as follows:

Servo Board Prep

– Then cut board along the line shown, and the strip at the three holes shown, I use a drill bit slightly wider than the strip, about a turn with a hand drill is plenty.
– Insert the wire links & solder
– Cut the header into three sections of 3 pins, and one of 4 pins, insert and solder them where shown.
– Insert & solder the board mounted screw terminals, you may first need to enlarge the holes in the board with the 1mm drill bit.
– Insert & solder the capacitors

The finished product shouls look like

Servo board Final

Use of the board

The connections to the Ardunio are along the edge of the board. Note that the pin marked “logic ground” must be connected to the GND on the Arduino, s1 to s3 are then connected to the desired PWM outputs on the Arduino.

If only low power servos are to be used, the Positive (+) connection on the PWR header may be connected to the +5v connection on the Arduino. The design assumes it will use an external supply should be used. I reviewed a suitable one here:

Home Automation · Host

A sneak peek

It’s at an early development phase, but I have been thinking about how to present information from an IOT system, and here is a sneak peek of the code I have come up with for the MyIOT web site. I thought it too good not to share. I have the image manipulation code complete, how to link it to the sensors is still at the advanced design phase.

Teaser

 

Host · Internet of Things

It’s alive!

Introduction

In my last post (https://myiot97.wordpress.com/2017/06/21/the-host-side-why/) I explained that my intention was to create a host that my IOT creations can communicate via. The advantage of this is that the devices can be accessed from remote sites without having to mess around with ISP incoming connection settings, dynamic DNS or any of that stuff (if you don’t know what I’m talking about, it doesn’t matter because that’s what the MyIOT host is for).

The good news is that the MyIOT host site is alive.

The better news is I am happy for others to use it for legal,  non-commercial, non-life critical, user accepts all responsibility for losses/damages purposes, so I’m going to describe how to register with and use the site in this post. The reason for the condition is that the site is a development environment, and will evolve, though what I document will mostly stay the same.

Site operation

The site is designed with efficient device programming in mind, so the user interface while clunky to a human should be easy for a device to interface with.

The device issues commands to the site using http get operations, on a web browser, this would look like the following:

MyIOT/index.php?cmd=get&id=12

In this case,  it gets the setting for device ID 12, and the result looks like:

GetResult

Result of get operation

In most cases, the device will just have to parse the data line by line looking for the value= line and using that value.

There is a corresponding command, set that sets the value, which looks like:

MyIOT/index.php?cmd=set&id=12&value=23

Before you can use the site, you need to create a loginid, and before creating and using device ids you need to login, to learn how to do that, read on…

Before that though, the site will evolve, keep an eye on this blog for information as that happens. One of the first changes on the way will be an easier way to see device status  in a web browser, anyway, back to the basics.

Creating a loginid

A login ID is associated with a valid email address. A quick privacy note – the email address is stored for security only, It won’t be used for spam purposes or provided to third-parties

To create a loginid, modify the following URL to include your email address replacing <email> and open it in a browser:

http://rowanfamily.org/MyIOT?cmd=register&email=<email&gt;

The response will be:

RegisterResult

The email will include a randomly generated loginid, and a link you need to click on to activate the loginid. The loginid may then be used by devices to access the site.

ActivationEmail

Click on the link to activate your account.

Logging in

In order to access your device information, you must first login using the connect command, which has the format:

http://rowanfamily.org/MyIOT?cmd=connect&loginid=<id&gt;

replacing  <id> with the loginid provided in the email. The response will be:

ConnectResult

You can now create and access devices

Creating a device

Devices have numeric ids that you chose from -2147483648 to 2147483647, I don’t recommend using 0 though.

In order to create a device id, you need to be logged in. The device id only needs to be created once.

The command to create a device id is:

http://rowanfamily.org/MyIOT?cmd=create&id=<n&gt;

Replacing <n> with the device id that you choose.

Setting a value for a device

Before this will work, you need created the device id. This command can be used if you are logged in, or you can use it without being logged in by specifying the loginid=<n> parameter.

The command format is

http://rowanfamily.org/MyIOT?cmd=set&id=<n>%value=<value>%5B&loginid=<l>%5D

Replacing <n> with the device id that you choose, and <value> with a number from -2147483648 to 2147483647.

Getting the value of a device

Before this will work, you need created the device id. This command can be used if you are logged in, or you can use it without being logged in by specifying the loginid=<n> parameter.

The command format is

http://rowanfamily.org/MyIOT?cmd=get&id=<n>%5B&loginid=<l>%5D

Replacing <n> with the device id that you choose.

Incrementing a value for a device

This option is intended for devices that have only one event to report, like a movement sensor, it is known as a woof, referring to an alarm event.

Before this will work, you need created the device id. This command can be used if you are logged in, or you can use it without being logged in by specifying the loginid=<n> parameter.

The command format is:

http://rowanfamily.org/MyIOT?cmd=woof&id=<n>%5B&loginid=<l>%5D

 

If you lose your loginid

If you lose the loginid, just attempt to re-register the same email address, and you will get the response:

Resend

Click on the link, and the activation email will be re-sent with the details. You do not need to  re-activate if you previously activated your account.

AMP · Home Automation · Host · Internet of Things

The Host Side – Why?

I have been a bit occupied on the professional front, so haven’t had a chance to blog for a while.

IoT devices need some way of establishing communication with each other, one way would be to configure them with each other’s IP address details, and that certainly would make for an efficient implementation, but is a bit complicated to configure especially for consumer devices, I have been thinking instead of some form of host as the better option, the host may be in a data center, or it may be a local device on the same network.

Apart from ease of configuration, I see this approach having the advantage that devices that need to minimise power consumption can periodically poll/update the host, and then power-down until the next time the poll/update needs to occur. In other terms, they can operate asynchronously. The down-side is that response times will depend on the poll/update period. To illustrate, lets say we have two devices (nodes), one is connected to a gate closure sensor, the other turns on a light to indicate when the gate is closed. Lets say the sensor updates the host every minute, and the light unit polls every 23 seconds (I have deliberately chosen times that aren’t divisible to illustrate that the operation is asynchronous), the sequence might look like:

Time (sec)
0 Gate check, open, no change
0 Lamp poll, open, lamp off
23 Lamp poll, open, lamp off
46 Lamp poll, open, lamp off
60 Gate check, open, no change
69 Lamp poll, open, lamp off
92 Lamp poll, open, lamp off
115 Lamp poll, open, lamp off
120 Gate check, closed, update host(Gate Closed)
138 Lamp poll, closed, lamp on
161 Lamp poll, closed, lamp on
180 Gate check, closed, no change
184 Lamp poll, closed, lamp on
207 Lamp poll, closed, lamp on
230 Lamp poll, closed, lamp on
240 Gate check, closed, no change
253 Lamp poll, closed, lamp on
276 Lamp poll, closed, lamp on
299 Lamp poll, closed, lamp on
300 Gate check, open, update host(Gate Opened)
322 Lamp poll, open, lamp off
345 Lamp poll, open, lamp off
360 Gate check, open, no change

Operating this way means that at both the gate sensor side, and the lamp side the controller can power down to save power, the host, however needs to be available whenever a node needs to connect, but it may be shared by many nodes.

In practice some form of heart-beat should be included to indicate that there is ongoing connectivity between the nodes and the host, this may be achieved by the gate sensor updating the host periodically even when the gate hasn’t been opened or closed, and showing a fault indicator (eg flashing) on the lamp if the gate misses 2 or more updates.

An alternative to polling would be for the host to send a notify message to the lamp unit whenever the gate unit sends an update. This would improve the response time, but would require that the lamp unit be on and able to receive the notification. A further refinement is that the gate unit could check the gate much more frequently but only establish communication with the host when the gate is opened/closed, or when the heartbeat is required. Both these refinements reduce the latency between the event (eg gate closing) and the action (light coming on), but at a cost that will affect the solution design.

In the next post, I will start to introduce my home-grown host, there are existing websites that provide a host capability, but have decided to roll my own, partly because I can then design it the way I want, but mostly because it’s a good learning experience. My plan is to do it using an AMP (Apache, MySQL, PHP) stack (see Wikipedia.org for more information about what this is.

Internet of Things

ESP8266 Success!

A friend lent me an ESP8266 module to experiment with. The ESP8266 is a very cheap serial-WiFi interface with a surprising amount of processing power on-board. Originally intended as a WiFi communication subsystem to be interfaced to a different processor running the application, what makes it really interesting is that it can now be programmed as a stand-alone processor with WiFi using the Arduino IDE.

Programming the ESP8266 means first connecting it to the IDE, and that was the objective for this post, the resulting breadboard looks like:

Test Setup

From left to right, the breadboard contains:

ESP-8266 module (ES-12E on a breadboard carrier)

FTD-1232 USB-serial module (self powered from laptop’s USB port)

MB-102 power supply module (Powered by batter, not shown, this board powers the ESP-8266, as the FTD-1232 cannot provide sufficient power to run the ESP-8266 reliably.

They are wired with shared 0v connection, FTD-1232 Tx to ESP-8266 Rx, FTD-1232 Rx to ESP-8266 Tx

Firing up the ESP-8266, connecting the FTD-1232 to the PC and loading the Arduino IDE serial monitor. The red LED on the FTD-1232 was lit, as shown in the photo, as was the green LED on the power supply. When power was initially applied, there was also a blue LED on the ESP-8266 that flashed a couple of times and then stayed off. This indicates that the WiFi module was initializing ok.

In the serial monitor, entering the command “AT<CR>”, gave the response “Ok” indicating that everything was talking, time for some commands to see if the module could see my network:

1

The commands are:

“AT+GMR” – gets release information

“AT+CWMODE?” – shows the mode, my reference says that it needs to be 1 (Station mode), 2 is Access point mode.

“AT+CWMODE=1” – sets the mode to Station

“AT+CWLAP” – list the access points that the module can see, as well as the signal strengths, and WiFi channels.

So I tried connecting to an Access point:

2

AT+CWJAP=”NETGEAR64″,”<password>” – connect to the nominated access point

AT+CWJAP? Shows the connected AP, the last number appears to show the signal strength as I moved the module.

For this test, I had to use the default baud rate of 115 200, some modules have alternate rates of 57 600 and 9 600, there is a firmware update that I shall apply that sets the default to 9 600, but I needed this initial test to work before I can do that.

There is a great list of the AT commands at This link : https://room-15.github.io/blog/2015/03/26/esp8266-at-command-reference/