Mechatronic Marionette
  • HOME
  • Subsystems
  • Blog
  • Gallery
  • About
  • Budget
  • Contact

Software System

The firmware/software system of the Mechatronic Marionette is mainly composed of original Arduino code with user libraries. Since we have two major electrical components: buttons and motors, we have two user libraries we are using to control them: the Adafruit MotorShield library and EasyButton library. For each pre-programmed motion, it is self contained within a single module that is activated by the press of a button. The individual modules actuate the appropriate motors at appropriate times in order to perform a smooth and realistic motion. At the end of each motion, there is also pre-progarmmed script to adjust the position of the marionette in order to come back to the same position every time. After each motion, the script automatically switches to the "STOP" mode and wait for the next button press. The entire script works together as a coherent and dynamic unit that sends out smooth signals to the buttons, motors, and motorshields.

Below we have included more information on the details of the script with the intent to help you understand it with ease.

The Adafruit MotorShield library is used to control the motors that are manipulating the marionette. Here is a direct link to their info page so you can learn about programming with the motorshield. The direct link to download the libary is here.

​
The way we are including the motorshield into our code is as follows:
​#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include "utility/Adafruit_PWMServoDriver.h"


The way we are initializing the motorshields is:
// Create the motor shield object with stacking I2C addresses
Adafruit_MotorShield AFMSMotorShield1 = Adafruit_MotorShield(0x60);
Adafruit_MotorShield AFMSMotorShield2 = Adafruit_MotorShield(0x63);


After the motorshields are initialized, we use them to set up the motors:
// Initiate the motors controlling the left and right side of the body
Adafruit_DCMotor *lefthandMotor = AFMSMotorShield1.getMotor(1);  // Motor 1
Adafruit_DCMotor *righthandMotor = AFMSMotorShield1.getMotor(2);  // Motor 2
Adafruit_DCMotor *leftfootMotor = AFMSMotorShield1.getMotor(3);  // Motor 3
Adafruit_DCMotor *rightfootMotor = AFMSMotorShield1.getMotor(4);  // Motor 4
Adafruit_DCMotor *laterallefthandMotor = AFMSMotorShield2.getMotor(1);  // Motor 5
Adafruit_DCMotor *lateralrighthandMotor = AFMSMotorShield2.getMotor(2);  // Motor 6
Adafruit_DCMotor *upperbodyMotor = AFMSMotorShield2.getMotor(3);  // Motor 7
Adafruit_DCMotor *bottomMotor = AFMSMotorShield2.getMotor(4);  // Motor 8


The motor speeds are initially declared in void setup{}:
    AFMSMotorShield1.begin();
    AFMSMotorShield2.begin();
    // Set the speed to start, from 0 (off) to 255 (max speed)
    lefthandMotor->setSpeed(50);
    righthandMotor->setSpeed(50);
    leftfootMotor->setSpeed(50);
    rightfootMotor->setSpeed(50);
    laterallefthandMotor->setSpeed(50);
    lateralrighthandMotor->setSpeed(50);
    upperbodyMotor->setSpeed(50);
    bottomMotor->setSpeed(50);

​We also use a library for controlling the buttons on the control panel. The link to the documentation is here.
The way the buttons are set up is by first setting up the pins where inputs are collected from the buttons:

const int buttonPin1 = 5;    
const int buttonPin2 = 6;
const int buttonPin3 = 7;
const int buttonPin4 = 8;
const int buttonPin5 = 9;
const int buttonPin6 = 10;


​Then we set up the easybuttons in order to control them with code:
//Setting up the easybuttons
EasyButton button1(buttonPin1);
EasyButton button2(buttonPin2);
EasyButton button3(buttonPin3);
EasyButton button4(buttonPin4);
EasyButton button5(buttonPin5);
EasyButton button6(buttonPin6);


We check for button states by calling:
    button1.update();
    button2.update();
    button3.update();
    button4.update();
    button5.update();
    button6.update();


If a button is pushed, we then switch to that motion:
if (button1.IsPushed()) {
          mode = 1;
    }


For the "Random" button, we are picking one out of nine pre-programmed motions using the randomSeed and random function:

    // if analog input pin 0 is unconnected, random analog
    // noise will cause the call to randomSeed() to generate
    // different seed numbers each time the sketch runs.
    // randomSeed() will then shuffle the random function.
    randomSeed(analogRead(0));
    mode = round(random(1,10));


Below is an example of a pre-programmed motion: 
  else if (mode ==6) { // DROP DEAD
    Serial.println("DROP DEAD");
     // First, we set the appropriate motor speeds for this specific motion
      lefthandMotor->setSpeed(100);
      righthandMotor->setSpeed(100);
      leftfootMotor->setSpeed(50);
      rightfootMotor->setSpeed(50);
      laterallefthandMotor->setSpeed(100);
      lateralrighthandMotor->setSpeed(100);
      upperbodyMotor->setSpeed(100);
      bottomMotor->setSpeed(50);
    // We then go through the pre-programmed motions by updating the counter
    if (mode6counter == 0) {
        currentMillis = millis();
      if (currentMillis - previousMillis > 500) {            // wait for two second
      previousMillis = currentMillis;
      mode6counter++;
    lefthandMotor->run(BACKWARD);
    righthandMotor->run(BACKWARD);
    rightfootMotor->run(RELEASE);

    leftfootMotor->run(RELEASE);
    lateralrighthandMotor->run(FORWARD);
    laterallefthandMotor->run(BACKWARD);
      upperbodyMotor->run(BACKWARD);
      bottomMotor->run(RELEASE);
    }
    }
    if (mode6counter == 1) {
        currentMillis = millis();
      if (currentMillis - previousMillis > 1500) {            // wait for two second
      previousMillis = currentMillis;
      mode6counter++;
    righthandMotor->run(RELEASE);
    lefthandMotor->run(RELEASE);
    rightfootMotor->run(RELEASE);
    leftfootMotor->run(RELEASE);
    lateralrighthandMotor->run(RELEASE);
    laterallefthandMotor->run(RELEASE);
      upperbodyMotor->run(BACKWARD);

      bottomMotor->run(RELEASE);
    }
    }
    if (mode6counter == 2) {
        currentMillis = millis();
      if (currentMillis - previousMillis > 1000) {            // wait for two second
      previousMillis = currentMillis;   
      mode6counter++;
      righthandMotor->run(RELEASE);
      lefthandMotor->run(RELEASE);
      rightfootMotor->run(RELEASE);
      leftfootMotor->run(RELEASE);
      lateralrighthandMotor->run(RELEASE);
      laterallefthandMotor->run(RELEASE);
      upperbodyMotor->run(RELEASE);
      bottomMotor->run(RELEASE);
    }
    }
    if (mode6counter == 3) {

        currentMillis = millis();
      if (currentMillis - previousMillis > 3000) {            // wait for two second
      previousMillis = currentMillis;
      mode6counter++;
      righthandMotor->run(RELEASE);
      lefthandMotor->run(RELEASE);
      rightfootMotor->run(RELEASE);
      leftfootMotor->run(RELEASE);
      lateralrighthandMotor->run(RELEASE);
      laterallefthandMotor->run(RELEASE);
      upperbodyMotor->run(FORWARD);
      bottomMotor->run(RELEASE);
    }
    }
    if (mode6counter == 4) {
        currentMillis = millis();
      if (currentMillis - previousMillis > 1000) {            // wait for two second
      previousMillis = currentMillis;   
      mode6counter++;
      lefthandMotor->run(FORWARD);
      righthandMotor->run(FORWARD);

      rightfootMotor->run(RELEASE);
      leftfootMotor->run(RELEASE);
      lateralrighthandMotor->run(BACKWARD);
      laterallefthandMotor->run(FORWARD);
      upperbodyMotor->run(FORWARD);
      bottomMotor->run(RELEASE);
    }
    }
        if (mode6counter == 5) {
        currentMillis = millis();
      if (currentMillis - previousMillis > 1500) {            // wait for two second
      previousMillis = currentMillis;   
      mode6counter++;
      lefthandMotor->run(RELEASE);
      righthandMotor->run(RELEASE);
      rightfootMotor->run(RELEASE);
      leftfootMotor->run(RELEASE);
      lateralrighthandMotor->run(RELEASE);
      laterallefthandMotor->run(RELEASE);
      upperbodyMotor->run(FORWARD);

      bottomMotor->run(RELEASE);
    }
    }
    // In the last block, we reset the counter to 0, reset the mode to mode 0 (STOP), and reset the motor speeds
    if (mode6counter == 6) {
        currentMillis = millis();
      if (currentMillis - previousMillis > 250) {            // wait for two second
      previousMillis = currentMillis;
      mode6counter = 0;
      Serial.println(mode5counter);
      righthandMotor->run(RELEASE);
      lefthandMotor->run(RELEASE);
      rightfootMotor->run(RELEASE);
      leftfootMotor->run(RELEASE);
      lateralrighthandMotor->run(RELEASE);
      laterallefthandMotor->run(RELEASE);

      upperbodyMotor->run(RELEASE);
      bottomMotor->run(RELEASE);
      mode = 0;
      lefthandMotor->setSpeed(50);
      righthandMotor->setSpeed(50);
      leftfootMotor->setSpeed(50);
      rightfootMotor->setSpeed(50);
      laterallefthandMotor->setSpeed(50);
      lateralrighthandMotor->setSpeed(50);
      upperbodyMotor->setSpeed(50);
      bottomMotor->setSpeed(50);
    }
    }
  }

The complete source code is updated on our GitHub repository.

gitHub Repo
Create a free web site with Weebly
  • HOME
  • Subsystems
  • Blog
  • Gallery
  • About
  • Budget
  • Contact