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
    • 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
Design for a Cause - Design Challenge
  • Challenges & Projects
  • Design Challenges
  • Design for a Cause - Design Challenge
  • More
  • Cancel
Design for a Cause - Design Challenge
Blog Design for a Cause - The Ultimate Smart Trike Design Blog 3 of 4
  • Blog
  • Forum
  • Documents
  • Events
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Blog Post Actions
  • Subscribe by email
  • More
  • Cancel
  • Share
  • Subscribe by email
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: Sean_Miller
  • Date Created: 15 Aug 2018 3:03 AM Date Created
  • Views 451 views
  • Likes 7 likes
  • Comments 1 comment
  • ultrasonic sensor
  • trike
  • proximity
  • e14presents_raisingawesome
  • mkr1000
  • arduino
Related
Recommended

Design for a Cause - The Ultimate Smart Trike Design Blog 3 of 4

Sean_Miller
Sean_Miller
15 Aug 2018
image
Add a Motor to your Bike with Arduino

element14 Presents  | Raising Awesome's VCP Profile    |  Project Videos

 

THE TRIKE SMART CODE

In this blog and video, we'll see my approach to code and prototyping.  By starting with the code and commenting the code with the pin out purpose, I can quickly breadboard my circuits with the help of a highlighter - no schematic needed!

 

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

 

Here is the code for the Smart Trike:

 

/*

V1.0:  As Built 9/4/2018

Smart Trike by Sean and Connor Miller of Raising Awesome on YouTube
GPIO Assignments:
A0:  Motor Controller Killer (if it goes low, it kills the motor)
A1:  User okay button (interrupt) when pulled down, it interrupts
A2:  User menu button (interrupt) when pulled down, it interrupts
A3:  Ultrasonic Trigger (GPIO18)
A4:  Accelerometer X
A5:  Accelerometer Y
A6:  Accelerometer Z
D0:  pedal Sensor (interrupt)
D1:  Speed sensor (interrupt)
D2:  Beeper to give feedback when buttons are pressed
D3:  LCD's D7 pin
D4:  SD Card Chip Select Pin
D5:  LCD D5 pin
D6:  LCD D6 pin
D7:  LCD en pin 
D8:  SD Card
D9:  SD Card
D10: SD Card
D11: LCD rs
D12: LCD D4
D13: Ultrasonic Echo
D14: Brake Switch (when brake is pulled, goes to ground)
*/
// include the library code:
#include <LiquidCrystal.h>
#include <SPI.h>
#include <WiFi101.h>
#include <SD.h>
//miscellaneous pins
#define echoPin 13
#define interlockPin 15
#define pedalSensorPin 0
#define speedSensorPin 1
#define beeperPin 2
#define brakeSwitchPin 14
#define menuPin 16
#define okPin 17
// initialize the library by associating any needed LCD interface pin
// with the arduino pin number it is connected to
const int rs = 11, en = 7, d4 = 12, d5 = 5, d6 = 6, d7 = 3;
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
//Pins used by the SD card:  4, 8, 9, 10, gnd, vcc
const int chipSelect = 4;
//wifi setup
char ssid[] = "SSID";
char pass[] = "PASSWORD";
int keyIndex = 0;   
int status = WL_IDLE_STATUS;
// Initialize the WiFi client library
WiFiSSLClient wifi;
const int httpsPort = 443;//this is the SSL default port
// Use web browser to view and copy
// SHA1 fingerprint of the certificate
const char* host = "maker.ifttt.com";
String response;
int statusCode = 0;
const int trigPin=A3;//for proximity trigger
//ADXL Accelerometer pins:
const int ap1 = A4; 
const int ap2 = A5;
const int ap3 = A6;
int sv1 = 0;        
int ov1 = 0;    
int sv2 = 0;      
int ov2= 0;      
int sv3 = 0;       
int ov3= 0;      
volatile bool alarm_armed=false;//set when user selects to alarm to be on.
volatile bool alarm_triggered=false;
volatile bool menu_mode = false;volatile int menu_level=0; volatile bool want_beep=true;
volatile unsigned long menu_button_timer;volatile unsigned long ok_button_timer;//used to prevent double taps of buttons in ISRs.
volatile unsigned long speed_sensor_timer;volatile unsigned long speed_chatter_timer;volatile unsigned long proximity_timer;
volatile unsigned long pedal_sensor_timer;volatile unsigned long pedal_chatter_timer;//used to check if peddling
volatile float speed=0;volatile float top_speed=0;volatile float distance=0;float proximity=0;
volatile bool hill=false;volatile bool tilt=false;
volatile bool interlock=false; volatile bool want_garage=false;
bool not_peddling=true;bool too_slow=true;bool too_close=false;bool brake_applied=false;
int interlock_times=0; bool recorded_interlock=false;
int pedal_counter=0;//used to calculate calories burned.
String interlock_state="Enabled ";
void setup() {
  pinMode(beeperPin,OUTPUT);digitalWrite(2,LOW);//the buzzer
  pinMode(interlockPin,OUTPUT);digitalWrite(interlockPin,LOW);
  pinMode(brakeSwitchPin,INPUT_PULLUP);
  beepIt();
  lcd.begin(16, 2);// set up the LCD's number of columns and rows:
  lcd.clear();lcd.print("Starting up...");
  beepIt();
  setupProximity();
  beepIt();
  setupSDCard();
  beepIt();
  setupInterrupts();
  beepIt();
}
void loop() {
  // set the cursor to column 0, line 1
  // (note: line 1 is the second row, since counting begins with 0):
  lcd.setCursor(0,0);
  lcd.print(String(speed) + " mph ");  // print the number of seconds since reset:
  readADXL();
  readProximity();
  
  if (menu_mode) manageMenuMode();
  if (millis()>pedal_sensor_timer) {
    not_peddling=true; 
    lcd.setCursor(14,0);
    lcd.print("NP");
  }
  else 
  {
    lcd.setCursor(14,0);
    lcd.print("P ");
    not_peddling=false;
  }
  
  if ((millis()-speed_sensor_timer)>3000) speed=0;//if we haven't triggered the interrupt in 3 seconds, we are stopped.
  if (speed<2) too_slow=true;else too_slow=false;//not triggering on this anymore.  Need to be able to throttle from stop if you move the pedals around.
  if (proximity<6) too_close=true;else too_close=false;
  if (digitalRead(brakeSwitchPin)==LOW) brake_applied=true;else brake_applied=false;
  if ((brake_applied||hill||tilt||not_peddling||too_close)&&interlock_state=="Enabled ") 
  {
    if (!recorded_interlock) {
      digitalWrite(interlockPin,LOW);
      recorded_interlock=true;interlock_times++; saveToSD();delay(1000); 
      lcd.setCursor(0, 1);
      lcd.print("Locked  ");
      beepIt();    
    }
  } else {
    recorded_interlock=false;digitalWrite(interlockPin,HIGH);
    lcd.setCursor(0, 1);  
    lcd.print(interlock_state);
  }
  delay(100);
}
void setupInterrupts(){
  menu_button_timer=millis();ok_button_timer=millis();speed_chatter_timer=millis();speed_sensor_timer=millis();
  pedal_chatter_timer=millis();pedal_sensor_timer=millis();proximity_timer=millis();
  pinMode(pedalSensorPin, INPUT_PULLUP);  attachInterrupt(digitalPinToInterrupt(pedalSensorPin), pedalISR, FALLING);
  pinMode(speedSensorPin, INPUT_PULLUP);  attachInterrupt(digitalPinToInterrupt(speedSensorPin), speedISR, FALLING);
  pinMode(menuPin, INPUT_PULLUP);  attachInterrupt(digitalPinToInterrupt(menuPin), menuISR, FALLING);
  pinMode(okPin, INPUT_PULLUP);  attachInterrupt(digitalPinToInterrupt(okPin), okISR, FALLING);
}
void pedalISR(){
  if (millis()>pedal_chatter_timer) {
    if (alarm_armed) alarm_triggered=true;
    ++pedal_counter;
    pedal_sensor_timer=millis()+5000;//must pedal every 5 seconds or we will interlock
    pedal_chatter_timer=millis()+300;
  }
}
void speedISR(){
  if (millis()>speed_chatter_timer){
    if (alarm_armed) alarm_triggered=true;
    speed=.001189/(((    ( (float)millis()-(float)speed_sensor_timer ) /1000)/60.0)/60);   //(2*3.14*12/12)/5280
    distance=distance+.001189;  
    if (speed>top_speed) {top_speed=speed; saveToSD();}
    speed_sensor_timer=millis();
    speed_chatter_timer=millis()+250;//250 is to prevent noise from causing an issue.  It would mean we were going 17mph or over, which exceeds the drivetrain speed and can't happen.
  }
}
void menuISR(){
  if ((millis()>menu_button_timer)&!alarm_armed){
    want_beep=true;
    if (menu_mode==true) {
      if (++menu_level>8) menu_level=0;
    }
    else 
    {
      menu_mode=true;menu_level=0;
    }
    menu_button_timer=millis()+300;
  }
}
void readProximity() {
  //only check every half second
  if (millis()>proximity_timer) {
    long my_duration; float old_proximity=proximity;
    digitalWrite(trigPin, LOW);  
    delayMicroseconds(20); 
    digitalWrite(trigPin, HIGH);
    delayMicroseconds(50); 
    digitalWrite(trigPin, LOW);
    my_duration = pulseIn(echoPin, HIGH);
    
    proximity = ((my_duration*0.017/2.54)/12);
    if (proximity<1) proximity=old_proximity;//used to suppress bad values.
    if (proximity<1) proximity=10;//if two bad values in a row, just assume 10.  This will prevent nusance trips.
    lcd.setCursor(9,1);lcd.print(String(proximity) + "ft ");
    proximity_timer=millis()+500;
  }
}
void beepIt(){
  tone(beeperPin,800);
  delay(100);
  noTone(beeperPin);
}
void okISR(){
  if (millis()>ok_button_timer){
    if (menu_mode==true){  
      if (menu_level==0) {want_beep=true;menu_mode=false;}
      if (menu_level==7) {
        want_beep=true;
        if (interlock_state=="Enabled ") {         
          interlock_state="Disabled";
        } else interlock_state="Enabled ";
        lcd.setCursor(0,1);
        lcd.print(interlock_state);
        menu_mode=false;
      }
      if (menu_level==1){want_beep=true;want_garage=true;}//triggers the garage opener.
      
      if (menu_level==2){
        want_beep=true;
        alarm_armed= !alarm_armed;
        lcd.clear();
        if (alarm_armed) {
          lcd.print("Alarm Armed     ");
          lcd.setCursor(0,1);
          lcd.print("Don't Move!     ");
        }else {
          alarm_triggered=false;
          lcd.print("Alarm Off       ");
          menu_mode=false;
        }
      }
    }
    ok_button_timer=millis()+300;
  }
}
void soundAlarm(){
  while(alarm_triggered) {
    tone(beeperPin,1000);
    digitalWrite(brakeSwitchPin,HIGH);
    delay(300);
    noTone(beeperPin);
    delay(300);
  };//wait for disarm
}
void manageMenuMode(){
  int last_level=menu_level;
  lcd.clear();
  lcd.print("Menu:  Exit     ");
  while (menu_mode){
    if (alarm_armed) {delay(300);readADXL();}
    if (alarm_triggered) soundAlarm();
    if (last_level !=menu_level){
      if (menu_level==0) {
          lcd.clear();
          lcd.print("Menu:  Exit");
      }
      if (menu_level==1) {
          lcd.clear();
          lcd.print("Menu:Garage Door");
          lcd.setCursor(0,1);
          lcd.print("Press to trigger");
      }
      
      if (menu_level==2) {
          lcd.clear();
          lcd.print("Menu:  Alarm");
          lcd.setCursor(0,1);
          lcd.print("Press to Arm");
      }
      
      if (menu_level==3) {
          lcd.clear();
          lcd.print("Menu:  Top Speed");
          lcd.setCursor(0,1);
          lcd.print(String(top_speed));
      }
      
      if (menu_level==4) {
          lcd.clear();
          lcd.print("Menu:  Distance");
          lcd.setCursor(0,1);
          lcd.print(String(distance) + " Miles");
      }
      if (menu_level==5) {
          lcd.clear();
          lcd.print("Menu:  Time");
          lcd.setCursor(0,1);
          lcd.print(String((millis()/1000)/60) + " Mins " + ((millis()/1000) - 60*(millis()/1000/60)) + " Secs");
      }
      if (menu_level==6) {
          lcd.clear();
          lcd.print("Menu:Interlock #");
          lcd.setCursor(0,1);
          lcd.print(String(interlock_times));
      }
      if (menu_level==7) {
          lcd.clear();
          lcd.print("Menu:Interlock");
          lcd.setCursor(0,1);
          lcd.print(interlock_state);
      }
      
      if (menu_level==8) {
          lcd.clear();
          lcd.print("Menu:Designed by");
          lcd.setCursor(0,1);
          lcd.print("Raising Awesome");
      }
      last_level=menu_level;
    }
    if (want_beep) {want_beep=false;beepIt();}
    if (want_garage) {want_garage=false;sendGarageDoorCommand();}
  }
  lcd.clear();lcd.print("Exited Menu.");
}
void setupSDCard(){
  //Initialize Serial and wait for port to open:
  lcd.setCursor(0, 0);
  
  lcd.print("Initializing SD card...");
  
  // see if the card is present and can be initialized:
  if (!SD.begin(chipSelect)) {
    lcd.clear();lcd.print("Card failed, or not present");
  
   while (true);
  }
  lcd.setCursor(0,0);
  lcd.print("card initialized...");
}
void sendGarageDoorCommand(){
  lcd.clear();lcd.print("connecting WiFi");
  connectToAP();    // connect the board to the access point
 
  lcd.clear();lcd.print("making request");
  //HttpClient client=HttpClient(wifi, host, httpsPort);
  WiFiClient client;
  client.connect(host, 80);
  lcd.clear();lcd.print("Hit IFTTT");
  String url="/trigger/GarageDoorButtonPress/with/key/-oGdgnjVXXXXXXXXXm3";
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" +
               "User-Agent: BuildFailureDetectorESP8266\r\n" +
               "Connection: close\r\n\r\n");
               
  lcd.clear();
  while (client.connected()) {
    String line = client.readStringUntil('\n');
    lcd.print("Sending Command");
    if (line == "\r") {
      break;
    }
  }
  String line = client.readStringUntil('\n');
  
  lcd.clear();lcd.print("Garage Sent");
  saveToSD();
}
void connectToAP() {
  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    // don't continue:
    return;
  }
  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);
    // wait 1 second for connection:
    delay(1000);
  }
}
void saveToSD() {
  File dataFile = SD.open("RA.csv", FILE_WRITE);
  if (dataFile) {
    dataFile.print("Time:" + String(millis()/1000) +", Speed: " + String(speed) + ", Top Speed: " + String(top_speed) + ", Distance: " + String(distance) + ", Hill:" + String(hill) + ", Tilt: " + String(tilt) + ", Not Peddling: " + not_peddling +", Too Slow: " + too_slow + ", Interlock Count: " + interlock_times + "\n");
  }
  dataFile.close();
}
void readAndPrint() {
  return;
  File dataFile = SD.open("logo.txt", FILE_READ);
  while (dataFile.available()) {
    char c = dataFile.read();
   // Serial.write(c);
  }
  dataFile.close();
}
void setupProximity() {
  pinMode(trigPin, OUTPUT);digitalWrite(trigPin, LOW);
  pinMode(echoPin, INPUT_PULLDOWN);
}
void readADXL() {
  sv1 = sv1+((sv1-analogRead(ap1))/2);//this is to ease in to a tilt over a couple of seconds.  We just want to detect hills - not bumps.
  delay(2);
  sv2 = analogRead(ap2);     
  delay(2);
  sv3 = analogRead(ap3);
  lcd.setCursor(9,0);
  
  if (sv1>550) {//tilt hit  || <490will get it the other way.
     lcd.print("Hill   ");
     hill=false;
    
     tilt=true; if (alarm_armed) alarm_triggered=true;
   }else {
    lcd.print(String(sv1-520) + "   ");//give the illusion of degrees of incline
    tilt=false;
   }   
 }

In the final episode, we'll solder up a perfboard, print the 3D Plastic parts, and install.   This will finish out the Smart Trike part of the build.  We'll later jump into welding brackets for installing the batteries lower on the frame.  We'll dive into that on your main channel, Raising Awesome.

 

-Sean and Connor

  • Sign in to reply
  • hitechbuzz
    hitechbuzz over 2 years ago

    How do I download ALL the code thanks?

    • Cancel
    • Vote Up 0 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

  • Facebook
  • Twitter
  • linkedin
  • YouTube