1

Topic: Slow jerky servo response to slider input

Hi

I am trying to control two servos from sliders on my Android phone and communicating using BLE-HM10.
Everything functions but I have an irritating issue:

The response to my slider input is slow/stuttering. When I smoothly swipe along the Slider on the GUI, the servo moves to the correct position but it does so in jerky steps -just as if their position signal is only being updated at around 3 or 4 Hz. If I swipe slower then the jerkiness is less pronounced (as would be expected from slow updating). It feels like my Arduino code is taking 200ms to 300ms for each loop!

Any ideas? Does RemoteXY just take that long to run each time? Have I got a library with a Delay() in it somewhere?

My code is below -note I also have code to read some thermocouples and report that to my RemoteXY GUI -that all works fine.

//This program allows position control of the servos via RemoteXY client.

#include <Wire.h>
#include <RunningAverage.h>
#include <Servo.h>
#include <SPI.h>                //http://arduino.cc/en/Reference/SPI
#include <Thermocouple.h>         //http://github.com/JChristensen/Thermocouple

//////////////////////////////////////////////
//        RemoteXY include library          //
//////////////////////////////////////////////

// RemoteXY select connection mode and include library 
#define REMOTEXY_MODE__HARDSERIAL

#include <RemoteXY.h>

// RemoteXY connection settings 
#define REMOTEXY_SERIAL Serial
#define REMOTEXY_SERIAL_SPEED 9600


// RemoteXY configurate  
#pragma pack(push, 1)
uint8_t RemoteXY_CONF[] =
  { 255,2,0,24,0,153,0,8,13,0,
  130,1,2,35,96,27,5,67,4,50,
  4,20,5,2,26,6,67,4,50,10,
  20,5,2,26,6,67,4,50,16,20,
  5,2,26,6,67,4,50,22,20,5,
  2,26,6,4,128,68,51,26,6,2,
  26,4,128,3,51,62,6,2,26,129,
  0,9,41,22,6,17,84,104,114,111,
  116,116,108,101,0,129,0,67,42,18,
  6,17,67,104,111,107,101,0,129,0,
  19,4,20,6,17,69,110,103,105,110,
  101,0,129,0,19,10,23,6,17,69,
  120,104,97,117,115,116,0,129,0,19,
  16,28,6,17,87,97,116,101,114,32,
  79,117,116,0,129,0,19,22,23,6,
  17,87,97,116,101,114,32,73,110,0 };
  
// this structure defines all the variables of your control interface 
struct {

    // input variable
  int8_t choke; // =0..100 slider position 
  int8_t throttle; // =0..100 slider position 

    // output variable
  char TempEngine[6];  // string UTF8 end zero 
  char TempExhaust[6];  // string UTF8 end zero 
  char TempWaterOut[6];  // string UTF8 end zero 
  char TempWaterIn[6];  // string UTF8 end zero 

    // other variable
  uint8_t connect_flag;  // =1 if wire connected, else =0 

} RemoteXY;
#pragma pack(pop)

/////////////////////////////////////////////
//           END RemoteXY include          //
///////////////////////////////////////////// 

//MAX6675 SPI pin definitions
#define csTC1 6             //chip select for MAX6675 #1
#define csTC2 7             //chip select for MAX6675 #2
#define csTC3 8             //chip select for MAX6675 #3
//#define csTC4 9             //chip select for MAX6675 #4

//Additionally, connect the MAX6675s as follows:
//MISO  Arduino pin 12          //master in slave out
//SCK   Arduino pin 13          //serial clock

Thermocouple tc_engine = Thermocouple(csTC1);    //instantiate the thermocouple objects
Thermocouple tc_exhaust = Thermocouple(csTC2);
Thermocouple tc_waterin = Thermocouple(csTC3);
//Thermocouple tc_waterout = Thermocouple(csTC4);

float EngineTemp;
float ExhaustTemp;
float WaterInTemp;
float WaterOutTemp;

char EngineTempChar[6];
char ExhaustTempChar[6];
char WaterInTempChar[6];
char WaterOutTempChar[6];

//define Servos
Servo ServoThrottle;
Servo ServoChoke;

//Thermocouple Read Timer
const int read_interval = 500;
unsigned long currentMillis = 0;    // stores the value of millis() in each iteration of loop()
unsigned long previousRead_Millis = 0;

//SETUP--------------------------------------------------------------------------------------------

void setup() 
{
    RemoteXY_Init ();  
    Serial.begin(9600); //initialize Serial
    ServoThrottle.attach(9);
    ServoChoke.attach(10);
    delay (20);
    RemoteXY.throttle = 50;   //sets GUI slider to mid
    RemoteXY.choke = 50;    //sets GUI slider to mid
    }

//LOOP---------------------------------------------------------------------------------------------

void loop()
{
 RemoteXY_Handler (); 
 ServoControl();
 ReadThermo();
 currentMillis = millis();
}

//---------------------------------------------------------------------------------------------  
 void ServoControl()
{
        int ms = RemoteXY.throttle*20+500; 
        ServoThrottle.writeMicroseconds(ms);  
        int ms2 = RemoteXY.choke*20+500; 
        ServoChoke.writeMicroseconds(ms2);  
} 
//---------------------------------------------------------------------------------------------  

void ReadThermo()
{
    if (currentMillis - previousRead_Millis >= read_interval)        //only call when timer runs out
        {
            //read thermocouple temperatures as float
            EngineTemp = tc_engine.readC();
            ExhaustTemp = tc_exhaust.readC();
            WaterInTemp = tc_waterin.readC();
            //WaterOutTemp = tc_waterout.readC();
            
            //send to RemoteXY app
            dtostrf(EngineTemp,3,2,RemoteXY.TempEngine);
            dtostrf(ExhaustTemp,3,2,RemoteXY.TempExhaust);
            dtostrf(WaterInTemp,3,2,RemoteXY.TempWaterIn);
            dtostrf(WaterOutTemp,3,2,RemoteXY.TempWaterOut);
            
            //reset timer
            previousRead_Millis = currentMillis;
        }
}

2

Re: Slow jerky servo response to slider input

I also have that problem, but I was going to fix it later with some sort of filtering or smoothing system yet to be devised.

My problem is more serious, I have four servos attached, 2 controlled by the X/Y axes of a joystick, and two controlled by independent sliders.

I can only get two of these servo controls to work - is there a limit to how many Servo objects you can configure and use simultaneously ??

#include <Servo.h>

//////////////////////////////////////////////
//        RemoteXY include library          //
//////////////////////////////////////////////


// RemoteXY select connection mode and include library 
#define REMOTEXY_MODE__HARDSERIAL

#include <RemoteXY.h>

// RemoteXY connection settings 
#define REMOTEXY_SERIAL Serial
#define REMOTEXY_SERIAL_SPEED 115200


// RemoteXY configurate  
#pragma pack(push, 1)
uint8_t RemoteXY_CONF[] =
  { 255,7,0,0,0,144,0,8,137,0,
  130,1,62,10,36,51,17,4,0,67,
  11,6,47,2,26,4,0,87,11,6,
  47,2,26,4,0,51,11,6,47,204,
  26,1,0,67,2,6,6,246,31,80,
  0,1,0,87,2,6,6,246,31,83,
  0,129,0,18,10,9,4,8,70,87,
  68,0,129,0,18,50,8,4,8,82,
  69,86,0,129,0,1,29,2,4,8,
  76,0,5,0,4,14,35,35,2,26,
  31,129,0,40,30,3,4,8,82,0,
  129,0,47,9,12,4,24,76,105,103,
  104,116,115,0,129,0,77,2,7,3,
  24,72,111,111,107,0,129,0,75,5,
  11,3,24,82,101,108,101,97,115,101,
  0 }; 
  
// this structure defines all the variables of your control interface 
struct {

    // input variable
  int8_t porthopper; // =0..100 slider position 
  int8_t stbdhopper; // =0..100 slider position 
  int8_t lights; // =0..100 slider position 
  uint8_t hkr_a; // =1 if button pressed, else =0 
  uint8_t hkr_b; // =1 if button pressed, else =0 
  int8_t joystick_1_x; // =-100..100 x-coordinate joystick position 
  int8_t joystick_1_y; // =-100..100 y-coordinate joystick position 

    // other variable
  uint8_t connect_flag;  // =1 if wire connected, else =0 

} RemoteXY;
#pragma pack(pop)

/////////////////////////////////////////////
//           END RemoteXY include          //
/////////////////////////////////////////////

// Arduino Pins

// Outputs
#define pin_PortInd     2             // Port Hopper Indicator Light
#define pin_StbdInd     3             // Starboard Hopper Indicator Light
#define pin_PortServo   5             // Port Hopper Servo (Servo)
#define pin_StbdServo   6             // Starboard Hopper Servo (Servo)
#define pin_THR_Servo   9             // Speed Controller (Servo)
#define pin_RUD_Servo   10            // Rudder (Servo)
#define pin_PortSol     7             // Port Release Solenoid
#define pin_StbdSol     4             // Starboard Release Solenoid
#define pin_Lights      11            // Dimmable Lights (PWM)

// Inputs
#define pin_batt_mon    A7            // battery level monitor

// create the servo objects
Servo srv_PortHopper;
Servo srv_StbdHopper;
Servo srv_Throttle;
Servo srv_Rudder;

// declare variables
// battery monitoring parameters
int batt_min = 550;               // battery low voltage

// PWM : Servo parameters
int Servo_Min = 1000;          // 1000 mS
int Servo_Max = 2000;          // 2000 mS

// PWM : Analog Write parameters
int PWM_Min = 0;            // Min
int PWM_Max = 255;          // MaX

// LED blink parameters
int blinkFast = 100;
int blinkSlow = 600;

// bait release memory flags
bool PortRelease = false;
bool StbdRelease = false;



void setup() 
{
  RemoteXY_Init (); 
  
  pinMode (pin_PortSol, OUTPUT);
  pinMode (pin_StbdSol, OUTPUT);
  pinMode (pin_PortInd, OUTPUT);
  pinMode (pin_StbdInd, OUTPUT);
  pinMode (pin_THR_Servo, OUTPUT);
  pinMode (pin_RUD_Servo, OUTPUT);
  pinMode (pin_PortServo, OUTPUT);
  pinMode (pin_StbdServo, OUTPUT);

  Serial.begin(115200);                   // connect to the serial port

  digitalWrite(pin_PortSol, LOW);
  digitalWrite(pin_StbdSol, LOW);
  digitalWrite(pin_PortInd, LOW);
  digitalWrite(pin_StbdInd, LOW);

  // attach our Hopper Servos to the Output pins
  srv_PortHopper.attach(pin_PortServo, Servo_Min, Servo_Max);
  srv_StbdHopper.attach(pin_StbdServo, Servo_Min, Servo_Max);
  srv_Throttle.attach(pin_THR_Servo, Servo_Min, Servo_Max);
  srv_StbdHopper.attach(pin_RUD_Servo, Servo_Min, Servo_Max);

  
  // TODO you setup code
  
}

void loop() 
{ 
  RemoteXY_Handler ();
  
  digitalWrite(pin_PortSol, (RemoteXY.hkr_a==0)?LOW:HIGH);
  digitalWrite(pin_StbdSol, (RemoteXY.hkr_b==0)?LOW:HIGH);
  
// Servo controls

  srv_PortHopper.writeMicroseconds(map(RemoteXY.porthopper, 0, 100, Servo_Min, Servo_Max));  
  srv_StbdHopper.writeMicroseconds(map(RemoteXY.stbdhopper, 0, 100, Servo_Min, Servo_Max));
  srv_Throttle.writeMicroseconds(map(RemoteXY.joystick_1_y, -100, 100, Servo_Min, Servo_Max));
  srv_Rudder.writeMicroseconds(map(RemoteXY.joystick_1_x, -100, 100, Servo_Min, Servo_Max));

  
  int L_PWM = map(RemoteXY.lights, 0, 100, PWM_Min, PWM_Max);
  if (L_PWM < 10) L_PWM = 0;
  if (L_PWM >255) L_PWM = 255;
  analogWrite(pin_Lights, L_PWM);

}
2B, or not 2B, that is the pencil ...

3

Re: Slow jerky servo response to slider input

Sorry I forgot to post back when I solved the issue days ago.

You can see in my original code post I had

  // attach our Hopper Servos to the Output pins
  srv_PortHopper.attach(pin_PortServo, Servo_Min, Servo_Max);
  srv_StbdHopper.attach(pin_StbdServo, Servo_Min, Servo_Max);
  srv_Throttle.attach(pin_THR_Servo, Servo_Min, Servo_Max);
  srv_StbdHopper.attach(pin_RUD_Servo, Servo_Min, Servo_Max);

I had mistakenly put StbdHopper (in red) when it should have been "Rudder", it so obviously was a mistake....

Isn't it amazing how you can miss something as stupid as this, no matter how many times you read the code ....

2B, or not 2B, that is the pencil ...

4 (edited by Daba 2018-05-13 16:49:00)

Re: Slow jerky servo response to slider input

I have got my project all coded now, and I am also having trouble with jerky response from the slider and joystick controls.

My Arduino sketch executes in 750 uS, so that is not the reason for the poor response.

The problem lies in the data transmission rate from the phone (in my case) to the BLE module.

The block of data from the phone takes (on my project) 1.4 mS, but then there is a delay of a whopping 113 mS before the block is sent again.   Most of the time the data transfer is not taking place at all, which means that the analog values of controls will only update at best, about 8 times a second. 

But that does not explain the jerkiness I get, and it looks to me that the interface alternates between digital, and analog data, which might explain the "4 times a second" update I am seeing on my servo movements.  Certainly the data block "pulses" dance in time with my servo jerks.....

I am going to look into the library file, to see if there is a setting for the data update rate.

UPDATE : No, it looks as though the data transmission interval is set in the Phone App, since that is what occurs first every 112mS, so there's not a lot we can do about it, except to push for a configuration option that we can tweak for our projects.

FURTHER UPDATE : I have just measured, and captured, waveforms that show that joystick (and presumably slider) data is transmitted at somewhere near 500mS intervals!!!. I have put the picture on DropBox if you want to have a look at it.

https://www.dropbox.com/s/bwzl9wpf1rytp … k.bmp?dl=0

The image was grabbed while I was throwing the joystick in all directions continuously, the thicker blue traces are the joystick data blocks being received by the BLE module - the cursors measure the time gap between those thick blocks - 522 mS !!   I really think it is not good enough to update slider and joystick data only twice a second....!!

AND YET ANOTHER UPDATE : I have just tested the project with a proper motor ESC, and it obviously does not like the "step" changes in throttle setting, only working occasionally. Unless the issue is fixed somehow, I will not be able to use RemoteXY on this project !!!

2B, or not 2B, that is the pencil ...