Control Servo with USB Host Shield (XBOX controller)

Hello,

I am using an XBOX360 controller connected to an USB Host Shield to try and control a servo.

However, whenever I use:

if (Usb.Init() == -1) {
  Serial.print(F("\r\nOSC did not start"));
  while (1);
}

it appears as if the function

myservo.writeMicroseconds(ms_min);

does not work anymore (servo is not moving).

When I use writeMicroseconds without the initialization of the USB, then the servo does work.

I assume that you USB does not start properly, so that your code ends up in while(1). Remove that line, and your servo will work again.

Thank you for the reply.

Everything that I put after the initialization does work, except for the writemicroseconds.

So I can see the input of the XBOX controller (for example when moving the sticks), and can see the value of ms_min change.
However, it seems that it does not give this ms_min as input to the servo.
When I remove the initialization, I can give the ms_min as input to the servo (for example a static value or sinusoidal signal).

Post you complete code.

...R

#include <Servo.h>
#include <XBOXRECV.h>

#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif

// Control servo variables
Servo myservo;
const int ms_min = 1000; // minimum [ms] sent to servo   
const int ms_max = 2100; // maximum [ms] sent to servo

// Timing constants
unsigned long NewTick;         // [ms] time start of current loop
unsigned long LastTick;        // [ms] time start of previous loop
float dt;                      // [ms] time between consecutive loops
float interval_constant = 20;  // [ms] per signal send
int count_setup = 20;          // [s] setup time

// Servo constants
int ms_input = ms_min;

// Xbox controller variables
int Hat_tol = 5000;        // Tolerance on when the Xbox controller responds to input LeftHatY
float throttle_analog;     // Value received from input LeftHatY
float throttle;            // 0-1, gives rate of minimum to maximum input LeftHatY
int k = 0;                 // Variable to trigger 'Controller connected' message.
USB Usb;
XBOXRECV Xbox(&Usb);

float ms_float = (float) ms_min;       // [ms] calculated from Xbox Controller input (float)
int ms_int = ms_min;                   // [ms] calculated from Xbox Controller input (integer)

void setup() {
  Serial.begin(9600);
  while (!Serial);     // Wait for serial port to connect
  
  // Give user time to connect ESC to Arduino board
  Serial.print("\n\n   Program started, connect ESC to motor ("); Serial.print(count_setup);  Serial.println(" seconds)");
  for (uint8_t ii = count_setup; ii > 0; ii--) {
  Serial.print(ii); Serial.println(". "); delay(1000);
  }
  
  // ESC calibration and attach Servo to pin 9
  Serial.println("ESC calibration started");
  myservo.attach(9);   
  esc();
  Serial.println("ESC calibration completed"); 
  Serial.println(" ");
  
  // USB initialization
  Serial.println("Start USB Init"); 
  Serial.println(" ");
  if (Usb.Init() == -1) {
    Serial.print(F("\r\nOSC did not start"));
    while (1);
  }
  Serial.println("USB Init complete");
  
  Serial.println("Connect controller (3 seconds)");
  delay(3000);
}


void esc() 
{
  delay(5000);
  Serial.println("Sending lowest throttle ms_min");
  myservo.writeMicroseconds(ms_min);
  delay(2000);
  Serial.println("Low throttle sent");
}


void loop() {

  NewTick = millis();

  dt = NewTick - LastTick;

  if (dt > 50) {

    ms_input = Define_input();    //Retrieve input servo from XboxController
    
    myservo.writeMicroseconds(ms_input);    //Send input to servo

    LastTick = NewTick;
  }
  
  // Output to Serial to see values
  Serial.print(NewTick);
  Serial.print(",");
  Serial.print(ms_input);
  Serial.println("");
}


// Check input of Xbox controller
int Define_input()
{
  throttle = 0;  //Set throttle to 0, so that if no input is found, no throttle (ms_min) is sent
  
  Usb.Task();    //Polls connected usb devices for updates to their status
  if (Xbox.XboxReceiverConnected) {
    
    if (Xbox.Xbox360Connected[0]) {
      
      if (k==0){  //Print to Serial whenever the controller is connected
        Serial.println("Controller connected!");
        k = 1;
      }
      
      if (Xbox.getAnalogHat(LeftHatY, 0) > Hat_tol) {    //If value of LeftHatY is larger than tolerance 'Hat_tol'
        throttle_analog = Xbox.getAnalogHat(LeftHatY, 0);
        throttle = (throttle_analog - Hat_tol) / (32767 - Hat_tol);    // Calculate the throttle (0 - 1)
      }
    }
  }
  
  ms_float = ms_min+(ms_max-ms_min)*throttle;  // Calculate the input servo [ms] from throttle.
            
  ms_int = (int) ms_float;                     //Convert input servo from float to integer
  return ms_int;
}

Can anyone help with this problem?

I don't know the answer but maybe it would help if you put XBOX in your title. Edit your original post and you can change the title.

Have patience. Remember that other parts of the world are in bed.

...R

Still stuck unfortunately.

Anyone here that can help?

Tieske90:
Still stuck unfortunately.

Anyone here that can help?

Why did you not edit your Title as I suggested. There may be people with XBOX knowledge who have not bothered to look at your Thread.

...R

I have a theory on this, but I do not have the resources available to test it. Would you mind testing with a few minor adjustments to your code?

#include <Servo.h>
#include <XBOXRECV.h>

#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif

// Control servo variables
Servo myservo;
const int ms_min = 1000; // minimum [ms] sent to servo   
const int ms_max = 2100; // maximum [ms] sent to servo

// Timing constants
unsigned long NewTick;         // [ms] time start of current loop
unsigned long LastTick;        // [ms] time start of previous loop
float dt;                      // [ms] time between consecutive loops
float interval_constant = 20;  // [ms] per signal send
int count_setup = 20;          // [s] setup time

// Servo constants
int ms_input = ms_min;

// Xbox controller variables
int Hat_tol = 5000;        // Tolerance on when the Xbox controller responds to input LeftHatY
float throttle_analog;     // Value received from input LeftHatY
float throttle;            // 0-1, gives rate of minimum to maximum input LeftHatY
int k = 0;                 // Variable to trigger 'Controller connected' message.
USB Usb;
XBOXRECV Xbox(&Usb);

float ms_float = (float) ms_min;       // [ms] calculated from Xbox Controller input (float)
int ms_int = ms_min;                   // [ms] calculated from Xbox Controller input (integer)

void setup() {
  Serial.begin(9600);
  while (!Serial);     // Wait for serial port to connect
 
  // Give user time to connect ESC to Arduino board
  Serial.print("\n\n   Program started, connect ESC to motor ("); Serial.print(count_setup);  Serial.println(" seconds)");
  for (uint8_t ii = count_setup; ii > 0; ii--) {
  Serial.print(ii); Serial.println(". "); delay(1000);
  }
 
  // ESC calibration and attach Servo to pin 9
  Serial.println("ESC calibration started");
  //myservo.attach(9);   
  esc();
  Serial.println("ESC calibration completed");
  Serial.println(" ");
 
  // USB initialization
  Serial.println("Start USB Init");
  Serial.println(" ");
  if (Usb.Init() == -1) {
    Serial.print(F("\r\nOSC did not start"));
    while (1);
  }
  Serial.println("USB Init complete");
 
  Serial.println("Connect controller (3 seconds)");
  delay(3000);
}


void esc()
{
  delay(5000);
  Serial.println("Sending lowest throttle ms_min");
  myservo.writeMicroseconds(ms_min);
  delay(2000);
  Serial.println("Low throttle sent");
}


void loop() {

  NewTick = millis();

  dt = NewTick - LastTick;

  if (dt > 50) {

    ms_input = Define_input();    //Retrieve input servo from XboxController
   
    //myservo.writeMicroseconds(ms_input);    //Send input to servo
    digitalWrite(9,HIGH);
    delay(ms_input);
    digitalWrite(9,LOW);

    LastTick = NewTick;
  }
 
  // Output to Serial to see values
  Serial.print(NewTick);
  Serial.print(",");
  Serial.print(ms_input);
  Serial.println("");
}


// Check input of Xbox controller
int Define_input()
{
  throttle = 0;  //Set throttle to 0, so that if no input is found, no throttle (ms_min) is sent
 
  Usb.Task();    //Polls connected usb devices for updates to their status
  if (Xbox.XboxReceiverConnected) {
   
    if (Xbox.Xbox360Connected[0]) {
     
      if (k==0){  //Print to Serial whenever the controller is connected
        Serial.println("Controller connected!");
        k = 1;
      }
     
      if (Xbox.getAnalogHat(LeftHatY, 0) > Hat_tol) {    //If value of LeftHatY is larger than tolerance 'Hat_tol'
        throttle_analog = Xbox.getAnalogHat(LeftHatY, 0);
        throttle = (throttle_analog - Hat_tol) / (32767 - Hat_tol);    // Calculate the throttle (0 - 1)
      }
    }
  }
 
  ms_float = ms_min+(ms_max-ms_min)*throttle;  // Calculate the input servo [ms] from throttle.
           
  ms_int = (int) ms_float;                     //Convert input servo from float to integer
  return ms_int;
}

Thank you for the replies.

@Robin2: I have changed the title? Or am I doing it wrong :confused: ?
It did not have the '(XBOX controller)' in the title before.

@BH72: I will test the new code when I get home after work, and post feedback here.

Kind regards,

Tieske90:
@Robin2: I have changed the title? Or am I doing it wrong
It did not have the '(XBOX controller)' in the title before.

What you have done is what I had in mind.

...R

@BH72: Unfortunately this does not work.

Already the initialisation of the ESC does not work, because

if (Usb.Init() == -1) {
  Serial.print(F("\r\nOSC did not start"));
  while (1);
}

ran before the function

myservo.writeMicroseconds(ms_min);

Therefore, unfortunately the change you made to the loop did not change the result.

Are you continuously getting the "did not start" message?.

What i did witht the chqnge of code above (and i missed the void esc() part, my appologies) was attempt to eliminate use of servo.write or servi.writeMicroseconds. My goal in this was to determine if the USB library (which XBOXRECV.h is part of) is killing interrupts which would make servo library functions unuseable. If you wanted to try again you could modify void esc() to operate the same way as the changes I made in loop (sorry typing from phone so can't really paste code).

I am not getting the "did not start" message.

I am using the code from your post, and changed the void esc() to the following:

void esc()
{
  delay(5000);
  Serial.println("Sending lowest throttle ms_min");
  //myservo.writeMicroseconds(ms_min);
  
  digitalWrite(9,HIGH);
  delay(1000);
  digitalWrite(9,LOW);
  
  delay(2000);
  Serial.println("Low throttle sent");
}

A screenshot of the output that I get is attached.

Still no output is sent to the servo as far as I can tell (servo does not calibrate, beeping continues).

Kind regards,

Ok one my try on this...

#include <Servo.h>
#include <XBOXRECV.h>

#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif

// Control servo variables
Servo myservo;
const int ms_min = 1000; // minimum [ms] sent to servo   
const int ms_max = 2100; // maximum [ms] sent to servo

// Timing constants
unsigned long NewTick;         // [ms] time start of current loop
unsigned long LastTick;        // [ms] time start of previous loop
float dt;                      // [ms] time between consecutive loops
float interval_constant = 20;  // [ms] per signal send
int count_setup = 20;          // [s] setup time

// Servo constants
int ms_input = ms_min;

// Xbox controller variables
int Hat_tol = 5000;        // Tolerance on when the Xbox controller responds to input LeftHatY
float throttle_analog;     // Value received from input LeftHatY
float throttle;            // 0-1, gives rate of minimum to maximum input LeftHatY
int k = 0;                 // Variable to trigger 'Controller connected' message.
USB Usb;
XBOXRECV Xbox(&Usb);

float ms_float = (float) ms_min;       // [ms] calculated from Xbox Controller input (float)
int ms_int = ms_min;                   // [ms] calculated from Xbox Controller input (integer)

void setup() {
  Serial.begin(9600);
  while (!Serial);     // Wait for serial port to connect
 
  // Give user time to connect ESC to Arduino board
  Serial.print("\n\n   Program started, connect ESC to motor ("); Serial.print(count_setup);  Serial.println(" seconds)");
  for (uint8_t ii = count_setup; ii > 0; ii--) {
  Serial.print(ii); Serial.println(". "); delay(1000);
  }
 
  // ESC calibration and attach Servo to pin 9
  Serial.println("ESC calibration started");
  //myservo.attach(9);   
  esc();
  Serial.println("ESC calibration completed");
  Serial.println(" ");
 
  // USB initialization
  Serial.println("Start USB Init");
  Serial.println(" ");
  if (Usb.Init() == -1) {
    Serial.print(F("\r\nOSC did not start"));
    while (1);
  }
  Serial.println("USB Init complete");
 
  Serial.println("Connect controller (3 seconds)");
  delay(3000);
}

void loop() {

  NewTick = millis();

  dt = NewTick - LastTick;

  if (dt > 50) {

    ms_input = Define_input();    //Retrieve input servo from XboxController
   
    //myservo.writeMicroseconds(ms_input);    //Send input to servo
    digitalWrite(9,HIGH);
    delayMicroseconds(ms_input);
    digitalWrite(9,LOW);

    LastTick = NewTick;
  }
 
  // Output to Serial to see values
  Serial.print(NewTick);
  Serial.print(",");
  Serial.print(ms_input);
  Serial.println("");
}


// Check input of Xbox controller
int Define_input()
{
  throttle = 0;  //Set throttle to 0, so that if no input is found, no throttle (ms_min) is sent
 
  Usb.Task();    //Polls connected usb devices for updates to their status
  if (Xbox.XboxReceiverConnected) {
   
    if (Xbox.Xbox360Connected[0]) {
     
      if (k==0){  //Print to Serial whenever the controller is connected
        Serial.println("Controller connected!");
        k = 1;
      }
     
      if (Xbox.getAnalogHat(LeftHatY, 0) > Hat_tol) {    //If value of LeftHatY is larger than tolerance 'Hat_tol'
        throttle_analog = Xbox.getAnalogHat(LeftHatY, 0);
        throttle = (throttle_analog - Hat_tol) / (32767 - Hat_tol);    // Calculate the throttle (0 - 1)
      }
    }
  }
 
  ms_float = ms_min+(ms_max-ms_min)*throttle;  // Calculate the input servo [ms] from throttle.
           
  ms_int = (int) ms_float;                     //Convert input servo from float to integer
  return ms_int;
}

void esc()
{
  delay(5000);
  Serial.println("Sending lowest throttle ms_min");
  //myservo.writeMicroseconds(ms_min);
  for (int calibrationCount = 0; calibrationCount < 150; calibrationCount++)
  {
    digitalWrite(9, HIGH);
    delayMicroseconds(1000);
    digitalWrite(9, LOW);
    delayMicroseconds(19000);
  }

  Serial.println("Low throttle sent");
}

I changed esc() so it will loop for roughly 3 seconds while sending 1ms pulse (1000 microseconds). How long it actually needs to be held low throttle depends on your particular ESC, but I think 3 seconds should be long enough to get most ESCs to arm, if you need to change the time it takes to arm just change "calibrationCount < 150" in esc(), the way I figure this is it should loop 50ish times per second (servo specification is roughly 1-2ms high pulse total frame width of 20ms, so 50hz, so 150 loops equals 3 seconds).

Also I changed the delay(ms_input) in loop to delayMicroseconds(ms_input), it should have been that way in the first place, my head just was not attached correctly that day it would appear.

Thank you very much again for the response.
Will test this first thing when I get home from work.

Kind regards,

Just tested the new code.

The ESC initialization does not work.
Again the beeping continues (so no calibration sound).

Kind regards,

Anyone knows where I can also ask this question with a higher chance of someone reading it who can help me with the problem (forums, website, etc.)?

no?