Help with new project

Hi,

I'm a high level quad and I am trying to build an RC car transmitter controlled via Arduino and connected controller as per the instructions on this video (https://www.youtube.com/watch?v=pHaMghL2PHk).

The video is awesome but unfortunately it's over 3 years old and some of the required parts have been discontinued like the USB Host shield. All the crap dodgy USB shields that are available to buy don't work properly and don't send power to the connected USB device. Even after trying the fixes found online I cannot get any of them to work.

Could anyone recommend an alternative approach that doesn't use a USB shield? Are there any boards that have a native USB host and way to power the board by by battery?

Thanks for your help.

Post your annotated schematic showing all parts and links to there technical data. Posting your code will also help.

As far as videos, I think you picked a very poor one to follow.

Thanks for your reply.

I don't have an annotated schematic but I could try do one if it's really needed?

As far as parts go I am using a Quadstick (www.quadstick.com) for control (why I need for a USB host), an iRangeX IRX4 Plus 2.4G transmitter to receive PPM signals from the Arduino, an RGB LCD Shield to display settings and a USB powerbank to power the Arduino, Quadstick and transmitter.

I'm starting with the following code that has been taken from the YouTube video:

/*
 * Sketch by David Simpson
 * 
 * Adapted from sketch By DroneMesh
 * I did not create the Library this was Found online links are below
 * I did not create the PPM function Was found online links are below
 * I merged both codes to create something usefull out of it
 * 
 * 
 * PPM Output is on Pin 3 
 * 
 * Download USB Host Shield Library First 
 * https://github.com/felis/USB_Host_Shield_2.0/archive/master.zip
 * 
 * Channel Info Currently Setup AS AETR you can change this by changing the PPM Value in the main loop
 * 
 * Ch1 A (Steering) ==  ppm[0]
 * Ch2 E (Throttle) ==  ppm[1]
 * Ch3 T (NOT USED) ==  ppm[2]
 * Ch4 R (NOT USED) ==  ppm[3]
 * Ch5 AUX1 (NOT USED) == ppm[4]
 * Ch6 AUX2 (NOT USED) == ppm[5]
 * Ch7 AUX3 (NOT USED) == ppm[6]
 * Ch8 AUX4 (NOT USED) == ppm[7]
 */

// Satisfy the IDE, which needs to see the include statment in the ino too.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>

// Includes for PS3 Controller
// https://github.com/felis/USB_Host_Shield_2.0/archive/master.zip
#include <PS3USB.h>
USB Usb;
PS3USB PS3(&Usb);

// Includes and Defines for Adafruit RGB LCD Shield
// https://github.com/adafruit/Adafruit-RGB-LCD-Shield-Library/archive/refs/heads/master.zip
#include <LiquidCrystal.h>
#include <Wire.h>
#include <Adafruit_RGBLCDShield.h>
#include <utility/Adafruit_MCP23017.h>
Adafruit_RGBLCDShield lcd = Adafruit_RGBLCDShield();
// Define RGB LCD Colours
#define RED 0x1
#define GREEN 0x2

// Setup some variables
int steeringTrim = 0;
int steeringTrimLCD = 0;
int speedSetting = 1;
int speedMax = 1590;
int speedMin = 1410;

////////////// PPM 
/*
 * PPM generator originally written by David Hasko
 * on https://code.google.com/p/generate-ppm-signal/ 
 */

//////////////////////CONFIGURATION///////////////////////////////
#define CHANNEL_NUMBER 8  //set the number of chanels
#define CHANNEL_DEFAULT_VALUE 1500  //set the default servo value
#define FRAME_LENGTH 22500  //set the PPM frame length in microseconds (1ms = 1000µs)
#define PULSE_LENGTH 300  //set the pulse length
#define onState 1  //set polarity of the pulses: 1 is positive, 0 is negative
#define sigPin 3  //set PPM signal output pin on the arduino
//////////////////////////////////////////////////////////////////

#define SWITCH_PIN 16
#define CHANNEL_TO_MODIFY 11
#define SWITCH_STEP 100

byte previousSwitchValue;

/*this array holds the servo values for the ppm signal
 change these values in your code (usually servo values move between 1000 and 2000)*/
int ppm[CHANNEL_NUMBER];

int currentChannelStep;
bool printAngle;
uint8_t state = 0;
/////////////


void setup() {
  Serial.begin(115200);
#if !defined(__MIPSEL__)
  while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
#endif
  if (Usb.Init() == -1) {
    Serial.print(F("\r\nOSC did not start"));
    while (1); //halt
  }
  Serial.print(F("\r\nPS3 USB Library Started"));

///////////////////////////////
  previousSwitchValue = HIGH;
  
  //initiallize default ppm values
  for(int i=0; i<CHANNEL_NUMBER; i++){
    if (i == 2 || i == CHANNEL_TO_MODIFY) {
      ppm[i] = 1000;
    } else {
      ppm[i]= CHANNEL_DEFAULT_VALUE;
    }
  }
  
  pinMode(sigPin, OUTPUT);
  pinMode(SWITCH_PIN, INPUT_PULLUP);
  digitalWrite(sigPin, !onState);  //set the PPM signal pin to the default state (off)

  // Set up the LCD's number of columns and rows and display static text
  lcd.begin(16, 2);
  lcd.setCursor(0, 0);
  lcd.print("Steer trim: 0     ");
  lcd.setCursor(0, 1);
  lcd.print("Speed: 1");
  lcd.setCursor(15, 1);
  lcd.print("Q");
  
  cli();
  TCCR1A = 0; // set entire TCCR1 register to 0
  TCCR1B = 0;
  
  OCR1A = 100;  // compare match register, change this
  TCCR1B |= (1 << WGM12);  // turn on CTC mode
  TCCR1B |= (1 << CS11);  // 8 prescaler: 0,5 microseconds at 16mhz
  TIMSK1 |= (1 << OCIE1A); // enable timer compare interrupt
  sei();

  currentChannelStep = SWITCH_STEP; 
}


void loop() {
  Usb.Task();
  if (PS3.PS3Connected) {

    // Steering
    // Attached to PS3 Left Joystick X Axis
    
    // First calculate trim
    // Steering trim adjusted by Left and Right D-Pad
    
    if (PS3.getButtonClick(LEFT)){ // Incrementally trim steering to turn left
      steeringTrim = steeringTrim - 5;
      steeringTrimRefreshLCD();
    }
    if (PS3.getButtonClick(RIGHT)){ // Incrementally trim steering to turn right
      steeringTrim = steeringTrim + 5;
      steeringTrimRefreshLCD();
    }

    if (PS3.getAnalogHat(LeftHatX)) { // Centre stick value = 127, full left = 0, full right = 255. Deadzone provided between 124 and 130.
      if (PS3.getAnalogHat(LeftHatX) > 130 || PS3.getAnalogHat(LeftHatX) < 124) {
        ppm[0] = map(PS3.getAnalogHat(LeftHatX), 0 , 255, 1000, 2000) + steeringTrim;
      } else {
        ppm[0] = 1500 + steeringTrim;
      }
    } 
    
    // Throttle 
    // Attached to PS3 Left Joystick Y Axis
    // Allows adjustment of the speed range to allow a lower maximum speed to accommodate beginners

    if (PS3.getButtonClick(UP) && speedSetting < 4) {
      speedSetting = speedSetting + 1;
      Serial.println(speedSetting);
      speedSettingRefreshLCD();
    }

    if (PS3.getButtonClick(DOWN) && speedSetting > 1) {
      speedSetting = speedSetting - 1;
      Serial.println(speedSetting);
      speedSettingRefreshLCD();
    }

    if (speedSetting == 1) {
      speedMax = 1590;
      speedMin = 1410;
    }

    if (speedSetting == 2) {
      speedMax = 1700;
      speedMin = 1300;
    }

    if (speedSetting == 3) {
      speedMax = 1850;
      speedMin = 1150;
    }

    if (speedSetting == 4) {
      speedMax = 2000;
      speedMin = 1000;
    }
    
    if (PS3.getAnalogHat(LeftHatY)) { //Centre stick value = 127, full down/reverse = 255, full up/forward = 0. Deadzone provided between 124 and 130.
      if (PS3.getAnalogHat(LeftHatY) > 130 || PS3.getAnalogHat(LeftHatY) < 124) {
        ppm[1] = map(PS3.getAnalogHat(LeftHatY), 255 , 0, speedMin, speedMax);
      } else {
        ppm[1] = 1500;
      }
    } 
  
// All available PS3 Buttons - placed here for reference      
//    if (PS3.getButtonClick(UP))
//      Serial.println(F("Up"));
//    if (PS3.getButtonClick(DOWN))
//      Serial.println(F("Down"));
//    if (PS3.getButtonClick(LEFT))
//      Serial.println(F("Left"));
//    if (PS3.getButtonClick(RIGHT))
//      Serial.println(F("Right"));
//
//    if (PS3.getButtonClick(SHARE))
//      Serial.println(F("Share"));
//    if (PS3.getButtonClick(OPTIONS))
//      Serial.println(F("Options"));
//    if (PS3.getButtonClick(TOUCHPAD))
//      Serial.println(F("Touchpad"));
//    if (PS3.getButtonClick(PS))
//      Serial.println(F("PS"));
//
//    if (PS3.getButtonClick(L1))
//      Serial.println(F("L1"));
//    if (PS3.getButtonClick(R1))
//      Serial.println(F("R1"));
//    if (PS3.getButtonClick(L2))
//      Serial.println(F("L2"));
//    if (PS3.getButtonClick(R2))
//      Serial.println(F("R2"));
//    if (PS3.getButtonClick(L3))
//      Serial.println(F("L3"));
//    if (PS3.getButtonClick(R3))
//      Serial.println(F("R3"));
//
//
//    if (PS3.getButtonClick(TRIANGLE))
//      Serial.println(F("TRIANGLE"));
//    if (PS3.getButtonClick(CIRCLE))
//      Serial.println(F("CIRCLE"));
//    if (PS3.getButtonClick(CROSS))
//      Serial.println(F("CROSS"));
//    if (PS3.getButtonClick(SQUARE))
//      Serial.println(F("SQUARE"));

//    if (PS3.getAnalogButton(L2) > 0 || PS3.getAnalogButton(R2) > 0) {
//      if (PS3.getAnalogButton(L2) > 0) {
//        Serial.print(F("L2: "));
//        Serial.print(PS3.getAnalogButton(L2));
//        Serial.print("\t");
//      }
//      if (PS3.getAnalogButton(R2) > 0) {
//        Serial.print(F("R2: "));
//        Serial.print(PS3.getAnalogButton(R2));
//        Serial.print("\t");
//      }
//      Serial.println();
//    }
   
  }
    
  if (PS3.PS3Connected == false){
    lcd.setBacklight(RED);
    ppm[1] = 1500; // if controller is disconnected for some reason, throttle gets zeroed
  } else {
    lcd.setBacklight(GREEN);
  }
  
//Uncomment these for debugging if you want to see the ppm value for each channel
//Note: uncommenting these can disrupt the ppm signal so should be re-commented before actual use
//Serial.print("CH1: ");Serial.print(ppm[0]);Serial.print("\t");
//Serial.print("CH2: ");Serial.print(ppm[1]);Serial.print("\t");
//Serial.print("CH3: ");Serial.print(ppm[2]);Serial.print("\t");
//Serial.print("CH4: ");Serial.print(ppm[3]);Serial.print("\t");
//Serial.print("CH5: ");Serial.print(ppm[4]);Serial.print("\t");
//Serial.print("CH6: ");Serial.print(ppm[5]);Serial.print("\t");
//Serial.print("CH7: ");Serial.print(ppm[6]);Serial.print("\t");
//Serial.print("CH8: ");Serial.print(ppm[7]);Serial.print("\n");
//Serial.println(speedSetting);
}

ISR(TIMER1_COMPA_vect){  //leave this alone
  static boolean state = true;
  
  TCNT1 = 0;
  
  if (state) {  //start pulse
    digitalWrite(sigPin, onState);
    OCR1A = PULSE_LENGTH * 2;
    state = false;
  } else{  //end pulse and calculate when to start the next pulse
    static byte cur_chan_numb;
    static unsigned int calc_rest;
  
    digitalWrite(sigPin, !onState);
    state = true;

    if(cur_chan_numb >= CHANNEL_NUMBER){
      cur_chan_numb = 0;
      calc_rest = calc_rest + PULSE_LENGTH;// 
      OCR1A = (FRAME_LENGTH - calc_rest) * 2;
      calc_rest = 0;
    }
    else{
      OCR1A = (ppm[cur_chan_numb] - PULSE_LENGTH) * 2;
      calc_rest = calc_rest + ppm[cur_chan_numb];
      cur_chan_numb++;
    }     
  }
}

// Function to update steering trim setting information on LCD
// Converts steeringTrimLCD from negative and positive numbers to L and R
void steeringTrimRefreshLCD() {
  steeringTrimLCD = map(steeringTrim, -100, 100, -20, 20); // Remap steering trim adjustment to single increments
  if (steeringTrimLCD < 0) {
    steeringTrimLCD = abs(steeringTrimLCD);
    lcd.setCursor(12, 0);
    lcd.print(String(steeringTrimLCD) + "L ");    
  } else if (steeringTrimLCD > 0) {
    lcd.setCursor(12, 0);
    lcd.print(String(steeringTrimLCD) + "R ");
  } else {
    lcd.setCursor(12, 0);
    lcd.print(String(steeringTrimLCD) + "  ");
  }
}

// Function to update Speed setting information on LCD
void speedSettingRefreshLCD() {
  lcd.setCursor(7, 1);
  lcd.print(String(speedSetting));
}

The Quadtick has coding that turns actions into PS3 outputs that are sent to the Arduino, the Arduino reads the inputs, converts them into PPM signals that are sent to the transmitter out of Arduino pin 3.

I cannot find or get a USB host controller to work so I need any type of Arduino that can read input from a USB, be powered by battery, host an LCD screen and send commands to a PPM transmitter.

Hope this helps.

I don't see any information in that video about usb shields

Sorry I posted the 2nd video, the first was linked in the description

The sparkfun board is a good choice.

Thanks @jim-p that should work.

However I am a high level quad and can't use my hands so I will be trying to talk support workers through putting it together and I don't have anyone who is skilled enough to use a soldering iron.

Do you know of one that's already assembled or any boards that have an integrated host controller and capable of pairing with an LCD screen?

Thanks again and sorry for the noob questions.

That is a problem for many DIYers, handicapped or not. Unfortunately many DIY boards for use with Arduino don’t have the headers soldered on.

It seems like a lot of those cheap host shields have a wrong IC on them, so it’s not surprising you had problems.
Sorry but I don’t have any other recommendations.

Thanks anyway @jim-p I was really hoping there would be a board with integrated host that would make the process easier. I'll keep researching I guess.

The forum is international so someone with the answer might be speeping right now.
Give a day

Here maybe...

Yeah I have looked at something like this

But I have looked everywhere and can't find any instructions on how to attach it to the Uno?

What function do you require that the quadstick does not offer? (Quadstick and adaptive gaming link follows)

Also requires you to solder on the headers, so why are you considering it?

Choose one that is easily compatible with the Uno:
https://www.aliexpress.com/w/wholesale-usb-host-shield-arduino-uno-2.0.html
or
https://www.amazon.com/s?k=USB+Host+Shield+V2.0+for+UNO
or more generally:

@xfpd I have 3 Quadsticks and they are amazing but you can't directly control an RC car with one?

@jim-p Yeah at the moment I think I will get everything I need then take the parts to an electronic repair place

@Etienne_74 I have those parts already and they don't work because of the incorrect chip even after the hack found online there still isn't any power supplied

Hacking a part can be (or end up being) more expensive than buying the right one. Make sure it's not the case here...

I got one of these But still haven't gotten around to trying it out. Even my rainy days are busy.

I would guess the RC aircraft world (quadcopter, for example) has this ready to go.

Newer Arduino kit-cars are using bluetooth from a smartphone app for control... the phone is tipped for turning, direction and speed.

I finally found a USB Host with the correct IC chips used so it works now. Now I am having issues with the LCD shield...