2

I'm trying to create a dead zone so the joystick will turn the motor off completely when in the center position. It's much too sensitive and will start the motor if barely touched. How could I fix the code so the off position of the joystick is bigger? This is the original code.

#include <Servo.h> //Using servo library to control ESC

Servo esc; //Creating a servo class with name as esc

void setup()
{
  esc.attach(9); //Specify the esc signal pin,Here as D9
  esc.writeMicroseconds(1000); //initialize the signal to 1000
  Serial.begin(9600);
}

void loop()
{
  int val; //Creating a variable val
  val = analogRead(A0); //Read input from analog pin a0 and store in val
  val = map(val, 0, 1023, 1000, 2000); //mapping val to minimum and maximum(Change if needed)
  esc.writeMicroseconds(val); //using val as the signal to esc
}
2
  • Please post your code within the code tag for readability. As the compiler error tells you, it appears that your using a variable named 'adc_center' that is not declared. Are you familiar with C++? – Sacha Apr 7 at 7:21
  • When you edit the question, do not remove the tags (```c++ and ```) timemage and I have put around the code. There are there for a reason. – Edgar Bonet Apr 10 at 7:33
1

Here's how to create the new mapped range with a dead zone. I used Servo.write() which specifies the position in degrees because I couldn't understand what microsecond timings you need, but it should be easy to change it back. I've also added some debug statements to print val as the joystick is moved.

#include <Servo.h>

// Constants for servo angles in degrees.
const int SERVO_MIN = 0;
const int SERVO_MID = 90;
const int SERVO_MAX = 180;

// Constants for raw ADC values of joystick positions.
const int ANALOGUE_MIN = 0;
const int ANALOGUE_MID = 512;
const int ANALOGUE_MAX = 1023;
const int ANALOGUE_THRESHOLD = 100;

Servo esc;

void setup()
{
  esc.attach(9);         // Specify the esc signal pin as D9.
  esc.write(SERVO_MID);  // Move servo to mid position in degrees.
  Serial.begin(115200);
  Serial.println();
  Serial.println("Servo Test");
}

void loop()
{
  static int old_val = -1;   // Initialise to invalid value.
  int val = analogRead(A0);  // Read input from analogue pin A0.

  // Process val if it has changed.
  if (val != old_val)
  {
    old_val = val;
    Serial.print(val);
    Serial.print(", ");

    // Create the dead zone as per Majenko's algorithm.
    val -= ANALOGUE_MID;
    int direction = val < 0 ? -1 : +1;
    val = abs(val);
    val -= ANALOGUE_THRESHOLD;
    if (val < 0) val = 0;

    // Create a new mapped range with a dead zone.
    val *= direction;
    val += ANALOGUE_MID;
    Serial.print(val);
    Serial.print(", ");
    val = map(val, ANALOGUE_MIN + ANALOGUE_THRESHOLD, ANALOGUE_MAX - ANALOGUE_THRESHOLD, SERVO_MIN, SERVO_MAX);
    Serial.println(val);

    // Move servo to new angle in degrees.
    esc.write(val);
  }
}
1

Note that in your case, the width of the input range (1023) is only very slightly larger than the width of the output range (1000). You could take this width difference (23) as the dead zone, and this would simplify the arithmetics: now the linear parts of your map have a slope of exactly 1, and you do not need multiplications or divisions.

The map is then:

  • [0, 500] → [1000, 1500] (slope =1)
  • [500, 523] → 1500 (slope = 0)
  • [523, 1023] → [1500, 2000] (slope = 1)

In code:

/*
 * Map:
 *   [  0,  500] -> [1000, 1500]
 *   [500,  523] ->  1500
 *   [523, 1023] -> [1500, 2000]
 */
if (val < 500)
    val = 1000 + val;
else if (val < 523)
    val = 1500;
else
    val = (1500 - 523) + val;
0

My method is to separate the direction from the magnitude:

  • Subtract the "center" value to create a ± range
  • Use the sign to indicate the direction
  • Take the abs to give the magnitude
  • Subtract the "threshold" value
  • If negative set to zero

So, with example values:

int val = analogRead(0);          // Raw value
val -= 512;                       // Subtract center value (512)
int direction = val < 0 ? -1 : 1; // Direction is either -1 or +1
val = abs(val);                   // Remove the sign
val -= 10;                        // Subtract the threshold (10)
if (val < 0) val = 0;             // Anything below zero is now zero
// val is now 0-501 with a dead zone, and direction is -1 or +1.
10
  • Thank you for responding, I tried your modification, now I get an error: 'val' does not name a type. – edrummer Apr 7 at 16:54
  • 1
    Then you must have implemented it wrong. That code snippet compiles perfectly fine when wrapped in a function. – Majenko Apr 7 at 18:52
  • I'm sure I did implement it wrong. Could you show me how to wrap it in a function? I am not a coder. – edrummer Apr 8 at 1:10
  • I got it to compile but now the motor doesn't do anything. Could someone help me with this please? – edrummer Apr 9 at 15:44
  • @edrummer You'll have to edit your question and add an update to it with your new code so that we can see what you have done wrong. – Majenko Apr 9 at 15:49

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.