Hey, I'm working on a haptic project vibrating an LRA motor via an adafruit DRV2605 haptic driver and getting some unexpected results, would greatly appreciate any suggestions as to where I may be going wrong. What I'm trying to achieve is a variable vibration intensity of the motor depending upon incoming data received over serial. The ultimate setup will have 5 LRAs, (and parts of the code anticipate this) though I've just got it setup with the one LRA for now.
The realtime playback mode of the driver can accept continuous realtime inputs to set the vibration intensity, which in theory should work perfectly for my needs. However, what is happening at the moment is that;
If LRAINT is 0 - LRA does not buzz - ok
If LRAINT is between 1 and about 120 - the LRA buzzes but the vibration intensity does not change
If LRAINT is over about 120 the LRA does not buzz at all
So, what I have is a vibration that seems to be either on or off, rather than increasing in intensity as LRAINT increases and then once LRAINT is over about 120, the vibration ceases, rather than continuing to increase up to 255 (I've tried reducing 255 to 200 etc in case the LRA does not work at full max intensity, but this didn't make a difference).
So I guess 2 issues;
- Vibration intensity not varying with LRAINT realtime value
- Vibration intensities over 120 result in zero vibration response.
Here's the code so far:
#include <Wire.h>
#include <Adafruit_DRV2605.h> //change to adafruit library for RTP mode
// define data received over serial
const byte numChars = 255;
char receivedChars[numChars];
char tempChars[numChars]; // temporary array for use when parsing
float floatsFromPC[32];
// arrange 32 received FFT bins on a log scale and map to 5 LRAs - NB LRA start / end range starts at 0
float LRA[5];
const int LRAStartRange[5] = {0, 1, 3, 7, 15};
const int LRAEndRange[5] = {0, 2, 6, 14, 31};
int LRAINT[5];
boolean newData = false;
Adafruit_DRV2605 drv;
void setup() {
while (!Serial);
delay(1000);
Wire.begin();
Serial.begin(115200); // opens serial port, sets data rate
drv.begin(); //initiate the i2C interface - switch to drv. initialise instruction
drv.useLRA(); // set LRA mode
drv.setMode(DRV2605_MODE_REALTIME); //Realtime mode enabled for direct control through software rather than hardware
delay(2000);
Serial.println("Arduino is Ready");
Serial.println();
}
void loop() {
// receive and parse the serial data into 32 FFT bins and calculate LRA ampltiudes (see defined sections below) and set the realtime value of the LRA to data received
{
recvWithStartEndMarkers();
if (newData == true)
{
strcpy(tempChars, receivedChars);
// this temporary copy is necessary to protect the original data
// because strtok() used in parseData() replaces the commas with \0
parseData();
showParsedData();
LRAINT[0] = int(LRA[0]);
LRAINT[0] = map(LRAINT[0], 0, 100, 1, 255); //maps the received value to a new range
Serial.println(LRAINT[0]);
drv.setRealtimeValue(LRAINT[0]); //setting function to assign the new vibration value
newData = false;
}
}
}
//============
// receive a stream of data differentiated with <> start / end markers (from MaxMsp)
void recvWithStartEndMarkers()
{
static boolean recvInProgress = false;
static byte ndx = 0;
char startMarker = '<';
char endMarker = '>';
char rc;
while (Serial.available() > 0 && newData == false)
{
rc = Serial.read();
if (recvInProgress == true)
{
if (rc != endMarker)
{
receivedChars[ndx] = rc;
ndx++;
if (ndx >= numChars)
{
ndx = numChars - 1;
}
}
else
{
receivedChars[ndx] = '\0'; // terminate the string
recvInProgress = false;
ndx = 0;
newData = true;
}
}
else if (rc == startMarker)
{
recvInProgress = true;
}
}
}
//============
// split the data into its floating point parts
void parseData() // split the data into its parts
{
char * strtokIndx; // this is used by strtok() as an index
strtokIndx = strtok(tempChars, " "); // get the first part - the string
floatsFromPC[0] = atof(strtokIndx); // convert this part to a float
for (int i = 1; i < 32; i++)
{
strtokIndx = strtok(NULL, " "); // this continues where the previous call left off
floatsFromPC[i] = atof(strtokIndx); // convert this part to a float
}
}
// find the maximum figure in each LRA range
float maxInRange(int start, int end)
{
float max = floatsFromPC[start];
for (int i = start + 1; i <= end; i++)
{
if (floatsFromPC[i] > max)
max = floatsFromPC[i];
}
return max;
}
// print FFT amplitude in each of 32 bins
void showParsedData()
{
for (int i = 0; i < 32; i++)
{
// Serial.print("Bin ");
// Serial.print(i+1);
// Serial.print(": "
Serial.print(floatsFromPC[i]);
}
Serial.println();
// print LRA amplitude as maximum in each of 5 bins consolidated logarithmically from the 32 FFTs bins
for (int i = 0; i < 5; i++)
{
LRA[i] = maxInRange(LRAStartRange[i], LRAEndRange[i]) * 100;
Serial.print("LRA");
Serial.print(i + 1);
Serial.print(' ');
Serial.println(LRA[i]);
}
}
Best
Jess