Racing Power Wheels Part 11: Fixing the Caster for Stable Steering

So the next thing to work on was fixing the instability of the steering at high speeds. After doing some online research on steering geometry, I found that the caster plays a very important role in the stability of a vehicle. The current caster of the Power Wheels had negative caster. Negative caster is when the kingpin is leaning forward at the top. Below is a picture of the negative caster on the Power Wheels.



Below is a diagram of positive and negative caster that I found online.


Negative caster causes a vehicle to become unstable at higher speeds while positive caster causes a vehicle to be more stable at higher speeds. But having too much positive caster can cause the Power Wheels car difficult to steer at higher speeds. The current caster on the Power Wheels has a caster of -7 degrees. I measured it by using a level as my vertical axis and measuring the angle of the spindle bracket from the level. From doing some online searching, I found that a good amount of caster is +10 to +15 degrees. These numbers were for gas powered go karts. I found most of this information from diygokarts.com. There I found caster can be generally set to 10 to 15 degrees of positive caster.


The Pi Zero Drone Part 2: Construction of the Frame

With the correct thrust calculations from the Gartt 2300KV motors being done. I can now begin the design of the quadcopter. I would like to include that I have no real quadcopter experience other than cheap micro-copters and have spent a lot of time breaking props and arms with those. Any information from design has been from online sources in forums and experience in engineering projects from classes and extra-curricular clubs. This would be a great build for anyone excited about learning new skills and not afraid to break a couple of plastic parts along the way.






Virtual Reality R/C Car Part 3

So the next step on this project is really what sets this project apart from your typical R/C build. In order to make the driver feel like they are actually driving the car we added a FatShark FPV system to the car. In order to mount this system on the car I created a self contained box for the radio receiver, small LiPo battery, and the FatShark camera. If you have a 3D printer and a FatShark set up at home here is a link to the STL Files:

http://www.thingiverse.com/thing:1683678

Here is the case assembled and mounted on the car:



To put the case together I used 4 2.5mm screws and two #10 x 5/8 screw and nuts. I purchased the on/off switch from amazon at this link:

https://www.amazon.com/Yueton-Blovess-Rocker-Toggle-Control/dp/B011U1NU90?ie=UTF8&*Version*=1&*entries*=0

The goggles that we are using for the system are the FatShark Teleporter Model. Which work pretty well. The main drawback of the setup currently is that the camera is fixed facing forward on the car. While driving you want to be able to look around. Its kind of like trying to drive a car that only has a windshield. It works but it does not feel totally intuitive. In the future I would like to add some sort of moving camera mount that follows the head motion of the driver. Either with an accelerometer, two servos, and an Arduino or with some technology from FatShark. I know FatShark makes a Trinity Head Tracker Module so this may be a good route to go.


Also I have made a slight change to the code as well. The car now has two modes determined by the position of a switch. There is Easy Mode (Shown above) and Sport Mode. The difference is in easy mode the cars speed is limited. However in sport mode the more you turn the throttle the faster the car will go. It is harder to control that way but once you get used to it, it is very worth it. I will post a video soon of a test of this change. I have Highlighted the changes I made in the code to do this below:

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


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

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;
  bool pushButton;          // The Joystick push-down switch
} myData;                 // This can be accessed in the form:  myData.Xposition  etc.        


void setup()  
{
  Serial.begin(115200);  
  pinMode(6,INPUT);
  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);
  gogojuice.attach(5);
  gogojuice.write(40);
}


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
  }
    double Mode;
    if (HIGH == digitalRead(6))
    {
        Mode = 0.01;
    }
    else 
    {
        Mode = 0;
    }
    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 + throttleRecieved*Mode;
    }
    if (throttleRecieved < 100 && handBreakRecieved > 100)
    {
      drive = 85;
    }
    if (throttleRecieved > 100 && handBreakRecieved > 100)
    {
      drive = 90;
    }
    if (throttleRecieved < 100 && handBreakRecieved < 100)
    {
      drive = 90;
    }
    steering.write(tilt);
    gogojuice.write(drive);
    Serial.println(drive);
}


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);
}


video

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.