Alex LeitchCelia Chen
Published © CC BY-NC-ND

Strain

An emotive interactive sculpture that uses a Myo armband to control pneumatic actuators via the Programmable Air

ExpertShowcase (no instructions)8 hours376
Strain

Things used in this project

Hardware components

Myo Gesture Control Armband
Myo Gesture Control Armband
×1
Raspberry Pi 3 Model B+
Raspberry Pi 3 Model B+
×1
Programmable-Air
Tinkrmind Programmable-Air
×1
Skyn Original Condoms
×1
Bamboo Skewers 6 inch
×15
Silicone Tubing, Food Grade 1/8ID x 3/16OD
×1
Bamboo Stir Sticks - Generic Square End
×25
Heavy thread or common twine
×1
Medium Density Fiberboard
×1
6-32 Threaded Insert, Brass, Barbed
×6
Stainless Steel Socket Head Screws 6-32 1/4"
×6
Straight male luer lock Cole-Parmer EW-12028-51
×4
Female Luer Lock to 1/8 Hose Barb
×4
PLA Filament
×1

Software apps and online services

Arduino IDE
Arduino IDE
Raspbian
Raspberry Pi Raspbian
PuTTy
Used to run the Raspberry Pi headless
Fusion
Autodesk Fusion
Adobe Illustrator

Hand tools and fabrication machines

Prusa MK3S
VLS 6.60 Laser Cutter
Stepped Drill Bit

Story

Read more

Custom parts and enclosures

Enclosure - BreadBox

This is the bread box for the model. It requires some hand-drilling to correctly mount the pneumatic lines, and this is best done by hand for any given sculpture you wish to make - it's an aesthetic component!

A 3/16 hole will work well for this part, as you'll need 3 holes per actuator - one for the pipe and two for the threaded insert screw mounts.

This was generated at https://www.festi.info/boxes.py/ , using their "bread box" generator

3D Printed Clips and Spine Parts

This Fusion 360 archive contains all of the 3D printed parts needed to assemble an actuator. You'll need multiple prints of "Wishbone" and "Shackle" to assemble the spine chains.

Schematics

Strain Schematic

This schematic shows the input, control, and output components of Strain, our interactive sculpture system. The input is a Myo armband, worn on the arm, which detects hand/arm gestures through EMG sensors. These gestures are interpreted by a Raspberry Pi 3B+ running at 5V. Based on the gesture detected, the Raspberry Pi sends control signals to an Arduino Nano v3, which operates at 12V to provide sufficient power for the outputs. The Arduino controls a Programmable Air unit, which uses pneumatic actuators to create mechanical motion and interactivity with the sculpture. By detecting gestures with the Myo armband, this system allows the user to manipulate the sculpture by inflating and deflating the sculpture.

Code

Programmable Air Code

C/C++
This code requires an Arduino Nano V.3 to work correctly.

== USE ==
Upload this file to the Nano running the pneumatic system.

=== Information ===
The first state in this code block is probably the most important. It maintains peristalsis in the system, keeping it pulsing whenever the robot falls below a certain pressure difference from basic atmospheric pressure.

After that, it has a series of flags that are set and checked each loop. These flags can then be set to fire off either an inflation or deflation cycle.

Within the inflation cycle is a pressure differential limit to prevent overinflation.

Note: The programmable_air.h library was modified to communicate over 9600 baud in order to work with the Myo armband.
#include <programmable_air.h>

#define atmospheric_pressure 508;
#define targetPressure 2;

#define WAVE_IN "WAVE_IN"  // 7 char
#define REST "REST"
#define FIST "FIST"
#define WAVE_OUT "WAVE_OUT"
#define FINGERS_SPREAD "FINGERS"  // 7 char
#define THUMB_TO_PINKY "THUMB"

int upper_threshold = 10;
int lower_threshold = -10;

int pressureSetupInterval = 1500;

int pressurePollMillis = 0;
int pressurePollInterval = 50;

int serialPollMillis = 0;
int serialPollInterval = 75;

int inflatePollMillis = 0;
int inflatePollInterval = 200;

int currentMillis = 0;

bool deflateFlag = 0;
bool inflateFlag = 0;

bool buttonActiveFlag = 0;

String pose = "none";

void setup() {
  Serial.begin(9600);
  initializePins();
  unsigned long setupMillis = millis();

  // for an interval, check a pressure sensor
  // if it exceeds the necessary pressure
  // turn off

  // RED BUTTON ALSO
  switchOnPump(2, 100);
  blow();

  while (setupMillis < pressureSetupInterval) {  // Record max sensor value
    // switch on pumps to 50% power
    int pressure = readPressure();
    int pressureDiff = pressure - atmospheric_pressure;

    // targetPressure is a magic pressure number for internal boof
    if (pressureDiff > 2) {
      switchOffPumps();
      setupMillis = pressureSetupInterval;
    } else {
      setupMillis = millis();
    }
  }
}

void loop() {
  currentMillis = millis();

  // // ==========
  // /*  STATE 1: Peristalsis */
  // // every loop we have to check the basic pressure status
  // // the pressure should never really be below -1 or -2 or things get Floppy
  bool periTimeCheck = currentMillis - pressurePollMillis >= pressurePollInterval;
  bool pumpsOnFlag = inflateFlag || deflateFlag;

  if (periTimeCheck) {
    int pressure = readPressure();
    int pressureDiff = pressure - atmospheric_pressure;
    Serial.println(pressureDiff);
    if (pressureDiff < -4 && !pumpsOnFlag) {
      // RED BUTTON ALSO
      switchOnPump(2, 100);
      blow();
    }

    else if (pressureDiff > 1 && !pumpsOnFlag) {
      // BLUE BUTTON
      switchOnPump(1, 100);
      suck();
    }
    // no shutdown here

    pressurePollMillis += pressurePollInterval;
  }

  // ==========
  /*  STATE 2: Myo */
  bool serialTimeCheck = currentMillis - serialPollMillis >= serialPollInterval;
  if (Serial.available()) {
    String data = Serial.readString();  // get incoming poses
    pose = data.substring(0, 4);
  }

  // ==========
  // STATE 3: Check Buttons

  // These override myo commands by setting the pump flags
  // But not CHECKING the pump flags?

  bool inflateTimeCheck = currentMillis - inflatePollMillis >= inflatePollInterval;
  if (inflateTimeCheck) {
    int pressure = readPressure();
    int pressureDiff = pressure - atmospheric_pressure;
    
    if (readBtn(BLUE) || pose == "FING") {
      // if the BLUE button is pressed suck air out of the output, else, vent to atmosphere
      deflate_blue();
    } else if (readBtn(RED) || pose == "FIST") {
      // if the RED button is pressed blow air into the output, else, vent to atmosphere
      Serial.println(pressureDiff);
      if (pressureDiff < 3) { // prevent overinflation
        Serial.print("pressureRed ");
        Serial.println(pressureDiff);
        inflate_red();
      } else {
        shutDownPumps();
      }
    } else {
      // turn things off and up the interval
      shutDownPumps();
      inflatePollMillis += inflatePollInterval;
    }
  }
}
// pseudocode
// on setup, inflate until pressure sensor detects a certain core pressure
// pause inflation

// every tick
// check to see if pressure is steady - if not, inflate slightly

// for on fist control, pressurize more
// on release, relax flower back

// on no value, return to pre-set pressure

// FUNCTION LIST
void deflate_blue() {
  // switch on Pump 1 (suck) to 100% duty cycle
  deflateFlag = 1;
  inflateFlag = 0;
  switchOnPump(1, 100);
  suck();
}

void inflate_red() {
  // switch on Pump 2 (blow) to 100% duty cycle
  deflateFlag = 0;
  inflateFlag = 1;
  switchOnPump(2, 100);
  blow();
}

void shutDownPumps() {
  deflateFlag = 0;
  inflateFlag = 0;
  switchOffPumps();
}

Myo Serial code

Python
This code requires a Raspberry Pi 3B+, Arduino Nano V.3, and a Myo armband which must be updated to at least firmware v1.0 in order to work correctly.

== USE ==
Upload this file to the Raspberry Pi synced to the Myo armband and connected to the Arduino Nano.

=== Information ===
This code opens a serial connection between the Arduino in Myo armband gestures and sending them over serial to the Arduino that controls the Programmable Air.

Note: This code imports libraries from the RaspberryPy respository (GitHub linked below)
import sys
sys.path.append("/home/clichen/Projects/RaspberryPy")

import time
import serial
from raspberrypy.control.myo import Myo, Pose

arduino_port = "/dev/ttyUSB0"
arduino_baud_rate = 9600

#Open the serial connection to the Arduino
ser = serial.Serial(arduino_port, arduino_baud_rate, timeout=1)

def send_command(command):
	#Send the command to the Arduino
	ser.write(command.encode())
	#Wait so the command is processed
	time.sleep(0.1)

def on_pose(pose):
	print ("Detected pose:", pose)

	if pose == Pose.REST:
		send_command("REST")
	elif pose == Pose.FIST:
		send_command("FIST")
	elif pose == Pose.FINGERS_SPREAD:
		send_command("FINGERS_SPREAD")
	elif pose == Pose.WAVE_IN:
		send_command("WAVE_IN")
	elif pose == Pose.WAVE_OUT:
		send_command("WAVE_OUT")
	elif pose == Pose.THUMB_TO_PINKY:
		send_command("THUMB_TO_PINKY")

if __name__ == '__main__':
	myo = Myo()
	myo.add_pose_handler(on_pose)
	myo.connect()

	try:
		while True:
			myo.run(1)
		#	time.sleep(0.1)
	except KeyboardInterrupt:
		pass
	finally:
		myo.disconnect()
		ser.close()

RaspberryPy Repository

This code is part of a project to control a robot using the Myo armband - reference to this work was helpful in writing the code that allowed the Raspberry Pi to communicate with the armband. Work is by Shaofan Lai.

MyoDuino Code

Original libraries that allowed for Myo communication with an Arduino. The Programmable Air can be controlled using this work, but cannot receive over serial which is why we switched to the Raspberry Pi. Link to source code: https://www.jakechapeskie.com/wp_dir/myo/downloads/

Myo Raw Repository

This is the foundational code for providing an interface to communicate with the Thalmic Myo, providing the ability to scan for and connect to a nearby Myo, and giving access to data from the EMG sensors and the IMU. Work by Danny Zhu.

Programmable Air Repository

This is a link to the GitHub repository for the Programmable Air project by Amitabh Shrivastava

Credits

Alex Leitch
1 project • 1 follower
Contact
Celia Chen
1 project • 1 follower
Contact

Comments

Please log in or sign up to comment.