Motor Shield V2 with Processing over USB

Adafruit Ethernet, Motor, Proto, Wave, Datalogger, GPS Shields - etc!

Moderators: adafruit_support_bill, adafruit

Please be positive and constructive with your questions and comments.
Locked
CreatorLes
 
Posts: 19
Joined: Tue Dec 23, 2014 7:03 am

Motor Shield V2 with Processing over USB

Post by CreatorLes »

Hi, I would like to use Processing to control a V2 Motor Shield. I have tried to write my own serial comm link with no success. Also I have tried Firmata which works with the servos but not with anything else AFAIK. Any suggestions?

Les

User avatar
kcl1s
 
Posts: 1512
Joined: Tue Aug 30, 2016 12:06 pm

Re: Motor Shield V2 with Processing over USB

Post by kcl1s »

You should be able to modify this example that send single character codes to the arduino. Just link these codes to motor movements commands.
https://www.arduino.cc/en/Tutorial/PhysicalPixel


Keith

CreatorLes
 
Posts: 19
Joined: Tue Dec 23, 2014 7:03 am

Re: Motor Shield V2 with Processing over USB

Post by CreatorLes »

TY for your quick response Keith. I must be missing something because I did try something like that and noticed that if the link gets out of sync then the commands will go to the wrong motor or get interpreted wrongly. So if I understand it correctly there needs to be some sort of handshaking or framing or both. I was unable to find an example that transmitted multiple commands with handshaking and frame info. I must be missing something.

Les

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Motor Shield V2 with Processing over USB

Post by adafruit_support_bill »

That is a fairly basic example. That will work fine if the processing on the Arduino side is relatively low overhead. But for operations that can take some time, you will need some handshaking. This tutorial has an example of a two-way handshake: (see about 3/4 of the way down the page)
https://itp.nyu.edu/physcomp/labs/labs- ... n-arduino/

CreatorLes
 
Posts: 19
Joined: Tue Dec 23, 2014 7:03 am

Re: Motor Shield V2 with Processing over USB

Post by CreatorLes »

Hi Bill, thanks for chiming in, you are always so helpful. i remain confused because the example I found on that page was for Arduino to Processing, not the reverse. I know that I should be creative enough to alter the example but I tried and it just wouldn't work. Maybe a more specific example is available somewhere? Possibly using Firmata which has a solid serial port link? I did see I2C features in StandardFirmataPlus, maybe that will work?

Also I am kind of surprised that this issue has not come up in the past. Surely others are trying to control Arduino Motor Shields over the Serial link. What am I missing here? Sorry to be so dense and thanks for the help in advance.

Les

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Motor Shield V2 with Processing over USB

Post by adafruit_support_bill »

the example I found on that page was for Arduino to Processing, not the reverse.
With bidirectional communication, it doesn't really which side initiates the conversation. The point is, that for every message in one direction, you need some sort of acknowledgement message going back.

So, for every command sent by processing, the Arduino side performs the action, then sends an acknowledgement. That tells the Processing side that it is OK to send the next command.

If you post the code you have so far, we can take a look at where the handshake would fit in.

CreatorLes
 
Posts: 19
Joined: Tue Dec 23, 2014 7:03 am

Re: Motor Shield V2 with Processing over USB

Post by CreatorLes »

OK thanks Bill. Here is the code for Arduino:

Code: Select all

/* 
This is a test sketch for the Adafruit assembled Motor Shield for Arduino v2
It won't work with v1.x motor shields! Only for the v2's with built in PWM
control

For use with the Adafruit Motor Shield v2 
---->	http://www.adafruit.com/products/1438

This sketch creates a fun motor party on your desk *whiirrr*
Connect a unipolar/bipolar stepper to M3/M4
Connect a DC motor to M1
Connect a hobby servo to SERVO1
*/
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_MS_PWMServoDriver.h"
#include <Servo.h> 

// Create the motor shield object with the default I2C address
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 
// Or, create it with a different I2C address (say for stacking)
// Adafruit_MotorShield AFMS = Adafruit_MotorShield(0x61); 

// Connect a stepper motor with 200 steps per revolution (1.8 degree)
// to motor port #2 (M1 and M2)
Adafruit_StepperMotor *myStepper = AFMS.getStepper(200, 1);
// And connect a DC motor to port M3  this will drive the klaw servo
Adafruit_DCMotor *myMotor = AFMS.getMotor(3);

// declare the Arduino Servo library class instances
Servo servo1;  // left servo
Servo servo2;  // right servo
//Servo servo3;  // klaw servo

// global variables
float leftPos1 = 90;
float leftPos2 = 180;
float leftPosPrev = 63;
float leftPos = 63;
float rightPos1 = 90;
float rightPos2 = 180;
float rightPosPrev = 63;
float rightPos = 63;
float klawPos1 = 63 - 30;
float klawPos2 = 63 + 30;
float klawPosPrev = 63;
float klawPos = 63;
float tau = 0.8;
int dly = 10;
float diff = 0.1;
char buff[] = {
  0, 0, 0, 0, 0,
  0, 0, 0, 0, 0};
boolean stringComplete = false;  // whether the string is complete



void setup() {
  
  Serial.begin(9600);  // set up Serial library at 9600 bps
 
  AFMS.begin(1000.0/3.0);  // create with 333Hz frequency (3ms period)
  
  // Attach servos to pins
  servo1.attach(10);
  servo2.attach(9);
  //servo3.attach(3);
   
  // initialize the stepper
  myStepper->setSpeed(20);  // in units of rpm   
  myStepper->step(0, FORWARD, MICROSTEP);  // move clockwise

  // initialize left and right motor positions
  servo1.write(constrain(map(leftPos, 0, 127, leftPos1, leftPos2), leftPos1, leftPos2));
  servo2.write(constrain(map(rightPos, 0, 127, rightPos1, rightPos2), rightPos1, rightPos2));

  // initialize the klaw position
  myMotor->setSpeed(klawPos);
  myMotor->run(RELEASE);
  myMotor->run(FORWARD);
  //servo3.write(constrain(map(klawPos, 0, 127, klawPos1, klawPos2), klawPos1, klawPos2));
}



void loop() {

  // see if there's incoming serial data
  if (stringComplete) {

    // move stepper one step in direction of commmand
    if ( (int(buff[2]) == 0) && (int(buff[3]) != 0) ) { // buttons up and ready to move
      myStepper->step(1, FORWARD, MICROSTEP);  // move clockwise
      delay(dly);  // delay to allow commands to take effect
    }
    if ( (int(buff[2]) != 0) && (int(buff[3]) == 0) ) { // buttons up and ready to move
      myStepper->step(1, BACKWARD, MICROSTEP);  // move counter-clockwise
      delay(dly);  // delay to allow commands to take effect
    }
    
    // update left motor angle
    leftPosPrev = leftPos;
    leftPos = tau*leftPos + (1-tau)*int(buff[0]);
    //if ( (int(buff[2]) == 0) && (int(buff[3]) == 0) ) { // buttons up and ready to move
      if (abs(leftPos - leftPosPrev) >= diff) { // more than 'diff' distance apart
        if ( !servo1.attached() ) {  // servo not attached
          servo1.attach(10);  // attach servo
        }
        servo1.write(constrain(map(leftPos, 1, 127, leftPos1, leftPos2), leftPos1, leftPos2));  // move servo
      } else if (servo1.attached()) {  // servo attached
        servo1.detach();  // detach servo
      }
      delay(dly);  // delay to allow commands to take effect
    //}
    
    // update right motor angle
    rightPosPrev = rightPos;
    rightPos = tau*rightPos + (1-tau)*int(buff[1]);
    //if ( (int(buff[2]) == 0) && (int(buff[3]) == 0) ) {  // buttons up and ready to move
      if (abs(rightPos - rightPosPrev) >= diff) { // more than 'diff' distance apart
        if ( !servo2.attached() ) {  // servo not attached
          servo2.attach(9);  // attach servo
        } 
        servo2.write(constrain(map(rightPos, 1, 127, rightPos1, rightPos2), rightPos1, rightPos2));  // move servo
      } else if (servo2.attached()) {  // servo attached
        servo2.detach();  // detach servo
      }
      delay(dly);  // delay to allow commands to take effect
    //}
    
    // adjust grip of klaw to be open or closed when left mouse button is closed, y axos
    //if ( (int(buff[2]) == 0) && (int(buff[3]) == 0) ) {  // buttons up and ready to move
      //klawPos = int(int(buff[0]) * (1.0 - cos(2*PI * int(buff[1])/127.0) ) );
      klawPos = int(buff[0]);
      myMotor->setSpeed(constrain(map(klawPos, 1, 127, klawPos1, klawPos2), klawPos1, klawPos2));
      delay(15);
    //}
      
    stringComplete = false;
  }
}


/*
  SerialEvent occurs whenever a new data comes in the
 hardware serial RX.  This routine is run between each
 time loop() runs, so using delay inside loop can delay
 response.  Multiple bytes of data may be available.
 */
void serialEvent() {
  
  while (Serial.available() > 0) {

    // read in the data bytes
    Serial.readBytesUntil(char(128), buff, 10);
    //Serial.flush();
    
    stringComplete = true;
  }
}


and here is the code for Processing:

Code: Select all

/* Processing code for this example */

 // mouseover serial

 // Demonstrates how to send data to the Arduino I/O board, in order to
 // turn ON a light if the mouse is over a square and turn it off
 // if the mouse is not.

 // created 2003-4
 // based on examples by Casey Reas and Hernando BANNED
 // modified 30 Aug 2011
 // by Tom Igoe
 // This example code is in the public domain.

// modified extensively 
// Les Hall
// Sat Jun3 2017
//

 import processing.serial.*;

 Serial port;

 
int vdiv = 30;
String ports[];
boolean portSelected = false;
int w = 16;
int leftButton = 0;
int rightButton = 0;


 void setup() {
   
   size(510, 510);
   frameRate(20);
   rectMode(RADIUS);
}



void draw() {
  
  // set up this frame
  background(0, 255, 255);
  
  // convert to polar, then rotate 45 degrees
  float x0 = mouseX - width/2;
  float y0 = mouseY - height/2;
  float radius = sqrt(x0*x0 + y0*y0);
  radius = constrain(radius, 0, width/2);
  float theta = atan2(y0, x0);
  float x1 = width/2 + radius * cos(theta);
  float y1 = height/2 + radius * sin(theta);
  float x = width/2 + radius * cos(theta + PI/4);
  float y = height/2 + radius * sin(theta + PI/4);

  // draw a circle to contain the control motion
  fill(color(255, 0, 255));
  ellipse(width/2, height/2, width, height);

  // draw a marker to follow mouse position
  fill(color(255, 255, 0));
  ellipse(x1, y1, 20, 20);
  
  // display the port list
  if (!portSelected) {

    // List all the available serial ports in the output pane.
    // You will need to choose the port that the Arduino board is
    // connected to from this list. The first port in the list is
    // port #0 and the third port in the list is port #2.
    // if using Processing 2.1 or later, use Serial.printArray()
    ports = Serial.list();
   
    fill(color(255, 255, 255));
    textAlign(CENTER, CENTER);
    textSize(20);
    text("please select a port", width/2, 80);
    textAlign(LEFT, CENTER);
    for (int i = 0; i < ports.length; i++)
      text(str(i) + " " + ports[i], 75, 120 + i*vdiv); 
  }
  
  // add some text to customize it
  fill(color(0, 0, 255));
  textAlign(CENTER, CENTER);
  textSize(40);
  text("Ivan Robot Arm", width/2, 40);
  
  // fill byte array with data
  int buff[] = {
    int(constrain(x * 127.0 / width, 1, 127)), 
    int(constrain(y * 127.0 / height, 1, 127)), 
    int(leftButton), 
    int(rightButton), 
    int(128),
  };
  
  // write out one set of commands
  if (portSelected) {
    port.clear();
    for (int i = 0; i < buff.length; ++i)
      port.write(char(buff[i]));
  }
}



void keyTyped() {  
  
  if (!portSelected) {
    
    // deterimine which port was selected
    int num = int(key - '1') + 1;

    setPort(num);
  }
}



void mouseClicked() {
  
  if (!portSelected) {

    int selection = (mouseY - height/2 + 90) / vdiv;
  
    setPort(selection);
  }
}



void setPort(int num) {
  
  if (!portSelected) {
  
   // Open the port that the Arduino board is connected to (in this case #0)
   // Make sure to open the port at the same speed Arduino is using (9600bps)
   if (num < ports.length) {

     port = new Serial(this, Serial.list()[num], 9600);
     
      if (port != null)
        portSelected = true;
    }
  }
}


void mousePressed() {
  if (mouseButton == LEFT)
    leftButton = 1;
  if (mouseButton == RIGHT)
    rightButton = 1;
}


void mouseReleased() {
  if (mouseButton == LEFT)
    leftButton = 0;
  if (mouseButton == RIGHT)
    rightButton = 0;
}

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Motor Shield V2 with Processing over USB

Post by adafruit_support_bill »

In your Processing code, you send commands to the Arduino in this bit of code:

Code: Select all

  // write out one set of commands
  if (portSelected) {
    .clear();
    for (int i = 0; i < buff.length; ++i)
      port.write(char(buffport[i]));
  }
If you modify it something like:

Code: Select all

  // write out one set of commands
  if (portSelected) {
    .clear();
    for (int i = 0; i < buff.length; ++i)
      port.write(char(buffport[i]));

    while(!port.available()) {} // wait for an ack...
    port.read();  //read the ack.
  }
Now it will wait until the Arduino sends back a byte in acknowledgement.

Then on the Arduino side, you have this big 'if' statement: (I'm omitting most of the contents for the moment)

Code: Select all

  // see if there's incoming serial data
  if (stringComplete) {

  // lots of code here omitted for now.
      
    stringComplete = false;
  }
At the end of that, you can send the acknowledgement byte:

Code: Select all

  // see if there's incoming serial data
  if (stringComplete) {

  // lots of code here omitted for now.
      
    stringComplete = false;
    Serial.write('A');  // any old character will do for an 'ack'
  }

CreatorLes
 
Posts: 19
Joined: Tue Dec 23, 2014 7:03 am

Re: Motor Shield V2 with Processing over USB

Post by CreatorLes »

Bill! You rewrote the most vital part of my code! And on the fourth of July at 1 am your time. I'm grinning from ear to ear with thankfulness, I'll give this a try tonight. May happiness and long life be yours.

Les

CreatorLes
 
Posts: 19
Joined: Tue Dec 23, 2014 7:03 am

Re: Motor Shield V2 with Processing over USB

Post by CreatorLes »

Bill's code worked great with minor editing. Gotta love that Adafruit support! That's the value add that you get for buying genuine Adafruit products, right?

Thanks again Bill!

Les

User avatar
adafruit_support_bill
 
Posts: 88141
Joined: Sat Feb 07, 2009 10:11 am

Re: Motor Shield V2 with Processing over USB

Post by adafruit_support_bill »

Good to hear that is working for you. Thanks for the follow-up.

Locked
Please be positive and constructive with your questions and comments.

Return to “Arduino Shields from Adafruit”