Introduction: Arduino VR Skateboard Tutorial for Beginners

This is a really fun and easy project that can be done in about an hour. On the bottom of the skateboard is an accelerometer/gyro with an Arduino board that transmits the angular motion of the board via bluetooth to a little virtual reality game I made for Android phones. I attempted to model El Toro which is a famous skateboard spot in California. So, when you turn on your Arduino and the bluetooth connects with your phone, you start moving forward. Lean left and you go left, lean right and you go right. Lift up the front wheels and your character will jump. This only works for Android phones and your phone must be compatible with Google Cardboard. So, if you have an old board laying around, turn it into a virtual reality skateboard. Here's how:

You will need:

A Google Cardboard style virtual reality headset.

A skateboard.

4 tennis balls (to keep from rolling away)

An Arduino Leonardo (or Uno)

Some jumper wires

A mini breadboard

An HC-06 bluetooth module

An MPU-6050 accelerometer/gyro

A 9V battery with battery box that has a on/off switch and a barrel plug (to power the Arduino board)

A soldering iron and maybe a hot glue gun

Arduino code, and parts list with links can be found here:

http://wirebeings.com/virtual-reality-skateboard.h...

Android app can be downloaded here:

https://play.google.com/store/apps/details?id=com....

For anyone interested in replicating the bluetooth communication with Unity I have used the "Bluetooth for Microcontrollers" plugin on the asset store by techtweaking:

https://www.assetstore.unity3d.com/en/#!/content/...

Step 1: Create Your Arduino Transmitter Device

Assemble your device as shown in the picture above.

You will need to solder the header pins onto the MPU-6050, if your soldering iron is new and the tip is clean this can be done in about 11 seconds. If your soldering iron tip is dirty and old this will quickly become the hardest thing you have ever done (speaking from experience).

Make sure the orientation of everything is exactly as shown in the pictures above so you do not have to get into the code and edit anything.

NOTE: The Leonardo works much better for this...however... If you are using an Arduino Uno all the connections are the same. However, the SDA could go to A4 and SCL could go to to A5.

Step 2: Attach the Arduino Device to Your Skateboard

Here I glued the battery box to the board with hot glue and screwed the Arduino board down. I used an old school board because a wider board is better for the purposes of this experience. It is pretty hard to balance on a board while in virtual reality.

The MPU-6050 has an x and y on it with arrows. Make sure the y arrow is pointing up towards the nose of the board.

Also, make sure the Arduino's usb port is clear and that you will be able to plug into it as needed.

Step 3: Prepare the Arduino IDE

Download the Arduino IDE from arduino.org if you don't already have it.

First we need to install two libraries that are code will be using.

Go to http://www.i2cdevlib.com/ and click on the usage tab.

Download the "zip archive of entire current repository snapshot"

Extract this folder and navigate to the Arduino folder. From there, find the i2cdev folder as well as the MPU6050 folder. Drag both of those onto your desktop and re-compress them to get them both into individual zip files.

Go to the Arduino IDE and from the toolbar add both of those zipped folders as libraries to your IDE.

Now we will be able to reference the scripts contained within those folders.

We need these libraries because converting raw accelerometer data is quite a challenge and these libraries will help us do it.

Step 4: Now Upload This Code to Your Skateboard

Plug in your Arduino board to your computer and upload this code. Don't forget to choose your Arduino board model and connected port from the toolbar.

#include "I2Cdev.h"
#include "MPU6050_6Axis_MotionApps20.h"
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
    #include "Wire.h"
#endif

MPU6050 mpu;

   bool sendLeft = true;
   bool sendRight = true;
   bool sendJump = true;
   bool sendCenter = true;

bool dmpReady = false;  
uint8_t mpuIntStatus;   
uint8_t devStatus;     
uint16_t packetSize;    
uint16_t fifoCount;     
uint8_t fifoBuffer[64]; 


Quaternion q;           
VectorInt16 aa;        
VectorInt16 aaReal;     
VectorInt16 aaWorld;    
VectorFloat gravity;    
float euler[3];         
float ypr[3];           
volatile bool mpuInterrupt = false;  

void setup() 
{
 
    #if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
        Wire.begin();
        TWBR = 24; 
    #elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
        Fastwire::setup(400, true);
    #endif

    Serial.begin(9600);  //For use with Arduino Uno
    Serial1.begin(9600); //For use with Leonardo

    Serial.println(F("Initializing I2C devices..."));
    mpu.initialize();

    Serial.println(F("Testing device connections..."));
    Serial.println(mpu.testConnection() ? F("MPU6050 connection successful") : F("MPU6050 connection failed"));
    Serial.println(F("Initializing DMP..."));
    devStatus = mpu.dmpInitialize();

    mpu.setXGyroOffset(220);
    mpu.setYGyroOffset(76);
    mpu.setZGyroOffset(-85);
    mpu.setZAccelOffset(1788); 
    if (devStatus == 0) {
        Serial.println(F("Enabling DMP..."));
        mpu.setDMPEnabled(true);
        Serial.println(F("Enabling interrupt detection (Arduino external interrupt 0)..."));
        attachInterrupt(0, dmpDataReady, RISING);
        mpuIntStatus = mpu.getIntStatus();
        Serial.println(F("DMP ready! Waiting for first interrupt..."));
        dmpReady = true;
        packetSize = mpu.dmpGetFIFOPacketSize();
    } else {
        Serial.print(F("DMP Initialization failed (code "));
        Serial.print(devStatus);
        Serial.println(F(")"));
    }
   
}


void loop() 
{
  
    if (!dmpReady) return;
    mpuInterrupt = false;
    mpuIntStatus = mpu.getIntStatus();
    fifoCount = mpu.getFIFOCount();
    if ((mpuIntStatus & 0x10) || fifoCount == 1024) {
        mpu.resetFIFO();
        Serial.println(F("FIFO Overflow"));

    } else if (mpuIntStatus & 0x02) {
        while (fifoCount < packetSize) {
          fifoCount = mpu.getFIFOCount();
        }
        mpu.getFIFOBytes(fifoBuffer, packetSize);        
        fifoCount -= packetSize;
        mpu.dmpGetQuaternion(&q, fifoBuffer);
        mpu.dmpGetGravity(&gravity, &q);
        mpu.dmpGetYawPitchRoll(ypr, &q, &gravity);
        
        int x = ypr[0] * 180/M_PI;
        int y = ypr[1] * 180/M_PI;
        int z = ypr[2] * 180/M_PI;
        
   if (z >= 0){
      //backward
      if (sendJump){
      Serial1.write("b");
      Serial1.write(10);
      Serial.write("b");
      Serial.write(10);
      sendJump = false;
      }
      sendLeft = true;
      sendRight = true;
      sendCenter = true;
      
    } else if (y > 4){   //To make more sensitive change value to 4 or less
      //right
      if (sendRight){
      Serial1.write("r");
      Serial1.write(10);
      Serial.write("r");
      Serial.write(10);
      sendRight = false;
      }
      sendJump = true;
      sendLeft = true;
      sendCenter = true;
    } else if (y < -4){  //To make more sensitive change to -4 or greater 
      //left
      if (sendLeft){
      Serial1.write("l");
      Serial1.write(10);
      Serial.write("l");
      Serial.write(10);
      sendLeft = false;
      }
      sendJump = true;
      sendRight = true;
      sendCenter = true;

    } else if (y >= -3 || y <= 3){
      //center
      if (sendCenter == true){
          Serial1.write("c");
          Serial1.write(10);
          Serial.write("c");
          Serial.write(10);
          sendCenter = false;
      }
      
      sendJump = true;
      sendLeft = true;
      sendRight = true;
    }   
        
       
    }
}

void dmpDataReady() 
{
    mpuInterrupt = true;
}

Step 5: Lets Calibrate the Board

With your board still plugged in pull up the serial monitor on 9600 baud.

When the board is flat you should see a "c" displayed.

When the nose is lifted up it should display "b".

Left is "l" and right is "r".

These are the values that the bluetooth module is sending the app.

You can either change the code in the if statements inside the main loop to change the thresholds, or just tighten or loosen your trucks until all the controls are working, and to your satisfaction.

You could also make a different type of controller if you wanted to control your character by hand. Just make sure that "c" is sent whenever the character is supposed to revert back to going straight.

For the Arduino Leonardo these values must be sent with Serial1.Write("c") and for the Arduino Uno it is Serial.Write("c").

Step 6: Pair the Bluetooth Module.

Before the app can connect with your skateboard it must be paired with your phone like any other bluetooth device.

On your Android phone go to settings, bluetooth, and search for a new device.

Turn your skateboard on and you should see "HC-06" pop up in your list of available devices.

Click to pair your phone with the device and it will prompt you to enter a password.

The password is "1234".

Once you are paired, you are ready to download the app.

Step 7: Download the App and Start Skating!

Go to the Google Play Store and search "Arduino VR Skateboard".

Once you have the app installed turn your phone sideways and face it in the same direction the nose of your board is facing BEFORE the app is opened.

This must be done because the character in the game is moving automatically forward so you need to make sure he is going straight in the same direction your board is facing, for the best experience.

Make sure your skateboard has been on for at least 5 seconds and open the app.

You will be prompted to click the connect button. Once you do this the red light on your bluetooth module will go from blinking red to solid, this is how you know it is connected.

Step 8: Have Fun!

Now have fun!

Put your phone into your VR headset and get to skating.

It is not a bad idea to be close to a wall or something else to hold on to while your are playing. Balancing on a skateboard is hard enough, but it becomes much harder when you have a VR headset on.

Playing on carpet is the safest but if you are like me and only have hardwood floor you can cut holes in tennis balls and wrap them around your wheels to help keep stable (and from scratching the floor).

Happy skating.

Comments

author
smoustakis made it!(author)2017-07-20

Hi, i try to compile the code and get this error...

Arduino: 1.6.13 (Windows 10), Board: "Arduino/Genuino Uno"

C:\Users\Operations1\Documents\Arduino\eeg\test1\test1.ino: In function 'void setup()':

test1:43: error: 'Serial1' was not declared in this scope

Serial1.begin(9600); //For use with Leonardo

^

C:\Users\Operations1\Documents\Arduino\eeg\test1\test1.ino: In function 'void loop()':

test1:103: error: 'Serial1' was not declared in this scope

Serial1.write("b");

^

test1:116: error: 'Serial1' was not declared in this scope

Serial1.write("r");

^

test1:128: error: 'Serial1' was not declared in this scope

Serial1.write("l");

^

test1:141: error: 'Serial1' was not declared in this scope

Serial1.write("c");

^

exit status 1

'Serial1' was not declared in this scope

About This Instructable

2,533views

18favorites

License:

Bio: My name is Matthew and I attend the University of Pittsburgh. Currently I am a senior, going for a bachelors in Information Science with a ... More »
More by matthewh8:Apple ArKit Augmented Reality AppAugmented Reality Fidget SpinnerFacial Recognition With Tracking.js
Add instructable to: