Log in Page Discussion History Go to the site toolbox

RPI Haptics:Pulsing from Max

From BluWiki

Switching between 0V and PWM allows you to simulate a low frequency square wave of variable frequency and intensity. It should look like this:

+-+ +-+ +-+
| | | | | |
| +-+ +-+ +-----------

|a|
|----b----|
|----------c----------|
          |-----d-----|

Where a is standard PWM (determining the amplitude of the square wave), b describes the length of the pulses, and c the overall frequency. b and c can also be expressed as b and d.

Contents

Parameter Control

Early Version

These three parameters can be controlled from Max using a custom Wiring sketch. Wiring code for receiving parameters over serial that modify characteristics of the output signal:

#define params 3
#define pin 3

boolean state, lastState;
int value = 0;
int mode = 0;
int param[params]; // intensity, b, d

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

void loop() { 
  while (Serial.available() > 0) {
    value = Serial.read();
    if(value == 255) {
      mode = 0;
    } else if(mode < params) {
      param[mode] = value;
      mode++;
    }
  }
  
  analogWrite(pin, param[0]);
  delay(param[1]);
  analogWrite(pin, 0);
  delay(param[2]);
}

An earlier version used millis() to alternate between b and d, delay() works better.

Max/MSP patch for sending parameters to the Arduino.

max v2;
#N vpatcher 639 371 885 611;
#P window setfont "Sans Serif" 9.;
#P window linecount 1;
#P comment 128 94 70 9109513 d (ms);
#P comment 110 76 70 9109513 b (ms);
#P number 91 94 35 9 0 254 3 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P number 73 76 35 9 0 254 3 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P number 55 58 35 9 0 254 3 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 37 135 65 9109513 pak 255 0 0 0;
#P message 50 161 26 9109513 print;
#P newex 37 186 68 9109513 serial j 115200;
#P comment 92 58 70 9109513 intensity (0-5v);
#P connect 2 0 1 0;
#P connect 3 0 1 0;
#P connect 4 0 3 1;
#P connect 5 0 3 2;
#P connect 6 0 3 3;
#P pop;

Revised Version

Demonstrates writing to three outputs without "jumps". Updates a single output pin (11) with PWM of serial input value.

float counter[3] = {0., 0., 0.};
float frequency[3] = {1, 2, 3};
float sustain[3] = {.8, .1, .5};
float amplitude[3] = {1, .5, .2};
int outputPin[3] = {9, 10, 11};

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

void loop() {
  if(Serial.available())
    frequency[2] = Serial.read();
  updateOutputs();
}

float mod(float x, float y) {
  return x - ((int) (x / y) * y);
}

float lastTime = 0;

void updateOutputs() {
  float time = (float) millis() / 1000.;
  float timeDiff = time - lastTime;
  for(int i = 0; i < 3; i++) {
    counter[i] = mod(counter[i] + (timeDiff * frequency[i]), 1.);
    analogWrite(outputPin[i], 255 * amplitude[i] * squareWave(counter[i], sustain[i]));
  }
  lastTime = time;
}

float squareWave(float c, float s) {
  return c < s ? 1. : 0.;
}

Direct Control

An alternative approach is to use Max to determine the timing of the signal, and only send the PWM values.

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

void loop() { 
  if (Serial.available() > 0)
    analogWrite(3, Serial.read());
}
max v2;
#N vpatcher 257 237 431 510;
#P window setfont "Sans Serif" 9.;
#P flonum 99 101 35 9 0. 100. 3 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 78 166 31 9109513 delay;
#P message 51 190 23 9109513 255;
#P message 78 190 14 9109513 0;
#P flonum 21 101 35 9 0. 500. 3 139 0 0 0 221 221 221 222 222 222 0 0 0;
#P newex 21 135 40 9109513 train~;
#P message 22 190 26 9109513 print;
#P user ezdac~ 54 43 98 76 0;
#P newex 51 224 68 9109513 serial j 115200;
#P connect 4 0 3 0;
#P connect 3 1 6 0;
#P connect 2 0 0 0;
#P connect 5 0 0 0;
#P connect 6 0 0 0;
#P connect 3 1 7 0;
#P connect 7 0 5 0;
#P connect 8 0 7 1;
#P pop;

The downside of this approach is that communicating quickly over serial produces discrepancies in timing.

Site Toolbox:

TOOLBOX
LANGUAGES
GNU Free Documentation License 1.2
This page was last modified on 19 June 2008, at 05:28.
Disclaimers - About BluWiki