element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Members
    Members
    • Benefits of Membership
    • Achievement Levels
    • Members Area
    • Personal Blogs
    • Feedback and Support
    • What's New on element14
  • Learn
    Learn
    • Learning Center
    • eBooks
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • Experts & Guidance
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Dev Tools
    • Manufacturers
    • Raspberry Pi
    • RoadTests & Reviews
    • Avnet Boards Community
    • Product Groups
  • Store
    Store
    • Visit Your Store
    • 'Choose another store...'
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
element14 presents
  • Challenges & Projects
  • More
element14 presents
e14 presents blogs E14 Presents - Ball on a Beam - Build Inside the Box 2021
  • Blog
  • Forum
  • Documents
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
element14 presents requires membership for participation - click to join
Blog Post Actions
  • Subscribe by email
  • More
  • Cancel
  • Share
  • Subscribe by email
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: aspork42
  • Date Created: 8 May 2021 7:49 AM Date Created
  • Views 2088 views
  • Likes 13 likes
  • Comments 6 comments
  • build inside the box
  • bitb
Related
Recommended

E14 Presents - Ball on a Beam - Build Inside the Box 2021

aspork42
aspork42
8 May 2021

Greetings Earthicans!

 

For this write up, I present my project for "Build Inside the Box." This contest was designed to give various makers a "random assortment of components and have them create a project with them. This is somewhat in the style of "Chopped" cooking show.

 

I was able to get as far as a solid mechanical assembly of components, but did run quite a bit short on final assembly time.

 

I had a  build log running which can be found here if anyone is interested.

 

What did I build?

I attempted to create a "ball on a beam" project which uses a PID loop to position a rolling ball on a horizontal beam. I found out that 'nothing is simple' and  spent a lot of time over the last 2+ weeks trouble shooting. I had issues with everything rom communication to the distance sensor to reading from the SD card. Regardless, I do have basic functionality on all necessary components.

 

(Post updated to include better link to the video)

You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image

How did I use the components?

Great question!

The official list can be found here.

MKR Zero

Main brains. Controls based on the code linked here.

 

Battery Bank

Powered the system. I was able to pull over 2 amps using a programmable load. Actual system uses around 1.4 amps nominal with microstepping the stepper motor. Using normal steps takes over 1.9 amps.

 

Wago Lever Nuts

I love these things! We actually use them at work all the time.  I only found out in the last week about the IPx8 version of the GelBox from Wago and am patiently waiting on samples.... I ended up using these for connecting my microphone input to the Op Amp. Hey Wago - howz about some samples of these???

 

Vishay Phototransistor

I used this for a homing sensor to let the controller know where the beam is located. I have a 'flag' hanging off the beam that goes down and blocks the beam of this sensor when in the 'low' position.

 

Microchip Op-Amp

This component ended up being very useful. I wasn't sure at first how to use it. I ended up using it to clear up a "clap" [audio] signal into an extremely simple digital input. I look at a microphone input in one stage, then pass into an R/C circuit for the second stage. At the third stage, I just clean up the signal into a digital which the microcontroller can easily read. So the microphone input uses 3/4 of the channels on this chip. The fourth channel was used by the photo interrupter to clean up the signal into digital.

image

 

image

The circuit is as shown here.

 

OLED Display

I used this to read out all the info from the system.

 

Temperature Sensor

This is read from an analog input. My original idea was to position the ball based on the current temperature. Time constraints got to me on this one, and I was only able to read the temperature and display it on the screen.

 

Distance Sensor

In a lot of ways, this is a main component of the system. The ball's position is read from the sensor and fed into a control loop which drives the motor.

 

SD Card

We were lovingly provided with a 32 gig SD card; just for fun. I chose to use this like I which we used some things at work - local settings. I created (BORROWED)  a script to read settings from an SD card to configure the Arduino. On boot, settings are pulled in and used. I ran into  a lot of stability issues with the SD. I was at least able to read and have values displayed on-screen.

 

 

The Code

Here is the code I used in the video .

/*
 * Notes:
 * 
 * MCP9701e Datasheet: https://www.sparkfun.com/datasheets/DevTools/LilyPad/MCP9700.pdf
 * Temperature conversion = 19.5 mV/°C and range from  0°C to +70°C 
 * 400mv = 0°C (~124 bit-level). 1024 bits (using default 10-bit ADC) gives 0.00322265625 V/level
 * Formala: ((analogRead(A4) * 0.00322265625)- 0.4) /0.0195
 * 
 * I2C Addresses:
 * 0x29 VL530x distance measurement
 * 0x60 Motor shield
 * 0x70 Motor shield
 * 
 * Stepper:
 * US-17HS4401S Usongshine
 * bipolar stepper
 * Black + Green 
 * Red + Blue
 * 1.8° (200 steps/rev)
 * 9-42V DC
 * 
 * Running Microstep
 * 
 * OLED
 * Connections:
 * OLED--> MKR
 * GND-GND
 * VIN open
 * VDD-3.3v (MKR 'VCC' pin)
 * CS - 2
 * Reset- Reset
 * DC-3
 * SCL-9 (SCK)
 * SDA - 8 (MOSI)
 * 
 */




//Distance Measurement
#include "Adafruit_VL53L0X.h"
Adafruit_VL53L0X lox = Adafruit_VL53L0X();


//Stepper setup
#include <Wire.h>
#include <Adafruit_MotorShield.h>
#include <AccelStepper.h>
Adafruit_MotorShield AFMS = Adafruit_MotorShield(); 
Adafruit_StepperMotor *myMotor = AFMS.getStepper(200, 2);




// OLED setup
#include <SPI.h>
// #include <Wire.h> (Wire library included above)
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>


//SD Card
#include <SD.h>


File mySettings;
char homePin[1];
char micPin[1];
char temp;
char settingHomePin[8] = "HomePin";
char settingMicPin[7] = "MicPin";
char settingTemp[10];
char valueTemp[63];
int settingTempLastPos = 0;
int valueTempLastPos = 0;
int percentCount = 0;
int andCount = 0;
bool isSetting = true;
bool homePinValueFound = false;
bool micPinValueFound = false;




uint16_t motorPos;


#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels


// Declaration for SSD1306 display connected using software SPI (default case):
#define OLED_MOSI  8
#define OLED_CLK   9
#define OLED_DC    3
#define OLED_CS    2
#define OLED_RESET 13
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
  OLED_MOSI, OLED_CLK, OLED_DC, OLED_RESET, OLED_CS);






void forwardstep() {  
  myMotor->onestep(FORWARD, MICROSTEP);
}
void backwardstep() {  
  myMotor->onestep(BACKWARD,MICROSTEP);
}


AccelStepper AcStepMotor(forwardstep, backwardstep);




//PID tuning values (read from analog pins)
volatile uint16_t P_val;
volatile uint16_t I_val;
volatile uint16_t D_val;


void readSDConfig(){
  
  Serial.println("Initializing SD card...");
  display.setTextSize(1); 
  display.clearDisplay();
  display.setCursor(0,0);
  display.println("Reading SD...");
  display.display();


  if (!SD.begin(SDCARD_SS_PIN)) {
    Serial.println("Initialization failed!");
    display.println("Read from SD Failed.");
    display.display();
    delay(3000);
    return;
  }
  Serial.println("Initialization done.");
  mySettings = SD.open("BITB.TXT");
  if (mySettings) {
    Serial.println("BITB.TXT");  


    while (mySettings.available()) {
      temp = mySettings.read();
      if (temp == '%') {
        percentCount++;
        isSetting = true;
        if (percentCount == 2) {
          //Serial.println(settingTemp);
          if (strcmp(settingHomePin,settingTemp) == 0) {
            Serial.println("HomePin SETTING FOUND");
            //IF FOUND RAISE FLAG FOR ADDING VALUE TO SSID CHAR ARRAY
            homePinValueFound = true;
            }
          else if (strcmp(settingMicPin,settingTemp) == 0) {
            Serial.println("MicPin SETTING FOUND");


            //IF FOUND RAISE FLAG FOR ADDING VALUE TO SSID CHAR ARRAY
            micPinValueFound = true;
            }
          memset(&settingTemp[0], 0, sizeof(settingTemp));
          settingTempLastPos = 0;
          percentCount = 0;
        }
      }
      else if (temp == '&') {
        andCount++;
        isSetting = false;
        if (andCount == 2) {
          //Serial.println(valueTemp);
          if (homePinValueFound) {
            //Serial.println(valueTemp);
            memcpy(homePin,valueTemp,63);
            Serial.println(homePin);
            display.print("Home Pin is: ");
            display.println(homePin);
            display.display();
            homePinValueFound = false;
            }
          else if (micPinValueFound) {
            //Serial.println(valueTemp);
            memcpy(micPin,valueTemp,63);
            display.print("Mic Pin is: ");
            display.println(micPin);
            display.display();
            Serial.println(micPin);
            micPinValueFound = false;
            }
          memset(&valueTemp[0], 0, sizeof(valueTemp));
          valueTempLastPos = 0;
          andCount = 0;
        }
      }
      else {
        if (isSetting == true) { //setting
          settingTemp[settingTempLastPos] = temp;
          settingTempLastPos++;
        }
        else if (isSetting == false) { //value
          valueTemp[valueTempLastPos] = temp;
          valueTempLastPos++;
        }
      }
    }
    //Serial.println(settingTemp);
    mySettings.close();
    delay(3000);
  } else {
    Serial.println("Can't open BITB.TXT");
  }




}




void setup() {
  Serial.begin(115200);
  //pinMode(A4, INPUT);
  delay(100);




  
  pinMode(5, INPUT);
  pinMode(6, INPUT);
  
  //enable display first
  Serial.println("Starting OLED display...");
  if(!display.begin(SSD1306_SWITCHCAPVCC)) {
    Serial.println(F("SSD1306 allocation failed"));
    for(;;); // Don't proceed, loop forever
  }
  display.clearDisplay();
  display.setTextSize(2);             
  display.setTextColor(SSD1306_WHITE);        // Draw white text
  display.setCursor(0,0);             // Start at top-left corner
  display.println(F("Ball on"));
  display.println(F("   a Beam"));
  display.display();
  delay(2000);
    
  Serial.println("Starting VL53L0X device");
  if (!lox.begin()) {
      display.clearDisplay();
      display.setTextSize(1); 
      display.setCursor(0,16);    
      display.println(F("Dist. Sense failed to boot"));
      display.display();
    //Serial.println(F("Failed to boot VL53L0X"));
    delay(1000);
  }
  
  Serial.println("Attempting to read SD settings");
  readSDConfig();
  
  //stepper setup
  AFMS.begin(); 
  AcStepMotor.setMaxSpeed(3200.0); //was up to 1200
  AcStepMotor.setAcceleration(3000.0); //was up to 1000.0


  //clear display before starting
  display.clearDisplay();
  display.display();
  display.setTextSize(1);
  display.setTextColor(SSD1306_WHITE);
}




uint32_t lastTime = 0;
uint32_t waitTimer = 50;


int myDistance =0;
float myTemperature =0;


void loop() {
  readPID();
  
  if(millis() > lastTime + waitTimer){
    display.clearDisplay();
    display.setTextSize(1);
    display.setCursor(0, 0);
    display.print("P"); 
    display.print(P_val);
    display.setCursor(0, 9);
    display.print("I"); 
    display.print(I_val);    
    display.setCursor(0, 18);
    display.print("D"); 
    display.print(D_val);


    myTemperature = readTemperature();
    display.setCursor(50, 0);
    display.print(myTemperature);
    display.print("C");
  
    //Serial.print(" Distance: ");
    myDistance = readDistanceSensor();


    
    display.setTextSize(2);
    display.setCursor(40, 15);
    display.print("D:");
    display.print(myDistance);


    display.setTextSize(1);
    uint8_t homePresent = 1;
    if(digitalRead(6)) homePresent=0;
    display.setCursor(110, 24);
    display.print(homePresent);
        
    uint8_t MicActive = 0;
    if(digitalRead(5)) MicActive=1;
    display.setCursor(110, 14);
    display.print(MicActive);
    
    //AcStepMotor.moveTo(myDistance);
    
    display.display();
    lastTime = millis();
  }
  
    
  //stepper positioning
  AcStepMotor.moveTo(analogRead(A1));
  AcStepMotor.run();
}


float readTemperature(){
  float temp=round(((analogRead(A4) * 0.00322265625)- 0.4) /0.0195 * 10) / 10;
  return temp;
}


void readPID(){
  uint32_t tempVal=0;
  uint8_t readLoops=32;
  
  for(int i=0; i<readLoops; i++){
    tempVal += analogRead(A1);
  }
  P_val = tempVal/readLoops;
  tempVal = 0;
  
  for(int i=0; i<readLoops; i++){
    tempVal += analogRead(A2);
  }
  I_val = tempVal/readLoops;
  tempVal = 0;


  for(int i=0; i<readLoops; i++){
    tempVal += analogRead(A3);
  }  
  D_val = tempVal/readLoops;
  tempVal = 0;
}




int readDistanceSensor(){
  VL53L0X_RangingMeasurementData_t measure;
    
  //Serial.print("Reading a measurement... ");
  lox.rangingTest(&measure, false); // pass in 'true' to get debug data printout!


  if (measure.RangeStatus != 4) {  // phase failures have incorrect data
    //Serial.print("Distance (mm): "); Serial.println(measure.RangeMilliMeter);
    return(measure.RangeMilliMeter);
  } else {
    return(-1);
    //Serial.println(" out of range ");
  }  
}

 

The code for after reading settings from SD are taken from here - but I always got a lock-up after trying.

 

 

 

I could easily have used an extra week or three on this project, but was able to get this far given the time constraints. Thanks as always to the E14 team for making this all possible.

-James O'Gorman

  • Sign in to reply

Top Comments

  • dubbie
    dubbie over 2 years ago +2
    You have my sympathies. Sometimes stuff just won't work. Dubbie
  • greenmate
    greenmate over 2 years ago +1
    I had issues with the SD card / SPI for the OLED screen as well, after moving the screen to other pins (see my code for which pins I used, not all of them ended up working), and using software SPI, everything…
  • aspork42
    aspork42 over 2 years ago in reply to greenmate +1
    Thanks Mate - I might give those a try. It took me a little bit at first even realizing that the SD card has its own 'internal' pins on the MKR that aren't shared with the normal pin headers.
  • mayermakes
    mayermakes over 2 years ago

    I especially like the detailed explanation!

    Challenges are what this contest is about! and I think you made a great job showing functionality and trouble shooting.

    Spoiler: I also had trouble on my project.
    isn't problemsolving the fun in these kinds of challenges!

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • aspork42
    aspork42 over 2 years ago in reply to dubbie

    Thanks Dubbie. I'm licking my wounds on this one! Hoping to post an update just so I can sleep good at night (I know I'm after the deadline now, so it won't count for anything contest-related).

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • dubbie
    dubbie over 2 years ago

    You have my sympathies. Sometimes stuff just won't work.

     

    Dubbie

    • Cancel
    • Vote Up +2 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • greenmate
    greenmate over 2 years ago in reply to aspork42

    It does have its own SPI bus, but for some reason, it didn't like using both the SD card and hardware SPI on the pin headers. I could get one of them to work, but never together. I thought that the SD card shares the SPI pins as well, but it doesn't, so I have no idea what's happening. I'll play around with it later.

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • aspork42
    aspork42 over 2 years ago in reply to greenmate

    Thanks Mate - I might give those a try. It took me a little bit at first even realizing that the SD card has its own 'internal' pins on the MKR that aren't shared with the normal pin headers.

    • Cancel
    • Vote Up +1 Vote Down
    • Sign in to reply
    • More
    • Cancel
>
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2023 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube