Super Lagged / Unresponse Core After Start

Hi,

I have a robot that I am controlling and it receives the first command but then refuses to receive any commands there after. I’m controlling the robot with the arrows via javascript JQUERY DOM. It’s almost like the code isn’t receiving the onclick changes or the core isn’t getting the new messages.

Thanks

Figured it out. But there is still a huge lag time between when the core receives a a new post message.

I’m sitting very close to it and it’s taking about 5 maybe 10 seconds to realize it has a new message. Then it backs it into a queue like state.

post 1 lagged by 10 seconds
post 2 lagged by 20 seconds
… etc

then it runs through everything.

Here’s the code block that’s making these posts

  $('body').on('keydown', function (event) { // whole page onclick
    if (event.keyCode === 40) {
      currentCommand = 'backward';
    }
    // arrow up
    else if (event.keyCode === 38) {
      currentCommand = 'forward';
    }
     // arrow left
    else if (event.keyCode === 37) {
      currentCommand = 'turnleft';
    }
     // arrow right
    else if (event.keyCode === 39) {
      currentCommand = 'turnright';
    }

    // request string
    var requestURL = "https://api.spark.io/v1/devices/" + deviceID + "/" + currentCommand + "/";

            // execution post of request string
    $.post(requestURL, { params: speed, access_token: accessToken });
  });

  
  // like above block but for stopping. whenever I lift up on whatever arrow I have it stops 
  $('body').on('keyup', function () {
    var requestURL = "https://api.spark.io/v1/devices/" + deviceID + "/" + currentCommand + "/";
    $.post( requestURL, { params: 90, access_token: accessToken });
  });

Would you mind also posting the Core code, perhaps some optimisations can be made there?

I hard coded speeds for all functions but the forward one, just to test.

Servo left;  // create servo object to control a servo
Servo right;
#define PIN D7

int leftpin = A0;
int rightpin = A1;
int speedx = 0;
int pos = 90;

void setup()
{

  left.attach(leftpin);  // attaches the servo on the A0 pin to the servo object
  right.attach(rightpin);  // attaches the servo on the A0 pin to the servo object
  
  //speed adjusting forward
  Spark.function("forward", Forward); //setpos // setPosition // original
  //Caluclation Functions for position drive
  
  /*
  Spark.function("setpos", setPosition);
  Spark.variable("getpos", &pos, INT);
  */
  
  //---
  
  //Backward default
  Spark.function("backward", Backward);
  
  Spark.function("turnright", TurnRight);

  Spark.function("turnleft", TurnLeft);
  

  
  //get a variable
  //Spark.variable("getpos", &pos, INT); // "getpos", &pos, INT
  //Spark.variable("getRightSpeed", getrightspeed, INT);
  //LED Function
  //Spark.function("led", ledControl); // registering spark function for led call and fucntion control
  // active pins for LEDs
  //pinMode(led1, OUTPUT);
  //pinMode(led2, OUTPUT);
  
  
  //initialize off
  pinMode(PIN, OUTPUT);

  
}

void loop()
{
    digitalWrite(PIN, HIGH);
    delay(1000);
    digitalWrite(PIN, LOW);
    
}

//example mapping
// no longer needed

/*
int setPosition(String posValue) {
    pos = posValue.toInt();
    //myservo.write(pos); this will do nothing, instead just route pos = speed and call forward function from here! It acts as the gateway!
    return 0;
}
*/

int Forward(String speed){

    //change value to int from string because string can only be passed to function
    speedx = speed.toInt();
    left.write(speedx);
    right.write(speedx);
    return 1;
    
}

int TurnLeft(String speed){
    
    speedx = speed.toInt();
    left.write(70);
    right.write(110);
    return 1;
    
}

int TurnRight(String speed){
    
    speedx = speed.toInt();
    left.write(110);
    right.write(70);
    return 1;
    
}

int Backward(String speed){
    
    speedx = speed.toInt();
    left.write(110); // must be > 90
    right.write(110);
    return 1;
    
}

/*
int ledControl(String command)
{
   int state = 0;
   //find out the pin number and convert the ascii to integer
   int pinNumber = (command.charAt(1) - '0') - 1;
   //Sanity check to see if the pin numbers are within limits
   if (pinNumber < 0 || pinNumber > 1) return -1;

   // find out the state of the led
   if(command.substring(3,7) == "HIGH") state = 1;
   else if(command.substring(3,6) == "LOW") state = 0;
   else return -1;

   // write to the appropriate pin
   digitalWrite(pinNumber, state);
   return 1;
}
*/

Do I need the rest of it with access token as below?

requestURL = “https://api.spark.io/v1/devices/” + deviceID + “/” + getMess + “/?access_token=” + accessToken;
^ this is for a GET request?

I thought that it was passed by the .post line:
$.post( requestURL, { params: 90, access_token: accessToken });

If so, why would that cause a delay?

Here’s the other half, complete jaavscript and html code.

<!DOCTYPE HTML>
<html>
<body>
<!--
 
 best version here

-->

<h1><b>Command App:</b></h1>
      <!-- form here 
        
        We need to map 90 to 30 : 0 mph to 5 mph or 12 pts = 1 mph 6 pts = .5 mph 3 pts = .25 mph 1.5 pts = .125 mph
        We then need to map 0 mph back to 90 - 30 for forward or 90 - 180 for backward function

      -->

      <h3>Set throttle speed</h3>
      <p>30 = top speed forward</p>
      <p>80 = slowest speed forward</p>
      <p>110 = slowest speed backward</p>
      <p>180 = fastest speed backward</p><br>

    <input type="range" name="degBox" id="degBoxId" min="0" max="180" step="1" value="90" list="myData">
    <!-- This adds the tick marks to the range but does not in Safari -->

    <datalist id="myData">

       <option value="0">
       <option value="30">
       <option value="60">
       <option value="90">
       <option value="120">
       <option value="150">
       <option value="180">

    </datalist>

    <br><br>

    <button id="minusbutton">&lArr; -5 &deg;</button>
    <button id="plusbutton">+5 &deg; &rArr;</button>

    <br><br>
    <P>Throttle Speed: <span id="curPos"></span><br>



    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js" type="text/javascript" charset="utf-8"></script>

      <!-- Javascript server side code -->
    <script type="text/javascript">
      //set credentials
      // set functions to call
      var deviceID    = "53ff6e066667574845592267";
      var accessToken = "6d3faea8e2c0d23c4fb78b1ca846c619855010ae";
      var speed = 90; // default speed changed from 40
      var currentCommand = '';


      // USELESS
      var fwd = "forward"; 
      // DONT NEED THESE //
      var tr = "turnright";
      var tl = "turnleft";
      var getFunc = "getpos";
      var setFunc = "setpos";
      // DONT NEED THESE //





/*
        //DEAD LEGACY CODE // 

      window.setInterval(function() {
        requestURL = "https://api.spark.io/v1/devices/" + deviceID + "/" + getFunc + "/?access_token=" + accessToken;

        //Get form values
        $.getJSON(requestURL, function(json) {
                 document.getElementById("curPos").innerHTML = json.result + "&deg;";// this injects curPOS into the span ID!
                 document.getElementById("curPos").style.fontSize = "28px";
                 document.getElementById("degBoxId").value = parseInt(json.result);
                 });
      }, 1500);*/


      $('#degBoxId').val(speed); // sets any ID with degBoxId to value speed
      // If i want to do multiple things use class. i.e. if i have multiple degree boxes and I want to set them. 
      // use class anywhere I want it to be set. 
      //Updates now for first update


      $('body').on('keydown', function (event) { // whole page onclick
        if (event.keyCode === 40) {
          currentCommand = 'backward';
        }
        // arrow up
        else if (event.keyCode === 38) {
          currentCommand = 'forward';
        }
         // arrow left
        else if (event.keyCode === 37) {
          currentCommand = 'turnleft';
        }
         // arrow right
        else if (event.keyCode === 39) {
          currentCommand = 'turnright';
        }

        // request string
        var requestURL = "https://api.spark.io/v1/devices/" + deviceID + "/" + currentCommand + "/";

                // execution post of request string
        $.post(requestURL, { params: speed, access_token: accessToken });
      });


      // like above block but for stopping. whenever I lift up on whatever arrow I have it stops 
      $('body').on('keyup', function () {
        var requestURL = "https://api.spark.io/v1/devices/" + deviceID + "/" + currentCommand + "/";
        $.post( requestURL, { params: 90, access_token: accessToken });
      });



      //whenever the slider changes, it will update the current position by re-assigning speed value
      $('#degBoxId').on('change', function (event) {
        speed = event.target.value;
        $('#curPos').text(speed);//assigns ID #curPos the newly made speed
      });


      // decrementing down with fineAdjust function
      $('#minusbutton').on('click', function (event) {
        fineAdjust(-5);
      });


      // Incrementing 
      $('#plusbutton').on('click', function (event) {
        fineAdjust(5);
      });


      // Used in input form. Gets curPos string element value, changes it to an integer
      function fineAdjust(value) {
        var setValue = speed + value; //adds last value plus this one
        document.getElementById("degBoxId").value = setValue; // set degBoxId element value to setValue DISPLAY
        speed = setValue;
        //sp(setValue); //sets current position
      }



      /*
      //passive function
      function setValue(obj) {
        var newValue = document.getElementById('degBoxId').value; // grabbing element by ID. ID finds element, then extracts the value!
        speed = newValue; // call third function sparkSetpos, this will send the value to fwd . Starts with 90 aka zero
        //Calling sparkSetPos(90);
        document.getElementById("degBoxId").value = newValue;
      }
      */

    </script>
</body>
</html>

I’ve edited your post to properly format the code. Please check out this post, so you know how to do this yourself in the future. Thanks in advance! ~Jordy

This seems all right to me…

Try to do as little as possible inside you functions. Rather, have them set a flag which gets checked for in the main loop. That might improve some things.

OK. You don’t think that there’s a way to optimize even faster? Like, doublerobotics does a good telepresence job, but that’s likely because they have their own special cocktail of hardware, etc?

So I see some familiar code in the commented out parts of your code! That’s great–hope it helped.

I am about 0.125 of seconds from the Spark cloud, so anything I send to cloud and it sends to my core takes at least 0.25 seconds round-trip even if the processing in the cloud and core takes zero time. In reality, anything faster than about one function call per second and one variable read per second starts to have lag problems for me. If you are going to use the public cloud, I don’t think you are going to be able to “spam” the arrow keys as my kids would say. That said, 10 seconds of lag is weird and not explained yet–maybe your core is going off line or has some other long delay bug.

I am sure that this can be improved if you switch to a local cloud setup where the latency can much lower.

Or you could switch to local TCP or UCP connections with your own controller app.

Yes, bko thank you for the code. I’ll definitely research which implementation may be best! Talk soon.

1 Like

I don’t see any logical explanation why it takes so long.
However, I experienced some weird timing errors a while ago and I managed to solve those with creating a delay loop which calls Spark.process(); ( @moors7 suggested that). Perhaps you can give that a shot.

2 Likes

Do you have any examples of the delay loop by chance? or just putting in delay(1000); ?

Yes of course. I’m home in a bit, I will edit this post then with the code. Spark build on mobile is a hell so :wink:

lol ok thank you so much!!

I think your on to something here, bko (where I got my original code from on his servo post) hd a delay timer so that it didn’t flood requests, or something.

1 Like

I think it has something to do with checking the cloud connection which should be done when you call delay() in automatic mode but in my case back then it seemed to fail.

Anyway, be right back :wink:

Edit:

This is the code:

void myDelay(unsigned long duration)
{
    unsigned long start = millis();
    while (millis() - start <= duration)
    {
        Spark.process();
    }
}

@transcendrobotics Replace delay(1000); with myDelay(1000); in your code. Hope this works :smile:

2 Likes

Thanks!!!

in my void loop() ?

void loop()
{
    digitalWrite(PIN, HIGH);
    delay(1000); //<--- Replace here!? I'm doing this because it gives some cushion on function responses each time it runs through? 
    digitalWrite(PIN, LOW);
    
}

Yes replace that line. This acts as a normal delay, the difference here is that the function Spark.process() inside the delay.

OK. Let me try this out!
THANK YOU!

2 Likes

Interestingly enough the standard delay() call does actually call spark.process() every so often. Not every loop like yours does @TheHawk1337 but every X seconds where I’ve forgotten X :stuck_out_tongue:

1 Like