pythonc++serializationarduinovibration

Interface Arduino/RedBoard vibrator to Python


I am trying to interface my SparkFun Qwiic Haptic Driver - DA7280 with Python3. My current set-up is as follows:

PC -USB to micro-USB-> SparkFun RedBoard Qwiic -Qwiic Cable-> Haptic Driver

I've trialed the accompanying Arduino sketch & managed to get the C++ code up and running fine; modulating the vibrator's intensity & frequency just fine.

Then, what I would like to do is to trigger a vibration pulse in time with some Python code. Such that, when python prints out a word, for example, a vibratory impulse would be triggered.

I have tried using pySerial to interface with the microcontroller, trigger the controller to run a pre-loaded script. This was worked fine with a simple C++ script to repeat an LED blink uploaded to the micro-controller:

/*
  Blink

  Turns an LED on for one second, then off for one second, repeatedly for 6 seconds
*/
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  // Open serial connection.
  Serial.begin(9600);
  Serial.write('1'); 
}

// the loop function waits until it receives an input from the serial port & will stop again when it receives a stop signal.
void loop() {
  if(Serial.available() > 0){      // if data present, blink
    digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(1000);                       // wait for a second
    digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
    delay(1000);                       // wait for a second
    digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(1000);                       // wait for a second
    digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
    delay(1000);                       // wait for a second
    digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
    delay(1000);                       // wait for a second
    digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
    delay(1000);                       // wait for a second    
    Serial.write('0');
  }
}

In conjunction with a Python script to trigger & close the controller:

# import necessary modules
import os
import serial 

# connect to the arduino
## Boolean variable that will represent whether or not the arduino is connected
connected = False

## open the serial port that your ardiono is connected to.
ser = serial.Serial("COM8", 9600) # you may need to change this pending on how the board connects to the PC

## loop until the arduino tells us it is ready
while not connected:
    serin = ser.read()
    connected = True

## trigger the arduino to run the uploaded code
ser.write(1)

## Wait until the arduino tells us it is finished
while ser.read() == '1':
    ser.read()
    print(ser.read())

## trigger the arduino to run the uploaded code
ser.write(0)

## close the port and end the program
ser.close()

However, when I try replacing the LED-specific lines with commands to start and stop vibration (below) there are a few issues:

  1. Although the controller waits for the go signal from Python as expected, Python blasts through the script in no time, not waiting for a stop from the controller.
  2. The controller starts vibrating but there is no delays as expected between vibratory impulses & the vibrator never stops, even after python sends the stop trigger.
/*
  Python triggered vibration.

  Waits for Python to send a go signal at which point the vibration starts for a given duration of time.
*/

#include <Wire.h>
#include "Haptic_Driver.h" # this module is from the aforementioned Arduino sketch

Haptic_Driver hapDrive;

int event = 0; 

void setup() {
  
  // Open serial connection.
  Wire.begin();
  Serial.begin(9600);
  
  if( !hapDrive.begin())
    Serial.println("Could not communicate with Haptic Driver.");
  else
    Serial.println("Qwiic Haptic Driver DA7280 found!");

  if( !hapDrive.defaultMotor() ) 
    Serial.println("Could not set default settings.");

  // Frequency tracking is done by the IC to ensure that the motor is hitting
  // its resonant frequency. I found that restricting the PCB (squeezing)
  // raises an error which stops operation because it can not reach resonance.
  // I disable here to avoid this error. 
  hapDrive.enableFreqTrack(false);

  Serial.println("Setting I2C Operation.");
  hapDrive.setOperationMode(DRO_MODE);
  Serial.println("Ready.");
  Serial.write('1'); 
}
void loop(){
  if(Serial.available() > 0){
    hapDrive.setVibrate(25);
    delay(1500); 
    hapDrive.setVibrate(0); 
    delay(1500);
    Serial.write(0);
    Serial.flush();
  }
}

I am a novice when it comes to both micro-controllers & C++ so, forgive me for any major misunderstandings/errors. Also if anything is unclear in the above description please let me know.

Many Thanks,
Liam


Solution

  • I suspect at least part of the problem is that you are not clearing the contents of the read buffer, only checking if something is there. Serial.flush() i think that as of Arduino 1.00 (don't quote me on that) serial flush doesn't do anything to the incoming buffer.

    try adding a var = Serial.read() in before your hapDrive.setVibrate(25); and see if that changes the functionality.

    I also HEAVILY recommend interrupts for serial. There's a serial event example that's really comprehensive (although i seem to remember that's not actually interrupt driven in the classical microcontroller sense, but it's close enough!)