Virtual Reality R/C Car Part 2

Now that I know the values that each of the potentiometers on the bike output, the next step is to transmit the values over a radio. The Arduino compatible Radio Frequency chips that I chose to use were the nRF24L01+ 2.4GHz wireless transceivers. I chose these transceivers for a couple reasons. One is that these chips is that they come in two different models that communicate with the the Arduino the same way. The low power version comes with a built in antenna and has a range of about 100 feet. I have seen this model vary in price from $0.89 to around $4. The high power version has an external antenna  and has a range of around 1000 feet. I have seen this model vary in price from about $4 to $15 online.
Low Power Module

High Power Module


Another reason I chose to use these modules was because they are well documented and widely used. I suppose they are so widely used because of how inexpensive they are. But all the documentation I used to learn how to set them up can be found here:
https://arduino-info.wikispaces.com/Nrf24L01-2.4GHz-HowTo

This website gives some great examples and background knowledge of how the chips work so that anyone can begin transmitting radio signals in no time. One thing that needs to be added to the chip though is a capacitor across power and ground. Without this capacitor the chip will not function properly. The capacitor should be between 3.3 and 10 micro Farads. An example shown below.



So the next step to getting this bike working as a  R/C car controller was to make sure that the Arduino connected to the bike potentiometers would use the nRF24L01+ to transmit the values and another Arduino which would use it's own nRF24L01+ to read these values and print them to the serial monitor on the computer screen to check that they are in fact the same ranges of values that were read before.

Connecting the nRFL01+



The library that I used to interface the Arduino with the chip was the TMRh20 RF24 library so I used the fifth column to determine where to hook up each pin. This makes it really easy to connect and use the chips because once the TMRh20 RF24 library is downloaded and included, the functions created in this library can be used to interface with the chip. Below is the Code I used to test the chips and make sure that the data made it from one chip to the next.

Transmit Code
#include <SPI.h>   //SPI library to communicate with the nRF24+
#include "RF24.h"  //
#include "printf.h" // Needed for "printDetails" which is a debugging tool

#define  CE_PIN  9   // The pins to be used for CE and CSN
#define  CSN_PIN 10

RF24 radio(CE_PIN, CSN_PIN);

byte addresses[][6] = {"1Node", "2Node"}; // These will be the names of the "Pipes"

unsigned long timeNow;  // Used to grab the current time, calculate delays
unsigned long started_waiting_at;
boolean timeout;       // Timeout? True or False


struct dataStruct {
  unsigned long _micros;  // to save response times
  int throttle;          // The Joystick position values
  int handBreak;
  int bikeTilt;
} myData;                 // This can be accessed in the form:  myData.throttle


void setup()
{
  Serial.begin(115200);   //Baud Rate
  /*printf_begin();  //uncomment for debug info*/


  radio.begin();          // Initialize the nRF24L01 Radio
  radio.setChannel(108);  // Above most WiFi frequencies corresponds to 2.400 GHz + 0.108 GHz meaning radio is set to 2.508 GHz
  radio.setDataRate(RF24_250KBPS);

  //radio.setPALevel(RF24_PA_LOW);
  radio.setPALevel(RF24_PA_HIGH);
  //  radio.setPALevel(RF24_PA_MAX);

  // Open a writing and reading pipe on each radio, with opposite addresses
  radio.openWritingPipe(addresses[0]);
  radio.openReadingPipe(1, addresses[1]);

  // Start the radio listening for data
  radio.startListening();

//  radio.printDetails(); //Uncomment to show a ton of debugging information
}


void loop()   /****** LOOP: RUNS CONSTANTLY ******/
{
  radio.stopListening();                                    // First, stop listening so we can talk.


    myData.throttle = analogRead(A0);
    myData.handBreak = analogRead(A2);
    myData.bikeTilt = analogRead(A4);
    myData.pushButton  = digitalRead(7);  // Invert the pulldown switch


  myData._micros = micros();  // Send back for timing

    Serial.print("Throttle = ");
    Serial.print(myData.throttle);
    Serial.print("\t");
    Serial.print("Hand Break = ");
    Serial.print(myData.handBreak);
    Serial.print("\t");
    Serial.print("Bike Tilt = ");
    Serial.println(myData.bikeTilt);
 
  // Serial.print(F("Now sending  -  "));

  if (!radio.write( &myData, sizeof(myData) )) {          
    Serial.println(F("Transmit failed "));
  }

  radio.startListening();                                

  started_waiting_at = micros();               // timeout period, get the current microseconds
  timeout = false;                            //  variable to indicate if a response was received or not

  while ( ! radio.available() ) {                        
    if (micros() - started_waiting_at > 200000 ) {           // If waited longer than 200ms, indicate timeout and exit while loop
      timeout = true;
      break;
    }
  }

  if ( timeout )
  { // Describe the results
    Serial.println(F("Response timed out -  no Acknowledge."));
  }
  else
  {
    // Grab the response, compare, and send to Serial Monitor
    radio.read( &myData, sizeof(myData) );
    timeNow = micros();

    // Show it
    /*
    Serial.print(F("Sent "));
    Serial.print(timeNow);
    Serial.print(F(", Got response "));
    Serial.print(myData._micros);
    Serial.print(F(", Round-trip delay "));
    Serial.print(timeNow - myData._micros);
    Serial.println(F(" microseconds "));
    */

  }

  // Send again after delay. When working OK, change to something like 100
  delay(100);


}

Receive Code

#include <SPI.h>
#include "RF24.h"


RF24 radio(9, 10);

byte addresses[][6] = {"1Node", "2Node"}; // These will be the names of the "Pipes"

struct dataStruct {
  unsigned long _micros;  // to save response times
  int throttle;          // The Joystick position values
  int handBreak;
  int bikeTilt;
} myData;                 // This can be accessed in the form:  myData.throttle      


void setup()
{
  Serial.begin(115200);

  radio.begin();          // Initialize the nRF24L01 Radio
  radio.setChannel(108);  //make sure it is the same channel as the tranmitter
  radio.setDataRate(RF24_250KBPS);

  radio.setPALevel(RF24_PA_HIGH);

  // Open a writing and reading pipe on each radio, with opposite addresses
  radio.openWritingPipe(addresses[1]);
  radio.openReadingPipe(1, addresses[0]);

  // Start the radio listening for data
  radio.startListening();
}


void loop()
{
  if ( radio.available())
  {
    while (radio.available())   // While there is data ready to be retrieved from the receive pipe
    {
      radio.read( &myData, sizeof(myData) ); // Get the data
    }

    radio.stopListening();                     // First stop listening so we can transmit
    radio.write( &myData, sizeof(myData) );    // Send the received data back.
    radio.startListening();                    // Now resume listening so we catch the next packet
 
    Serial.print("Throttle = ");
    Serial.print(myData.throttle);
    Serial.print("\t");
    Serial.print("Hand Break = ");
    Serial.print(myData.handBreak);
    Serial.print("\t");
    Serial.print("Bike Tilt = ");
    Serial.println(myData.bikeTilt);
 
  }

}

Now that we know the radio chips are communicating properly the next step is to make sure that the receiving Arduino can use the data it receives to control both the ESC and the Servo on the R/C car. To do this I have updated the code on the receiving Arduino a little bit.

The ESC can be controlled the same as a servo but because the regular <Servo.h> has a timer conflict with the RF24 library the <SoftwareServo.h> library was implemented. This library works very similar to the regular servo library. The main difference is that the SoftwareServo::refresh(); function must be called each loop in order to update the value being written to the servo. Another intricacy of using the Arduino to power the ESC is that it must be "primed." This means that it needs an initial value to be written to it before it is actually responsive.

Code

#include <SoftwareServo.h>
#include <SPI.h>
#include "RF24.h"


RF24 radio(9, 10);
SoftwareServo steering;
SoftwareServo ESC;

byte addresses[][6] = {"1Node", "2Node"}; // These will be the names of the "Pipes"

struct dataStruct {
  unsigned long _micros;  // to save response times
  int throttle;          // The Joystick position values
  int handBreak;
  int bikeTilt;
} myData;                 // This can be accessed in the form:  myData.Xposition  etc.        


void setup()
{
  Serial.begin(115200);

  pinMode(3, OUTPUT);
  pinMode(5, OUTPUT);

  radio.begin();          // Initialize the nRF24L01 Radio
  radio.setChannel(108);
  radio.setDataRate(RF24_250KBPS);

  radio.setPALevel(RF24_PA_HIGH);

  // Open a writing and reading pipe on each radio, with opposite addresses
  radio.openWritingPipe(addresses[1]);
  radio.openReadingPipe(1, addresses[0]);

  // Start the radio listening for data
  radio.startListening();
  steering.attach(3);
  ESC.attach(5);
  ESC.write(40); //to prime the ESC
}


void loop()
{
  if ( radio.available())
  {
    while (radio.available())   // While there is data ready to be retrieved from the receive pipe
    {
      radio.read( &myData, sizeof(myData) ); // Get the data
    }

    radio.stopListening();                     // First stop listening so we can transmit
    radio.write( &myData, sizeof(myData) );    // Send the received data back.
    radio.startListening();                    // Now resume listening so we catch the next packet
  }
    SoftwareServo::refresh();
    int drive;
    int bikeTiltRecieved = myData.bikeTilt;
    int handBreakRecieved = myData.handBreak;
    int throttleRecieved = myData.throttle;
    int tilt = map(bikeTiltRecieved, 0, 1023, 0, 180);
    if (throttleRecieved > 100 && handBreakRecieved < 100)
    {
      drive = 96;
    }
    if (throttleRecieved < 100 && handBreakRecieved > 100)
    {
      drive = 85;
    }
    if (throttleRecieved > 100 && handBreakRecieved > 100)
    {
      drive = 90;
    }
    if (throttleRecieved < 100 && handBreakRecieved < 100)
    {
      drive = 90;
    }
    steering.write(tilt);
    ESC.write(drive);
    Serial.println(drive);
}



Virtual Reality R/C Car Part 1

Introduction:

Over at the Boca Bearings Workshop we recently were able to obtain a handful of abandoned arcade games. Once all of them arrived at the shop, Brian and I were pretty eager to find out to what degree all of these games were still functional. I mean who doesn't love some classic arcade games? Once we started looking into some of these machines we realized that there were a lot of wires without any places to be plugged in. After Brian did a little further research it turns out that it was pretty common practice to take the motherboard out of those machines when they were abandoned. This meant that we basically have everything we need except for the software to play a game. One thing we did notice however was that the arcade motorcycles that originally were used for MANX TT Superbike contained three primary input devices, 3 geared potentiometers. With the help of an Arduino we figured we could turn that bike into a controller that would make you feel a little more immersed while driving your R/C car.

Testing the Potentiometers:




So on this machine there is a potentiometer to read the tilt of the bike, how far the break is pulled in, and how far the throttle has been turned. In order to test these devices I powered them with the 5 volt output from the Arduino, connected the ground pin on each of the potentiometer to the ground on the Arduino, and connected each of the signal pins to one of the analog input pins on the Arduino Uno. All three of the potentiometers can share the same 5v input and ground but each one must be connected to a separate analog input pin.




Code:

//Declare variables
int bikeTilt;
int throttle;
int handBreak;

void setup() {
 Serial.begin(9600); //Select Baud Rate
}

void loop() {
  //Read Pots
  bikeTilt = analogRead(A0);
  throttle = analogRead(A1);
  handBreak = analogRead(A2);

  //Print and format values
  Serial.print("Bike Tilt=");
  Serial.print(bikeTilt);
  Serial.print("  Throttle=");
  Serial.print(throttle);
  Serial.print("   HandBreak=")
  Serial.println(handBreak);  // the println moves to the next line in the serial monitor
 

}

Interpreting the Results:
Arduino reads analog signals in 10-bit. This means that each variables read in the code above can range in value from 0-1023, which corresponds to the signal of the potentiometer outputting between 0 and 5 Volts. However because of the way they are set up on the bike they could not actually reach their absolute maximum and minimum. So what I did was run the code above to find out the actual maximum and minimum values for each potentiometer on the bike.

Bike Tilt
313-737

Throttle
75-976

Break
0-305

These values will be important later because these are the range of values that I will use to control the R/C car.


Racing Power Wheels Part 10: New Hydraulic Brake System




So the first braking system on the Power Wheels Dune Racer wasn't working really well in stopping the car. So we ordered a new hydraulic braking system that was shown in the last blog post. I got around to installing it on the Power Wheels with some parts of the previous braking system and with the help of Bryan from here. Below is a picture of the original braking system with the metal linkage.



The Pi Zero Drone Part 1: Introduction

Figure 1: X Frame Quad Copter
Introduction: The multirotor copters or ‘multicopter’ is a highly popular recreational hobby but are also being implemented into professional use in cinematography and even surveying landscapes that may be hard to access by foot. There are many types of multirotor copters that come in various sizes depending on the cargo onboard the copter. For this build a quadcopter with 4 propellers will be the main focus. Now comes the time to pick the style of the frame. Popular quadcopter frames include X and H frame designs. Just as the shape of the letters depicts, the location of the rotors offer minor differences depending on the use of copter. X frame quadcopters are a highly stable platform with endless possibilities for various motors and propellers.

Racing Power Wheels Part 9: Demonstration, Test Run, and Steering Problems








You can see some of the testing that we did in the videos above. In the first video above, we were simply testing the motor with the chain, sprockets, and axle. In the second video, Mihai from Boca Bearings was testing the Power Wheels Boca Dune Racer around the building.

In the first video, you can see that the Power Wheels seem to pick up lots of speed by looking at how fast the wheels were spinning. I can't really remember if we went full throttle but I think we did. After doing some more testing of the motor with the chain and axle, the set screws on the motor sprocket would fling out. So I went to Lowe's to get some Loctite Blue Thread Locker to keep the screws from coming out. Below are some pictures of the Loctite and on the set screws.

Racing Power Wheels Part 8: The Brakes, Problems Encountered, and Sparks Resolved


In this post I will be covering the braking system and the components of the braking system. The braking system can be seen in the picture above. To start things off, I will be talking about the mechanical brake kit that was ordered for this project. A mechanical brake kit was ordered from Go Power Sports and the link to the kit is http://www.gopowersports.com/go-kart-mechanical-brake-disc-kit-9511-9598-th1000/. Below is a stock picture of the kit from the website.



It includes a brake disc that would go onto the axle and lock onto the axle with the use of set screws and a key. It also includes a caliper along with a bracket for the caliper. All three components can be seen installed onto the Power Wheels frame in the first picture above. To activate the brake lever, I decided to use some sort of linkage system based on what I have seen others do on go karts. In the picture above, you can see a L-like bracket where the caliper bracket is bolted to. This L-like bracket is then bolted to the extended frame. With the use of the L bracket, no welding was required to install the brake caliper. Initially, I was planning on getting the caliper bracket welded to the frame but John came up with this design/idea which is much better since now the braking system can be removed easily for any reason.

Below is another shot of the caliper installed on the frame.


Racing Power Wheels Part 7: Setting up the Steering





With the drive axle pretty much done the next thing to work on would be the steering system of the Power Wheels Dune Racer. The above pictures were just some shots during the process of fabricating the steering system. So to start things off, I'll talk about the individual parts of the steering system.

The first part I'll bring up is the spindles along with their brackets. They came together as a complete kit. Below is an image of the kit that I got from BMI Karts.