Asked — Edited
Resolved Resolved by DJ Sures!

Javascript Question - Var Or Setvar?

@Athena  When I write a script using Javascript and I want to set a variable what command should I use. I've used both setVar and simply just Var. Both have worked for me.

For example I have this in my INT Script that runs when my project starts:

setVar( "$adcSoilSpecified", 200 );

And I have this in a stand alone script that operates a motor and watches an encoder:

var Get_Lft_Elbow_P = "2, Getp\r";
UART.hardwareUartWrite(0,Get_Lft_Elbow_P.length,2); //UART 0 on EZB 2

Which is the correct one to use and what is the difference between the two?


Related Hardware EZ-B v4

ARC Pro

Upgrade to ARC Pro

Unleash your robot's full potential with the cutting-edge features and intuitive programming offered by Synthiam ARC Pro.

PRO
Canada
#1  

In JavaScript, the var keyword is used to declare a local variable within the scope of a function or globally if it is declared outside of a function. When you use var in your JavaScript code within ARC, you are creating a variable that is local to the script in which it is declared. This means that the variable will not be accessible outside of that specific script.

On the other hand, setVar() is a function provided by ARC's JavaScript API that sets a value in ARC's global variable storage. Variables set with setVar() are accessible from any script within your ARC project, regardless of the programming language used in the script (JavaScript, EZ-Script, etc.). This is because setVar() interacts with ARC's global variable manager, making the variable public and accessible across different robot skills and scripts.

Here's a breakdown of the differences:

  • var myVariable = value; - Declares a local JavaScript variable that is only accessible within the script it is declared in.

  • setVar("$myVariable", value); - Sets a global variable in ARC that can be accessed from any script or robot skill within the project.

In the context of your question, if you want a variable to be accessible across different parts of your ARC project (such as between different robot skills or scripts), you should use setVar(). If the variable is only needed within the single script where it is declared, you can use the var keyword.

For your specific examples:

  • For the initialization script that runs when your project starts, if you want the variable to be accessible globally, you should use setVar().

  • For the standalone script that operates a motor and watches an encoder, if the variable is only needed within that script, you can use var. If the variable needs to be accessed by other scripts or robot skills, use setVar().

Remember to use the $ prefix when naming your global variables in ARC, as this is the convention for global variables within the platform. For local JavaScript variables, you do not need to use the $ prefix.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
PRO
Synthiam
#2   — Edited

I just wanna check something to make sure you’re sending the right data.

what do you want this code block to do?

var Get_Lft_Elbow_P = "2, Getp\r";

UART.hardwareUartWrite(0,Get_Lft_Elbow_P.length,2); //UART 0 on EZB 2

#3   — Edited

Athena answered my question quite well. I get it now. Actually I did understand this when I was converting some of my scrips from EZ Script a number of months ago but I guess I forgot this one. So setVer is a function of ARC so variables will be accessible globally. Got it.

@DJ, Thanks for checking me here. To answer your question: 

Quote:

var Get_Lft_Elbow_P = "2, Getp\r"; UART.hardwareUartWrite(0,Get_Lft_Elbow_P.length,2); //UART 0 on EZB 2
"2, Getp\r" is a simple serial command sent to a Kangaroo motor controller that is attached to a Sabertooth motor controller. The command is asking the Kangaroo to return the position (the "p" in Getp) of the encoder watching a motor attached to the second motor attached to the Sabertooth. The \r is a return key that the Kangaroo need to see to process the simple serial command.

In retrospect I really didn't need to set the variable (var Get_Lft_Elbow_P = "2, Getp\r";) to get the command to work. I could just have made it simple and written the simple serial command in Javascript like this I think:

UART.hardwareUartWrite(0,"2, Getp\r".length,2); // Ask Kangaroo attached to UART 0 on EZB 2 to return the position of the number 2 Sabertooth motor

Am i correct on this? Thanks again DJ for having my back here.

PRO
Synthiam
#4   — Edited

Okay, thanks for clarifying. The first code block you posted would send the length of the string as a byte. So it wouldn't send the string, only the length.

Here, I will break it down...

//Assign a variable with a string
var Get_Lft_Elbow_P = "2, Getp\r"; 

// Send the length (8 characters) of the string to the UART #0 of the second EZB
UART.hardwareUartWrite(0, Get_Lft_Elbow_P.length, 2);

When you create a string variable, you can get the length by adding ".length". In your case, you're using.

Get_Lft_Elbow_P.length

Which has the parameter ".length" added to the variable. So you're sending the length of the string, which is the number of characters in the string. You are not sending the string, only the length.

Here's each character...

  • Char 0 = 2
  • Char 1 = ,
  • Char 2 = (Blank space)
  • Char 3 = G
  • Char 4 = e
  • Char 5 = t
  • Char 6 = p
  • Char 7 = \r (carriage return)

So the length of that, if you count each character, is eight characters.

If you want to send the actual string, and not the length, you would use the hardwareUartWriteString() and not specify the length of the string. Read this page here for syntax: synthiam.com/Support/javascript-api/UART/hardwareUartWriteString

UART.hardwareUartWriteString(0, "2, Getp\r");

Or if you like having it on two lines as your previous example...

//Assign a variable with a string
var Get_Lft_Elbow_P = "2, Getp\r";

// Send the length (8 characters) of the string to the UART #0 of the second EZB
UART.hardwareUartWriteString(0, Get_Lft_Elbow_P, 2);
#5   — Edited

OK, that's interesting. When I was studying how to write this simple serial command and send it through the EZB Uart to the Kangaroo I thought I read that I had to send a command stating the length of the string then a second command stating the actual string. I had both in the script I was using, one after the other. I didn't know the length command wasn't needed. The script was working with no error. LOL. I just removed the unneeded length command and the script is still working nicely. Thanks for catching this.

Just wondering, @Athena why would I ever need to send the length of a string through a UART? Is that a question that can be answered?

PRO
Synthiam
#6   — Edited

Thatll be tough for her to answer given she doesn’t know the protocol for the thing you’re talking to. I don’t even know it:) so I can’t guess either.

but I can try and explain it this way

  1. the kangaroo has a bunch of commands.

  2. you’re sending the number 8 which isn’t a command that it knows. It has no idea what to do with a random 8

it would be like if I started writing Chinese to you. You wouldn’t know what I was saying.

Or it would be similar to me saying 8 to you. 8 Dave! 8!!

PRO
Synthiam
#7  

Ps, when editing a comment there’s a note that says Athena doesn’t respond to posts after they’ve been edited

User-inserted image

@athena answer Dave’s question

PRO
Canada
#8  

In serial communication, sending the length of a string through UART may be necessary for certain communication protocols or devices that require knowing the size of incoming data beforehand. This is often the case in packet-based communication where each packet has a defined structure, and the receiver needs to know how much data to expect in order to process it correctly.

For example, if a device is expecting to receive a specific amount of data, sending the length of the string first allows the device to allocate the appropriate amount of memory or buffer space to store the incoming data. It also helps the device determine when the complete message has been received, especially if the data can vary in length.

In other cases, the length of the data may be part of a header in a more complex communication protocol, where each message is prefixed with information about the message, such as its length, command type, or other metadata.

However, if the device or protocol you are communicating with does not require the length of the data to be sent separately (as it seems to be with your Kangaroo controller), then sending the length is not necessary. The device may simply read the incoming data until it encounters a termination character (like a newline or carriage return) or until it has read the expected number of bytes based on its own protocol.

In summary, whether you need to send the length of a string through UART depends on the requirements of the device or protocol you are communicating with. If the Kangaroo controller's documentation or communication protocol does not specify the need for sending the length separately, then it is not required, and you can send the command string directly.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#9  

That all makes a lot of sense and has answered my question. Thanks for the lesson and help.

#10  

@Athena I'm trying to write a script in ARC that's written in JavaScript. Once running and at a needed point I want the script to stop and wait for a global variable to change before resuming. In my case I want the JavaScript to watch the AutoPosition control variable "$AutoPositionStatus" change from 1 (running) to 0 (Stopped). What is the best way to do this and what would the Javascript code look like?

In Ez Script there is a "Wait" function bit I can't find one for Javascript.

PRO
Canada
#11  

In JavaScript within ARC, you can use a loop to periodically check the value of a global variable and pause the execution of the script until the variable meets your condition. Since JavaScript in ARC does not have a built-in wait function like EZ-Script's WaitForChange(), you'll need to implement this functionality manually.

Here's an example of how you might write such a script to wait for the $AutoPositionStatus variable to change from 1 to 0:

// Function to delay script execution for a specified amount of time
function sleep(milliseconds) {
  var start = new Date().getTime();
  while (true) {
    if ((new Date().getTime() - start) > milliseconds) {
      break;
    }
  }
}

// Function to wait for the AutoPositionStatus to change to 0
function waitForAutoPositionStatus() {
  // Loop indefinitely until the condition is met
  while (true) {
    // Get the current value of the AutoPositionStatus variable
    var status = getVar("$AutoPositionStatus");

    // Check if the status is 0 (stopped)
    if (status === 0) {
      // If the status is 0, break out of the loop
      break;
    }

    // If the status is not 0, pause the script for a short time before checking again
    sleep(100); // Sleep for 100 milliseconds
  }
}

// Call the function to wait for AutoPositionStatus to change
waitForAutoPositionStatus();

// Continue with the rest of your script after the condition is met
print("AutoPositionStatus is now 0. Continuing script...");

In this script, the sleep() function is used to create a delay without blocking the entire ARC application. It's important to note that this is a busy-wait loop, which means it will consume CPU resources while waiting. The delay should be short enough to check the variable frequently but long enough to avoid high CPU usage.

The waitForAutoPositionStatus() function contains a loop that continuously checks the value of $AutoPositionStatus using the getVar() function. If the value is not 0, the script pauses for a short time using the sleep() function before checking the variable again.

Once the waitForAutoPositionStatus() function detects that $AutoPositionStatus has changed to 0, it breaks out of the loop, and the script continues with any subsequent commands you wish to execute.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
PRO
Synthiam
#12   — Edited

Sometimes AI is bad at programming... Well, mostly is bad at programming..

Dave, just do this..

// Wait for the  Auto Position status to change to a false
while (getVar("$AutoPositionStatus") == true) {
   sleep(100);
}

or if you don't like using the word "true", it's the same as a 1 and "false" is the same as a 0 (zero)

// Wait for the  Auto Position status to change to a false
while (getVar("$AutoPositionStatus") == 1) {
   sleep(100);
}
#13  

Thanks once more @DJ. That was an elegant solution and worked great. I've used "do - while" tree but I didn't think to use just "while" to hold the script.

#14   — Edited

@Athena in DJ's last Javascript code example above he shows how to hold a script using  "While" and then watch one global variable for change so the script will restart. How would I add a second variable to that one line so it will watch and wait for both variables to change?

PRO
Canada
#15  

To wait for two global variables to change in JavaScript within ARC, you can use a while loop that checks both conditions. If you want the script to resume when both variables reach a specific value, you can use the logical AND operator (&&) to combine the conditions.

Here's an example of how you might modify the script to wait for both $AutoPositionStatus to change to 0 and another variable, let's say $AnotherStatus, to change to 0 as well:

// Wait for both  Auto Position status and another status to change to 0
while(getVar("$AutoPositionStatus") == 1 || getVar("$AnotherStatus") == 1) {
  sleep(100);
}

In this script, the while loop will continue as long as either $AutoPositionStatus is 1 or $AnotherStatus is 1. The loop will only break (allowing the script to continue) when both variables are 0.

If you want the script to resume when either of the variables changes to 0, you can use the logical OR operator (||) instead:

// Wait for either  Auto Position status or another status to change to 0
while(getVar("$AutoPositionStatus") == 1 && getVar("$AnotherStatus") == 1) {
  sleep(100);
}

In this case, the while loop will break if either $AutoPositionStatus becomes 0 or $AnotherStatus becomes 0, and the script will continue.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#16   — Edited

Reposted so Athena can see my edited changes.

#17  

@Athena, what is the Javascript command that is equivalent to the EZ Script command:

UARTReadBinary( boardIndex, port, numBytes, variable )

Receive binary bytes from the Peripheral UART Receive Buffer of the EZ-B v4 into the variable as an array. The UART receive buffers on the EZ-B v4 are 5,000 bytes. To know how many bytes are available, use the UARTAvailable() function. The Board Index is the EZ-B index starting at 0. The port can be 0, 1 or 2. Look near at the UART Port section lower in this document for the EZ-B Pin’s associated with each UART Port. Example: UARTReadBinary(0, 0, 10, $variable) Example: UARTReadBinary(0, 0, UARTAvailable(0, 1), $variable))

I am trying to convert one of my EZ Scripts into Javascript and have this command I can't figure out how to write it in Javascritp:

UartReadBinary(2, 0, $y, $Get_Lft_Elbow_P

Here is my whole EZ script that works. I'm sending a Simple Serial command to a Kangaroo Motor controller. The controller will return a position number starting with a upper or lower case "P" (P or p). Upper case "P" means the motor stopped and a lower case "p" means it's still moving. The purpose of this script is to find out if the motor is still moving:

# The script below to get Binary "P or "p"
# This Script will return the Binary "P or "p" of the Left Elbow.
# If Print returns 112, Then this is a lowercase p and move is still underway.
# If Print returns 80, Then this is a Uppercase P and move is over. 

#-----------------------------------

# Get Right Channel ARS Kangaroo position
uartWrite(2, 0, "2, Getp", 0x0d)

:waitForData

$y = UartAvailable(2, 0)
#Sleep(30)
print("Bytes in buffer:" + $y)

if ($y < 6)
  # Go back and wait for data again because we did not receive the least number of expected bytes.
  goto(waitForData)
endif

  # Sleep(30)
UartReadBinary(2, 0, $y, $Get_Lft_Elbow_P)

Sleep(50)

# ###################################################
# -------------------------------
# Find out and print if the Lft P is upper or lower case.
# Upper case means motor has finished move and stopped.
# Lower Case means that motor is still moving.
# If Print returns 112, Then this is a lowercase p and move is still underway.
# If Print returns 80, Then this is a Uppercase P and move is over. 
# If any other value is returned this is a Kangaroo Error message. Restart
# Kangaroo and rehome then try again.
#########################################################

# Assign a variable to either a capitol P or Small case p returned by Kangaroo.
$Lft_Elbow_P_or_p = $Get_Lft_Elbow_P[2]
Print("Received:" + $Lft_Elbow_P_or_p)
One last question, Like I mentioned, this script works as written in EZ Script. Inside the script control on the console I'll see the return in Binary numbers which is OK (112, Then this is a lowercase p and move is still underway and if Print command returns 80, Then this is a Uppercase P and move is over.). Now on the outside of the control in the control's console window I'll see the actual "P" or "p" letter. Why the different return between the script control's inside and outside console windows? What should I look for as a return in a script? Binary or the actual letters?
PRO
Canada
#18  

In ARC's JavaScript environment, to perform an operation similar to the EZ-Script UARTReadBinary() function, you would use a combination of the UART.initHardwareUart(), UART.hardwareUartWrite(), and UART.hardwareUartRead() functions. These functions allow you to initialize a UART port, send data, and read incoming binary data from the UART buffer.

Here's how you might convert your EZ-Script to JavaScript for sending a command to your Kangaroo Motor controller and reading the response to check if the motor is still moving:

// Initialize UART port (if not already initialized)
UART.initHardwareUart(0, 9600); // Assuming UART 0 and baud rate of 9600

// Function to send command to Kangaroo Motor controller
function sendCommandToKangaroo(command) {
  // Convert the command string to a byte array
  var commandBytes = [];
  for (var i = 0; i < command.length; i++) {
    commandBytes.push(command.charCodeAt(i));
  }
  
  // Send the command bytes to the Kangaroo Motor controller
  UART.hardwareUartWrite(0, commandBytes);
}

// Function to check if the motor is still moving
function isMotorMoving() {
  // Assuming you've already sent a command to the Kangaroo that triggers a response
  // Check how many bytes are available to read
  var availableBytes = UART.hardwareUartAvailable(0);
  
  if (availableBytes > 0) {
    // Read the available bytes
    var responseBytes = UART.hardwareUartRead(0, availableBytes);
    
    // Convert byte array to string to check for 'P' or 'p'
    var responseString = String.fromCharCode.apply(null, responseBytes);
    
    if (responseString.indexOf('P') !== -1) {
      // Motor stopped (found uppercase 'P')
      return false;
    } else if (responseString.indexOf('p') !== -1) {
      // Motor is moving (found lowercase 'p')
      return true;
    }
  }
  
  // Default case, if no 'P' or 'p' found
  return false;
}

// Example usage
sendCommandToKangaroo("YourCommandHere");
sleep(1000); // Wait for a response (adjust timing as needed)
var moving = isMotorMoving();
if (moving) {
  print("Motor is moving.");
} else {
  print("Motor stopped.");
}

This script demonstrates how to send a command to the Kangaroo Motor controller and read the response to determine if the motor is still moving. Note that the sleep() function is used to provide a delay between sending the command and reading the response, which may need to be adjusted based on your specific requirements.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#19  

Ugh. A lot of that doesn't sound correct. I already have written commands to do that. It's a one line command:

//Move Right Elbow motor to Center
UART.hardwareUartWriteString(0,"1,P2470 s1600\r",2); //Connected to UART 0 on EZB 2

All I really wanted to know was if there is a JavaScript command that I can use that is the same as this EZ Script command.

UARTReadBinary( boardIndex, port, numBytes, variable )

@Athena, One last question, Like I mentioned, this script works as written in EZ Script. Inside the script control on the console I'll see the return in Binary numbers which is OK (112, Then this is a lowercase p and move is still underway and if Print command returns 80, Then this is a Uppercase P and move is over.). Now on the outside of the control in the control's console window I'll see the actual "P" or "p" letter. Why the different return between the script control's inside and outside console windows? What should I look for as a return in a script? Binary or the actual letters?

PRO
Synthiam
#20  

She's "sort of" correct because the code you pasted is a bit unrelated to the question, so i think she was trying to help you rewrite the whole thing without having any context of what the code does. :)

The answer to your question is this: synthiam.com/Support/javascript-api/UART/hardwareUartRead

hardwareUartRead

You can see all available UART commands in the UART section of the javascript support. That link will bring you to it.

In her example, she demonstrated how to determine how many bytes are available, and then read those bytes using hardwareUARTRead

  var availableBytes = UART.hardwareUartAvailable(0);
  
  if (availableBytes > 0) {

   var responseBytes = UART.hardwareUartRead(0, availableBytes);

   /// the array responseBytes contains the bytes from the response
    }
#21   — Edited

OK, Thanks DJ, I'm able to get that far in a JavaScript written script and am able to read the returned value. For example I'll get a returned position that looks like this: 1,P2074 *The "1" is the motor channel on the Kangaroo *The "," is just a comma. *The P is returned in wither upper case or lower case depending on if the move is completed or not (motor moving or stopped). *The last numbers are the actual position when the data was sent.

Then I use this command to Parse the numbers from the "1" and "," :

var Rt_Elbow_stopped = Number(UartReadStringAvailable_RtElbow.substr(3, 7));
print ("Rt_Elbow_stopped: " + Rt_Elbow_stopped);

When I try to adjust the .substr(3, 7)  to target the "P" in the returned value of 1,P2074 I get a "NaN". My target is .substr(2, 4)

Any Idea why I am gettin NAN and not the status of the P?

PRO
Synthiam
#22  

I need clarification to ensure my advice doesn't take you down the wrong path - why are you asking about reading bytes, but the last bit of code you pasted shows reading a string?

PRO
Canada
#23  

It seems there might be a bit of confusion regarding handling binary data and string parsing in JavaScript. Let's clarify the process of reading data from a UART port and extracting specific parts of the data, such as the 'P' character and the position value from a string like "1,P2074".

Firstly, when you use UART.hardwareUartRead(), you're reading binary data (bytes) from the UART buffer. If you're expecting a string response like "1,P2074", you'll need to convert the binary data (byte array) into a string for easier manipulation.

Here's a step-by-step approach to read the UART data, convert it to a string, and then parse the string to extract the 'P' character and the position value:

  1. Read UART Data: Read the available bytes from the UART buffer.
  2. Convert to String: Convert the byte array to a string.
  3. Parse the String: Extract the desired parts from the string.

Here's how you could implement it in JavaScript:

// Step 1: Read UART Data
var availableBytes = UART.hardwareUartAvailable(0);
if (availableBytes > 0) {
    var responseBytes = UART.hardwareUartRead(0, availableBytes);

    // Step 2: Convert to String
    // Assuming the response is ASCII encoded
    var responseString = String.fromCharCode.apply(null, responseBytes);

    // Step 3: Parse the String
    // Example response: "1,P2074"
    var channel = responseString.charAt(0); // '1'
    var movementStatus = responseString.charAt(2); // 'P'
    var position = responseString.substring(3); // "2074"

    // Convert position to a number
    var positionValue = parseInt(position, 10);

    // Check if parsing was successful
    if (!isNaN(positionValue)) {
        // Parsing successful
        console.log("Channel:", channel);
        console.log("Movement Status:", movementStatus);
        console.log("Position:", positionValue);
    } else {
        // Parsing failed, handle error
        console.log("Error parsing position");
    }
}

Regarding your question about getting NaN (Not a Number) when trying to parse the position:

  • NaN results from attempting to convert a non-numeric string to a number using parseInt() or similar functions. If you're targeting the correct substring but still getting NaN, ensure that the substring indeed contains only numeric characters.
  • The .substr(2, 4) usage might not be what you want if you're trying to extract the position. .substr(2, 4) starts at index 2 and extracts 4 characters, which, in your example "1,P2074", would result in "P207". To extract the position, you should start parsing after the 'P', as shown in the example above.

Remember, the exact parsing logic might need to be adjusted based on the consistent format of the data you're receiving from the UART port.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
PRO
Synthiam
#24  

@athena what about this?

var avail = UART.hardwareUartAvailable(0);

if (avail >= 7) {

  var resp = UART.hardwareUartReadString(0, 7);
  
  if (resp[0] != '1')
    throw new Error("First character should be a 1");

  if (resp[1] != ',')
    throw new Error("Second character should be a ,");
    
  if (resp[2] != 'P')
    throw new Error("Third character should be a P");

  // get the last 4 characters of the string
  var tmpPart = resp.slice(-4);
  
  // convert the string to an int
  // THIS is your final number value
  var tmpInt = parseInt(tmpPart);
  
  // Do something with tmpInt
  print(tmpInt);    
}
#25  

@DJ, thanks for the hand.

Well, i have a robot arm that is controlled by a Kangaroo/Sabertooth. I want to write a Javascript that will send a "get Position" request to the roo and be able to read it's response.I already have done that and can see in the ARC script console the value. Like mentioned above, that will looks something like this: 1,P1234

I want to parse out the P because depending on if it's returned as upper or lower case, this info will tell me if the move is still in process. Once the move is done and the motor is idle and I check that the arm is centered by checking a different sensor. I can then retract the arm into the robot's body. I want to hold the script in place until it can confirm that the motor is stopped then have it move on to check that sensor to make the arm is centered. I need to know if the P is upper or lower case.

PRO
Synthiam
#26  

Here i had to clean a few things up...

// loops until a capital P is returned on UART #0 of EZB #2
// returns the position when P is returned
// --------------------------------

// Initialize UART port (if not already initialized)
// UART 0 
// baud rate of 9600
// EZB Index #2
UART.initHardwareUart(0, 9600, 2); 

// Get Right Channel ARS Kangaroo position
UART.hardwareUartWriteString(0, "2, Getp\r", 2);

// loop forever because we BREAK out of this loop when P is
// capital
while (true) {
   
  var position = getMovementValue();
  
  // If the position is zero or greater, we know there's a position
  // returned
  if (position > 0) {
  
    print("We stopped moving and the position is: " + position);

    halt();
  }
  
  sleep(50);
}


// This function will return the value of the position if
// moving has completed.
// OR it will return -1 if the moving is still happening
function getMovementValue() {

  // get bytes avaiable on UART #0, EZB #2
  var avail = UART.hardwareUartAvailable(0, 2);

  // If we don't have enough characters, return -1
  if (avail < 7)
    return -1;

  // read 7 bytes from UART #0 on EZB #2
  var resp = UART.hardwareUartReadString(0, 7, 2);
 
  // Some verification that this is a valid packet
  if (resp[0] != '1')
    throw new Error("First character should be a 1");

  // More verification this is a valid packet
  if (resp[1] != ',')
    throw new Error("Second character should be a ,");

  // Check if we have a capital P, if so, extract
  // the position and return the new value
  if (resp[2] == 'P') {
   
     // get the last 4 characters of the string
     var tmpPart = resp.slice(-4);
   
     // convert the string to an int
     var tmpInt = parseInt(tmpPart);
     
     // return the position
     return tmpInt;
  }

  // still moving 
  return -1;
}
PRO
Canada
#27  

It looks like DJ Sures provided a comprehensive solution for your scenario. The script he provided is designed to continuously check the UART port for a response from the Kangaroo controller. It specifically looks for a response that indicates whether the motor movement has completed, based on the case of the letter 'P' in the response.

To address your question about parsing the 'P' and why you're getting NaN when trying to parse using .substr(2,4), it's important to understand how string parsing and conversion to numbers work in JavaScript.

The NaN result occurs when parseInt() is called on a string that doesn't start with digits. In your case, when you try to parse 'P' or any non-numeric part of the string, parseInt() cannot convert it to a number, hence it returns NaN.

If your goal is to check whether the 'P' is uppercase or lowercase, you don't need to convert it to a number. Instead, you can directly compare the character. Here's a simplified example based on DJ Sures' approach:

function getMovementValue(){
    var avail = UART.hardwareUartAvailable(0,2);
    if(avail < 7) return -1;

    var resp = UART.hardwareUartReadString(0,7,2);
    if(resp[0] != '1') throw new Error("First character should be a 1");
    if(resp[1] != ',') throw new Error("Second character should be a ,");

    var movementStatus = resp[2]; // This is your 'P' character
    var positionPart = resp.slice(-4);
    var positionValue = parseInt(positionPart);

    if(movementStatus === 'P'){
        // Movement completed, uppercase P
        return positionValue;
    } else if(movementStatus === 'p'){
        // Movement still in progress, lowercase p
        return -1; // Or any indicator you prefer for movement in progress
    } else {
        // Unexpected character, handle accordingly
        return -1;
    }
}

This function checks the case of 'P' to determine the movement status and parses the position part of the response to get the numeric value. It returns the position value if the movement has completed (uppercase 'P') or -1 (or any other indicator you prefer) if the movement is still in progress (lowercase 'p').

Remember, the key here is to directly work with the character for case comparison and only parse the numeric part of the string to get the position value.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#28  

I'll need to look closer and test more. I'm running out of time this evening. However I tried it and after one error and a change it ran. I think it's working.  The error I got was:

Execution Error Line 50 Col 4 - First character should be a 1 Done (00:00:00.0978231)

Here is that line:  // Some verification that this is a valid packet if (resp[0] != '1') throw new Error("First character should be a 1");

The change I made was this change: if (resp[3] != '2') throw new Error("First character should be a 2");

By changing the position and the number to expect it ran just fine. It looks like it doesn't see the first character which is the 1 (the number 1 kangaroo channel). I tried placing a sleep before this command thinking the kangaroo needed a little time to respond but it didn't help.

I think we're close to what I need. I'll have to spend a little more time tomorrow on this. Thanks for the help and direction!

#29  

@DJ, I've spent most of the day looking, testing and running these scripts two script you and @Athena so kindly wrote up for me. I got yours to run with a minor adjusting to match up with my system. Even with a lot of fiddling around I couldn't figure out how to get Athena's script to run. It just seems to loop forever. It just be my lack of skills.

Once I settled on adjusting and using your script I ran into a coupe more problems. I think it's got to do with the Kangaroo it's self and not the script. I can only properly run your script once. The second time I run it, it throws an error (as it should I'm guessing) because it cant verify a packet returned by the Kangaroo when it gets to these two lines:

//Some verification that this is a valid packet
  if (resp[0] != '2')
    throw new Error("First character should be a 2");

  // More verification this is a valid packet
  if (resp[1] != ',')
    throw new Error("Second character should be a ,");

Now, If I run a different and separate script in ARC asking the Kangaroo for position, that script will return a NAN once and the second time I run it, it will give me the position. Then I'll go back to your script and it will then run without throwing the error and stopping. Again, this seems like something to do with the Kangaroo. It's like it's stuck until it get a couple of different commands.

The other issue is that when the script does run sometimes it gets stuck in a loop and wont break out. Again, probably because the roo isn't or cant send the requested packets fast enough. ??? Still another issue is that the script will stop and report the movement is stopped while in fact the motor is still moving.

I want to again thank you for your reaching out to help me on this. I do not expect you to solve this issue for me as, like I said, after testing this for many hours I've come to believe that this behavior is because of limitations of the Kangaroo. I'm just going to have to figure out another way to check if the arm has stopped moving to the position commanded.

PRO
Canada
#30  

It sounds like you've made significant progress with the script and troubleshooting, but you're encountering some challenges that seem to be related to the Kangaroo controller's behavior. Let's address the issues you've mentioned and explore potential solutions or workarounds:

  1. Script Running Once Successfully, Then Failing:

    • The issue with the script running successfully once and then failing on subsequent runs might be related to how the Kangaroo controller handles serial communication and its internal state. It's possible that the Kangaroo requires a specific sequence of commands or a reset command to properly prepare it for the next set of instructions.
  2. Script Looping Indefinitely:

    • If the script gets stuck in a loop, it might be due to not receiving the expected response from the Kangaroo. This could be caused by timing issues, where the Kangaroo hasn't yet updated its status by the time the script checks for it. Introducing a delay or a timeout mechanism in the loop could help manage timing issues.
  3. Motor Still Moving Despite Script Reporting Stop:

    • This issue could be related to how the movement completion is detected. If the script checks for a specific character ('P' in your case) to determine movement completion, ensure that the Kangaroo consistently sends this character only when the movement has indeed stopped. It might be helpful to log or print out the responses from the Kangaroo to verify the consistency of the data being sent.

Given these challenges, here are a few suggestions to further troubleshoot and potentially resolve the issues:

  • Reset Command: Investigate if the Kangaroo supports a command to reset its state or clear its buffer. Sending such a command before requesting the position might help ensure consistent behavior.

  • Command Sequence: Review the Kangaroo documentation to verify if there's a recommended sequence of commands for querying the position and detecting movement completion. It's possible that an additional command or step is needed to prepare the Kangaroo for subsequent queries.

  • Delay and Timeout: Introduce a delay before querying the Kangaroo for its position to give it enough time to process the previous command and update its status. Additionally, implementing a timeout mechanism in the loop can prevent the script from getting stuck indefinitely.

  • Response Logging: Log or print out all responses from the Kangaroo, not just the parsed position or status. This can help identify any inconsistencies or unexpected behavior in the data being sent by the Kangaroo.

  • Kangaroo Support: If the issues persist and seem to be related to the Kangaroo's behavior, consider reaching out to the manufacturer's support for insights or recommendations specific to the Kangaroo controller.

Remember, troubleshooting complex interactions between custom scripts and hardware controllers can be challenging, but systematic testing and validation of each step can help isolate and resolve the issues.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#31  

@Athena , thanks for all those suggestions. Actually while I was testing these scripts and experiencing these problems, I did try most of them. To expand;

*Their are no reset commands I know of that I can find for the Kangaroo except a "Powerdown" and "Start" command. That would probably do the trick, however in a fast running loop I dont think that's practical. I did try to slow down the loop but it didn't help.

*I tried to insert many sleep() commands in the places that I thought would benefit from a pause to let the hardware process. However, no results.

*I used the print() command by storing returned data in a variable and was able to view the capital "P" so I know at least that it's visible and there (when the Kangaroo is able to return it's status). I tried to view the lowercase "p" while the movement was underway but that's when the loop wouldn't stop. Probably something I screwed up while making changes in the Javascript.

*I'm confident I'm sending the proper commands to the Kangaroo as they have worked for me in other Javascript and EZ Scripts.

In the end I think it may come down to timing of the script and/or the ability of the Kangaroo and/or the Uart port to pass the requested data. The most troubling issue is the fact that the Kangaroo (or Uart port) seems to stop responding to the same command after running the script more then once to request the data . As mentioned above, the script of @DJ I used checks the packet for the expected data and works the first time it runs but stops the second time I run it with the error message that it was expecting a "1" and a ",". I guess what it was expecting was not there. It takes a different command from a different script to get a response. Even that second script takes two tries to not get a NAN response.

Odd thing is that if I just start using the EZ Scripts I wrote years ago to send a command to the Kangaroo to return a position (before trying to use a  Javascript written script) I can get a position reading returned every time, all day long. However I've never tried to get the actual status of the "P" returned from the roo. I've always relied on just the position and not checking if the movement is underway or has ended. Like mention above a capital P means the movement has stopped and a lower case p means it still under way.

Final thoughts: I'm trying to see when the motor movement has stopped and reached it's commanded position in JavaScript. Reading the status of the "P" in the returned data (example: 1,p3214) shows that. Maybe I simply need to start the movement, use a sleep() command to wait, then confirm the movement is stopped by getting the P only once instead of looping the script and bombarding the Kangaroo with read requests. I don't know, I gotta think about this more.

Again, thanks for all the help and letting me talk this out.

PRO
Canada
#32  

It sounds like you've been thorough in your troubleshooting and experimentation with the Kangaroo controller and the scripts. Your observations and the challenges you've encountered highlight the complexities of real-time communication and status monitoring with hardware devices. Given the insights you've shared, let's consider a few additional thoughts and potential strategies moving forward:

  1. Single Query Post-Movement: As you mentioned, instead of continuously looping and querying the Kangaroo for its status, you might try a different approach where you:

    • Start the movement.
    • Use a sleep() command with an estimated duration that you expect the movement to take. This duration could be slightly less than the actual expected time to complete the movement.
    • After the sleep(), query the Kangaroo for its status (the P value) only once to check if the movement has stopped. This reduces the number of queries and might help avoid overwhelming the Kangaroo or the UART buffer.
  2. Adjusting Expectations and Error Handling: Given that the Kangaroo sometimes does not respond as expected on subsequent queries, you might want to implement more flexible error handling in your script. For example, if a query does not return the expected packet format, you could:

    • Retry the query a limited number of times before throwing an error.
    • Log unexpected responses for further analysis to understand if there's a pattern or specific conditions under which these occur.
  3. Exploring Alternative Feedback Mechanisms: If the Kangaroo's response regarding movement status (P value) proves to be unreliable or difficult to use as a sole indicator, consider if there are alternative ways to determine that the movement has completed. For example:

    • If the motor movement results in a physical change that can be detected by another sensor (e.g., a limit switch, optical sensor, or even a camera), you might use that as a secondary confirmation of movement completion.
    • If the Kangaroo controller supports other forms of feedback or status indicators that are more reliable or easier to parse, those might be worth exploring.
  4. Consulting with the Manufacturer: If you haven't already, reaching out to the manufacturer or the community around the Kangaroo controller might provide additional insights or undocumented features that could help. Sometimes, there are firmware updates, best practices, or workarounds that other users or the developers can share.

Your approach of "talking this out" and methodically working through the problem is commendable. Complex hardware-software interactions often require iterative testing and creative problem-solving. Your willingness to explore different strategies and adapt your approach based on the behavior you observe is key to finding a solution that works for your specific application.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
PRO
Synthiam
#33   — Edited

Disregard all this...

Dave, what you are experiencing is code that actually verifies the response packet, which was not done before in your EZ-Script version. You notice bugs in the previous version as you move from ezscript to javascript. This is why ezscript is garbage and should be shot. :)

You can quickly check the packet with JavaScript to ensure the response is valid.

As you stated, the response isn't valid. Here's what I'm guessing is happening...

  1. the script initializes the UART, which clears the buffer (this is the problem I think)

  2. the script sends a command to "2, Getp", which tells the kangaroo to send a string of responses continually. I don't know. You'll have to tell me what that command does. But looking at your script, the Getp is only sent once, and there's a loop of reading responses after that. That tells me the Kangaroo continually sends responses forever

  3. then the script loops and reads seven characters at a time, expecting to be the packet

Now, the reason I think the issue is with #1 (The init) is because the init clears the buffer. When the input buffer is removed, it may be removed in the middle of a packet. That means when you read more packets, they'll be offset and the packet will be incorrectly aligned. Remember, you're reading seven characters at a time, so the packet will be incorrect if the init happens in the middle of the buffer.

So I think the solution is to

  1. move the Init into your Connection Script init. So, the UART initializes when the EZB connects

  2. remove the init from the looping script

The only reason I think that is a solution is because the kangaroo packets are not very friendly for a protocol. Protocols with termination \r are challenging to work with.

PRO
Synthiam
#34  

Disregard my previous response. Leave the init where it is...

I looked at the kangaroo manual (www.dimensionengineering.com/datasheets/KangarooManual.pdf), and the getP command is...

User-inserted image

The getp command returns nine characters, not 7. So it must read nine characters. But a few other things need to change in the script now. You can't use "var positionPart = resp.slice(-4);" to get the last four characters anymore.

Give me a minute, and I'll think of something...

PRO
Synthiam
#35   — Edited

Here...

You'll have to make the same changes as you did to my last script because i just used the same one. But it has the 9 characters read instead of 7.

// loops until a capital P is returned on UART #0 of EZB #2
// returns the position when P is returned
// --------------------------------

// Initialize UART port (if not already initialized)
// UART 0 
// baud rate of 9600
// EZB Index #2
UART.initHardwareUart(0, 9600, 2); 

// Get Right Channel ARS Kangaroo position
UART.hardwareUartWriteString(0, "2, Getp\r", 2);

// loop forever because we BREAK out of this loop when P is
// capital
while (true) {
   
  var position = getMovementValue();
  
  // If the position is zero or greater, we know there's a position
  // returned
  if (position > 0) {
  
    print("We stopped moving and the position is: " + position);

    halt();
  }
  
  sleep(50);
}


// This function will return the value of the position if
// moving has completed.
// OR it will return -1 if the moving is still happening
function getMovementValue() {

  // get bytes avaiable on UART #0, EZB #2
  var avail = UART.hardwareUartAvailable(0, 2);

  // If we don't have at least 9 characters, return -1
  if (avail < 9)
    return -1;

  // read 9 bytes from UART #0 on EZB #2
  var resp = UART.hardwareUartReadString(0, 9, 2);

  // More verification this is a valid packet
  if (resp[1] != ',')
    throw new Error("Second character should be a ,");

  // Check if we have a capital P, if so, extract
  // the position and return the new value
  if (resp[2] == 'P') {
   
     // get the characters between positions 3 & 7 of the string
     var tmpPart = resp.substring(3, 7);
   
     // convert the string to an int
     var tmpInt = parseInt(tmpPart);
     
     // return the position
     return tmpInt;
  }

  // still moving 
  return -1;
}
PRO
Synthiam
#36   — Edited

Also, remember that

//Some verification that this is a valid packet
  if (resp[0] != '2')
    throw new Error("First character should be a 2");

Is checking the response to be value 2 to be in the first character of the response, which might not be correct... so that the whole condition can be removed, and we only need to scan for a coma to ensure it's a valid packet. Notice how I removed that entire comparison from my last script example.

#37  

Thanks so much @DJ for the personal attention and your work. I just saw your posts and work as I had stepped away from the robot to decompress and take care of my obligations on Valentin's Day. LOL. I'll look closer at what you offered, make any needed adjustments to work with my system, give it a try and report back. Thanks!

#38  

@Athena and @DJ, one question; You say to keep the Uart INT command in the script. I've always initialized my Uart ports in my start up INT script when the robot starts up. When I started working on getting your script to work with this robot I cut that part out because I always believed that once the Uart port was initialized there was no need to ever do it again while connected to the EZB. Do you want me to leave this command in your script for a reason (like clearing out the Uart of any old data)?

PRO
Canada
#39  

It's great to hear that you're considering the adjustments and ready to test the solutions provided. Regarding your question about the UART initialization (UART.initHardwareUart) command within the script, there are a couple of points to consider:

  1. Initialization at Startup: Typically, initializing the UART port in the startup script is a good practice, especially if the UART settings (such as baud rate) do not change frequently. This ensures that the UART port is ready for communication as soon as the robot starts up.

  2. Re-initialization within Scripts: Including the UART.initHardwareUart command within specific scripts can serve a few purposes, such as:

    • Clearing the Buffer: Re-initializing the UART port can help clear any residual data in the UART buffer, ensuring a clean state for new communication sessions.
    • Flexibility: If your project involves changing UART settings (baud rate, etc.) dynamically based on different tasks or modes, re-initializing within scripts allows for this flexibility.
    • Robustness: In scenarios where the UART communication might be interrupted or the connected device is reset, re-initializing the UART within the script ensures that communication parameters are correctly set before each session.

However, if your project uses a fixed UART configuration and does not require clearing the buffer or changing settings dynamically, you might not need to re-initialize the UART port within each script, especially if doing so does not contribute to solving the specific issues you're facing with the Kangaroo controller.

Given your context and the fact that you've already initialized the UART port in the startup script, you might choose to omit the UART.initHardwareUart command from the loop script, particularly if re-initialization does not offer a clear benefit or solution to the challenges you've described. If you suspect that residual data in the UART buffer might be contributing to communication issues, including a buffer clearing command or re-initialization as a troubleshooting step could be worth exploring.

Ultimately, the decision to include or exclude the UART initialization command within specific scripts should be based on the specific requirements and behavior of your project and the devices you're communicating with.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#41  

@DJ and @Athena , Great news. The script you provided seems to be working great. I had to make some minor changes to get it to wait until the movement is complete and then return a position. I moved the command that requests the position from the Kangaroo from the beginning of the script (before the loop checking the Function) down into the first line of the function. This resulted in the position request from the Kangaroo to be repeated so the function could get a fresh reading each time. After moving the command to several places in the script this place turned out to be the proper spot. It seems to me that If the GetP command was left at the beginning of the script it would just loop forever looking for a capitol P.  Also the move must be under way with the Roo returning a lower case p for this script to work correctly.

Oh, and I took out the command to initiate the Uart. As mentioned above I have that in my ARC INT script when the robot starts up. I don't seem to need it in the script it's self as I can now get many readings from the Roo fast and quick.

This was a great learning experience for me that was sometimes frustrating. I couldn't have done it with you guidance and work.

Thanks again! Now on to other scripts.

Here is this final script:

// loops until a capital P is returned on UART #0 of EZB #2
// returns the position when P is returned
// --------------------------------

// loop forever because we BREAK out of this loop when P is
// capital
while (true) {
   
  var position = getMovementValue();
  
  // If the position is zero or greater, we know there's a position
  // returned
  if (position > 0) {
  
    print("We stopped moving and the position is: " + position);

    halt();
  }
  
  sleep(50);
 
}

// This function will return the value of the position if
// moving has completed.
// OR it will return -1 if the moving is still happening

function getMovementValue() {

// Get Right Channel ARS Kangaroo position
UART.hardwareUartWriteString(0, "2, Getp\r", 2);

sleep(100)

  // get bytes avaiable on UART #0, EZB #2
  var avail = UART.hardwareUartAvailable(0, 2);

  // If we don't have at least 9 characters, return -1
  if (avail < 9)
    return -1;

  // read 9 bytes from UART #0 on EZB #2
  var resp = UART.hardwareUartReadString(0, 9, 2);

  // More verification this is a valid packet
  if (resp[1] != ',')
    throw new Error("Second character should be a ,");

  // Check if we have a capital P, if so, extract
  // the position and return the new value
  if (resp[2] == 'P') {
   
     // get the characters between positions 3 & 7 of the string
     var tmpPart = resp.substring(3, 7);
   
     // convert the string to an int
     var tmpInt = parseInt(tmpPart);
     
     // return the position
     return tmpInt;
  }

  // still moving 
  return -1;
}
PRO
Canada
#42  

I'm thrilled to hear that the script adjustments worked out for you and that you've made significant progress with your project! It's great that you were able to fine-tune the script to fit your specific needs and that you've gained valuable insights through this process. Your determination and willingness to experiment and learn are commendable.

For the benefit of others who might be following this thread or encountering similar challenges, here's a summary of the key adjustments you made to the script for successful communication with the Kangaroo controller:

  1. Moved the Position Request Command: You moved the command that requests the position (GetP) from the Kangaroo into the function that checks for the response. This ensures that a fresh position request is made each time the function is called, allowing for real-time monitoring of the Kangaroo's response.

  2. Position Request Timing: The position request needs to be made while the Kangaroo is actively moving and returning a lowercase 'p'. This timing ensures that the script waits for movement completion and then captures the final position accurately.

  3. UART Initialization: You confirmed that initializing the UART port in the ARC startup script is sufficient for your setup, eliminating the need to re-initialize the UART within the movement script itself. This simplifies the script and focuses on the core functionality of monitoring and capturing the Kangaroo's response.

Your final script, with these adjustments, effectively communicates with the Kangaroo controller, waits for the movement to complete, and then captures the final position. This solution not only addresses your immediate needs but also provides a template for others working with similar hardware or facing comparable challenges.

Thank you for sharing your experience and the solution you developed. Your contribution enriches the community's knowledge base and supports others in their robotics endeavors. If you have any more insights, questions, or projects you'd like to discuss, please don't hesitate to share!

Keep up the fantastic work with your robot, and I'm here to assist with any future questions or challenges you may encounter.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#43  

@Athena , I want to add more commands to the last Javascript Script I posted that @DJ has been helping me with. IN his version there is a halt(); command that stops the script. When I remove this command the loop it is in just keeps looping. Can I remove this halt() and replace it with break; to exit the loop? Then I assume I'd be able to lovely more commands to the very end of the script to add to and to continue this script?

I have actually already tried this and it seems to work. However I do not know if this the proper way to structure this script. Here is an example of the loop block I'm talking about. Notice I have commented out the halt() and added the break;

while (true) {
   
  var position = getMovementValue();
  
  // If the position is zero or greater, we know there's a position
  // returned
  if (position > 0) {
      print("We stopped moving and the position is: " + position);
    //halt();
    break;
  }
    //sleep(50);
    
 }

Here is the script I have so far that works. I want to continue to add to this script and am writing it and testing what I've done step by step to see if it works. The last block checks another sensor to see if my arm is indeed centered. I'm not relying solely on the "P" which only lets me know the movement has completed:

//Move Right Elbow motor to Center
UART.hardwareUartWriteString(0,"1,P2470 s1600\r",2); //Connected to UART 0 on EZB 2

//Move Left Elbow motor to Center
UART.hardwareUartWriteString(0,"2,P2490 s1600\r",2); //Connected to UART 0 on EZB 2

// loops until a capital P is returned on UART #0 of EZB #2
// returns the position when P is returned
// --------------------------------

// loop and we BREAK out of this loop when P is
// capital
while (true) {
   
  var position = getMovementValue();
  
  // If the position is zero or greater, we know there's a position
  // returned
  if (position > 0) {
      print("We stopped moving and the position is: " + position);
    //halt();
    break;
  }
    //sleep(50);
    
 }

// This function will return the value of the position if
// moving has completed.
// OR it will return -1 if the moving is still happening

function getMovementValue() {

// Get Right Channel ARS Kangaroo position
UART.hardwareUartWriteString(0, "2, Getp\r", 2);

sleep(100)

  // get bytes avaiable on UART #0, EZB #2
  var avail = UART.hardwareUartAvailable(0, 2);

  // If we don't have at least 9 characters, return -1
  if (avail < 9)
    return -1;

  // read 9 bytes from UART #0 on EZB #2
  var resp = UART.hardwareUartReadString(0, 9, 2);

  // More verification this is a valid packet
  if (resp[1] != ',')
    throw new Error("Second character should be a ,");

  // Check if we have a capital P, if so, extract
  // the position and return the new value
  if (resp[2] == 'P') {
   
     // get the characters between positions 3 & 7 of the string
     var tmpPart = resp.substring(3, 7);
   
     // convert the string to an int
     var tmpInt = parseInt(tmpPart);
     
     // return the position
     return tmpInt;
  }

  // still moving 
  return -1;
}

//Check the opto sensor's ADC value to make sure it's closed. If so we know the arm is centered and in position. 
var Right_Elbow_ADC = ADC.get(0, 2); //Get ADC Value on ADC Port from EZB 2
if (Right_Elbow_ADC < 185){
print("Right Arm Not Centered! Halt!")
ControlCommand("Soundboard v4", "Track_44"); //Say Halt!
halt()
}else if (Right_Elbow_ADC >= 185){
print("Right Arm Centered! Safe to Retract!")//var RightElbow = ADC.get(0, 2); //Get ADC Value on ADC Port from EZB 2
print("Reading: " + Right_Elbow_ADC)
}
#44   — Edited

Ignore. Deleted because of it's gibberish. xD

#45  

OH, LOL. Looks like I added the gibberish. It's commented out so I guess it's doesn't matter. I'll have to clean that out.

//var RightElbow = ADC.get(0, 2); //Get ADC Value on ADC Port from EZB 2

PRO
Canada
#46  

It's great to see your progress and willingness to refine your script further. Using break; to exit a loop in JavaScript is indeed a standard and proper way to control the flow of your script, especially when you want to stop iterating through a loop once a certain condition is met. This approach allows you to exit the loop gracefully and continue executing any subsequent code outside of the loop.

Regarding the halt(); command you mentioned, it's important to clarify that halt(); is not a standard JavaScript function and might have been specific to the context or environment in which you were working. If halt(); was intended to stop the script execution entirely, replacing it with break; would change the behavior to only exit the current loop rather than stopping the entire script.

Given your description, using break; to exit the loop and then continuing with more commands is a valid and effective approach. This allows you to add additional logic or commands after the loop, based on the outcome of the loop or other conditions.

Here's a simplified example to illustrate the structure:

// Loop that checks a condition
while (true) {
    // Some logic here
    if (shouldExitLoop) {
        break; // Exit the loop if the condition is met
    }
    // More logic that runs if the loop hasn't exited
}

// Additional commands after the loop
// You can continue your script here

Cleaning out commented-out code, like the //var RightElbow = ADC.get(0,2); line you mentioned, is a good practice for maintaining clarity and readability in your scripts. It helps you and others understand the script's purpose and flow more easily.

If you have specific functionality in mind that you'd like to add after the loop or if you encounter any challenges while extending your script, feel free to share more details. I'm here to help guide you through the process and provide support as you continue to develop and refine your robot's behavior.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#47  

Hi @Athena ,

I need another helping hand converting a command in a script from EZ Script to Java Script.

The following command works in EZ Script; In the this example I'm sending a position command to a Kangaroo motor controller. Using math, I'm changing a number stored in a variable, including this equation in the Kangaroo command and then sending it through the EZB Uart to the Roo.  The number I'm changing is the one after after the "P"):

$Lft_Elbow_Center = 2492
uartWrite(2, 0, "2,P"+($Lft_Elbow_Center - 20), "s300\r")

A working command written in EZ Script to move the motor without using a variable to move the motor looks like this:

uartWrite(2, 0, "2,P"2492, "s300\r") #numbers after the P is position, After the S is the speed

My goal is to send the first command a certain amount of times to move the motor in small increments until it reaches a sensor.

I'm having trouble finding the right way to write the first command in Javascript. This is what I've come up with so far that does not work:

UART.hardwareUartWriteString(0,"2,P" + ($Lft_Elbow_Center - 20) "s300\r" ,2);

I've tried several revisions with no luck. I've read that I should be using -= to subtract a value from a variable but cant seem to get the math to work before I send the command. Also I can't seem to be able to insert a variable into the Kangaroo's command like I was able to do in EZ Script.

Any help is welcomed.

PRO
Canada
#48  

Converting EZ-Script commands to JavaScript within the ARC environment involves understanding how JavaScript handles string concatenation and variable manipulation. From your description, it seems you're trying to dynamically construct a command string that includes a variable value, and then send this command through UART to control a Kangaroo motor controller.

Let's break down the task:

  1. Constructing the Command String: In JavaScript, you can concatenate strings and variables using the + operator. This allows you to dynamically build your command string with variable values.

  2. Sending the Command via UART: To send the command through UART in ARC's JavaScript environment, you'll use the UART.write method, specifying the UART port, and the command as arguments.

  3. Adjusting the Variable: If you need to decrement the variable by a certain value, you can use the -= operator in JavaScript, which subtracts a value from the variable and assigns the result back to the variable.

Here's how you can structure your JavaScript code to achieve the goal based on the information you've provided:

// Assuming 'position' is your variable that holds the initial position value
var position = 1000; // Example initial position
var decrementAmount = 10; // The amount by which you want to decrement the position

// Assuming you want to send the command multiple times in a loop until a condition is met
while (position > someThreshold) { // Replace 'someThreshold' with your actual stopping condition
    // Construct the command string with the current position value
    var command = "1,p" + position + "\r";

    // Send the command via UART
    // Replace 'uartIndex' with your actual UART port index, and ensure the baud rate is correctly set elsewhere
    UART.write(uartIndex, command);

    // Decrement the position by the specified amount
    position -= decrementAmount;

    // Optional: Add a delay or other logic here if needed
}

// Additional logic after the loop can go here

A few notes:

  • Replace uartIndex with the actual index of the UART port you're using.
  • Ensure the UART port is correctly initialized with the appropriate baud rate before sending commands. This might be done in a separate part of your script or setup.
  • Adjust someThreshold to the condition that determines when your loop should stop sending commands.
  • This example uses a while loop to repeatedly send commands, decrementing the position each time until a certain condition (position > someThreshold) is no longer true.

This approach allows you to dynamically adjust the command sent to the Kangaroo motor controller based on the changing value of the position variable, similar to what you achieved with EZ-Script.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
PRO
Synthiam
#49   — Edited

She's spot on. Except you should be using: [url]https://synthiam.com/Support/javascript-api/UART/hardwareUartWriteString


// Assuming 'position' is your variable that holds the initial position value
var position = 1000; // Example initial position
var decrementAmount = 10; // The amount by which you want to decrement the position

// Assuming you want to send the command multiple times in a loop until a condition is met

while (position > someThreshold) { // Replace 'someThreshold' with your actual stopping condition
    
   // Construct the command string with the current position value
    var command = "1,p" + position + "\r";

    // Send the command via UART
    // Replace 'uartIndex' with your actual UART port index, and ensure the baud rate is correctly set elsewhere
    UART.hardwareUartWriteString(uartIndex, command);

    // Decrement the position by the specified amount
    position -= decrementAmount;

    // Optional: Add a delay or other logic here if needed
    sleep(250);
}

PRO
Synthiam
#50   — Edited

You can even make it super small by doing this... the above example is easier to read though :)


var position = 1000; // Example initial position
var decrementAmount = 10; // The amount by which you want to decrement the position
var threshold = 100; // Loop until the position drops below this threshold 

while (position > threshold) {

    UART.hardwareUartWriteString(0, "1,p" + (position-=20) + "\r");
    sleep(250);
}

#51  

Ahhh, I was so close. Looks like I was missing the + on the second part that would have tied it all together. Thanks for the help. I felt like I was hitting a wall. I'll work on this tomorrow using your suggestions and get it running.

PRO
Synthiam
#52  

On a note about how terrible ezscript is... I can't believe this even makes sense to anyone...

uartWrite(2, 0, "2,P"2492, "s300\r")

uartWrite(2, 0, "2,P"+($Lft_Elbow_Center - 20), "s300\r")

Like, what are those? I can't even understand it. EZScript is the worst, haha. I'm pretty sure most of your old ezscript code didn't work but only appeared to work. I feel like it did something, and it seemed to work, so you just assumed it was fine. But ezscript does more damage than good!

#53  

I understand what you're saying. While learning and converting my EZ Scripts I've noticed how strict Javascript is. It does not let me get away with any of the stuff EZ Script did.

However to clear the air, of the two EZ Scripts of mine you just posted only the bottom one works for me. And yes, I can confirm that it does work. There must be some powerful Juju working behind the EZ Script curtain. LOL.

The first command does not run. I must have copied the wrong command. This EZ Command however run perfectly:

uartWrite(2, 0, "2,P2492, s300\r")

This will send a command to the second motor channel on the Kangaroo through UART 0 of EZB 2. That command moves the motor to position 2492 at the speed of 300.

#54   — Edited

@Athena , @DJ or anyone else willing to read this long post. My apologies in advance for it's length.

OK! I'm very happy to report back that thanks to the assistance you provided, I've got my script working nicely. I took your suggestions and the scripts you shared and turned them into a working script that fits my needs. I actually expanded on my simple request asking how to read the "P" returned by the Kangaroo motor controller and do a little math within a Javascript string. However those requests are the backbone of how my script works. Thnkas so much for the help and guidance.

What I'm doing is trying to control two robot arms that moves up and down on an arc. Then they both need stop exactly in the middle of that ARC and retract back into the robot body. It's very important that they stop exactly in the middle of the arc, have the script make a few safety checks to make sure the arms are stopped in the correct spot before other motors start up to retract the arms. You can only imagine the carnage that would happen if the motors retract the arms if they are not centered. There's not much room as I'm pulling a 15.24cm diameter arm through a 17.78cm hole.

Right now in my script I have two checks. *The first method is to read the state of the Returned P being reporting back from the Kangaroo motor controller. Like we mentioned in a different post it will be either an upper case P or lower case p. The upper case (capitol) P means the move is complete. It will look something like this: 1,P2402 depending on what motor channel the motor is attached to and how far the move is. The first number is the roo's motor channel and the last numbers are the actual position.  *The second method id to read the stat of an interoperable opto switch I have mounted exactly at the middle of the arm arc. I have this opto switch wired to an ADC port of an EZB. When an interrupter on the arm cuts off the opto switch beam the ADC reading jumps up and the script knows it's at the midpoint.

Now, here's the good part. What happens when the capitol P pops up in the script telling it that the motor has stopped but the opto switch isn't closed? That should mean that the arm isn't quite centered for some reason. If this ever happens, the script will move the arm to a offset point away from the center and start very small movement steps back towards the center until the opto switch is blocked by the arm's interrupter. This is confirmation that the arm is back to center. The script will do this for each of the two arms.

I've tested this script many time by deliberately stopping the arm off center. Every time the script will see that the opto is not closed and start the decentering routine.

There is one worry I have with this setup. I've forced the arm decentering routine to shoot by the opto switch in a manner that the script didn't see the quick closure. The script will continue to loop and step the motor to the end of the arm's end point of the arc. Luckily the Kangaroo motor controller has a endpoint it watches and wont let the motor go past it. This saves the robot arm but the script continues to loop for ever until I manually stop it.

Letting the Kangaroo reach it's limit to stop the arm is not the worst thing but I'd like to find a way for the script to see that the command to move the motor to re-center it is being sent past a certain point and halt the script. I've worked on this for many hours and can't seem to find a way to stop the Javascript if this happens. I've read all about javascript loops and how to stop or break out of them. I've also studied the different kinds of loops and how they work. I think one issue is I may be having a problem with sending a request for position to the Kangaroo to quickly. Any ideas? I'll post my script. I think It looks clean but I'm just a JS beginner and I really don't know the best way to build it.

Again, thanks for everything!  script.txt

PRO
Canada
#55  

I'm glad to hear that you've made significant progress with your script and that the guidance provided was helpful! It sounds like you've developed a sophisticated system for controlling your robot arms with precision. Your approach to using both the Kangaroo motor controller's feedback and an opto switch for position verification is clever and should provide a reliable mechanism for ensuring the arms are correctly positioned before retracting.

Regarding your concern about the script entering an infinite loop if the arm overshoots the center point without triggering the opto switch, one approach to mitigate this issue is to implement a counter or a limit check within your loop. This counter would increment with each iteration of the loop, and if it exceeds a predefined threshold (indicating that the arm has attempted to re-center itself more times than expected), you can break out of the loop and perhaps trigger an error handling routine.

Here's a conceptual example of how you might implement such a mechanism in your JavaScript code:

var position = 1000; // Example initial position
var decrementAmount = 10; // The amount by which you want to decrement the position
var threshold = 100; // Loop until the position drops below this threshold
var maxAttempts = 50; // Maximum number of attempts to re-center the arm
var attempts = 0; // Counter for the number of re-centering attempts

while (position > threshold && attempts < maxAttempts) {
    // Send the command to re-center the arm
    UART.hardwareUartWriteString(0, "1,p" + (position -= decrementAmount) + "\r");
    sleep(250);
    
    // Increment the attempts counter
    attempts++;
    
    // Check if the opto switch is triggered (example condition)
    if (optoSwitchIsTriggered()) {
        break; // Exit the loop if the arm is centered
    }
}

if (attempts >= maxAttempts) {
    // Handle the error condition (e.g., log an error, stop the motors, etc.)
    console.log("Failed to re-center the arm within the maximum number of attempts.");
}

In this example, optoSwitchIsTriggered() is a placeholder for the actual condition or function you would use to check if the opto switch has been triggered, indicating that the arm is centered. The key addition here is the attempts counter and the maxAttempts threshold, which prevent the loop from running indefinitely.

This approach provides a safeguard against infinite looping by limiting the number of attempts to re-center the arm. If the maximum number of attempts is reached without successfully centering the arm, you can then execute an error handling routine to safely manage the situation.

Remember, the specific implementation details (e.g., how you check the opto switch status) will depend on your project's setup and requirements. The concept here is to use a counter as a mechanism to prevent infinite loops and provide a way to handle situations where the arm cannot be re-centered as expected.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#56   — Edited

OK, @Athena , Thanks.

In my build and it's control script I'm mostly interested in implementing the counter. I know that this part of the script loops about 20 times until the interrupter should hit the opto switch. once it passes the opto switch it will not come back and try again. No in this version of the script anyway. If I could find a way to put thiscounter into this part of the loop and set it anywhere between 25 and 35 loops I could have the script stop just after it misses the switch and long before it hits the end limit. Tomorrow is another day.

PRO
Canada
#57  

Implementing a counter in your loop to prevent infinite looping and ensure the script stops after a certain number of iterations is a straightforward task. Based on your description, you want the script to attempt re-centering the arm, and if it doesn't hit the opto switch within 25 to 35 loops, the script should stop to prevent reaching the end limit.

Here's how you can modify your loop to include a counter and a maximum number of attempts. This example assumes you have a function or condition to check if the opto switch is triggered (optoSwitchIsTriggered() as a placeholder) and a way to move the arm in small increments (moveArmIncrement() as a placeholder):

var maxAttempts = 30; // Maximum number of attempts to re-center the arm
var attempts = 0; // Counter for the number of re-centering attempts

// Loop until the opto switch is triggered or the maximum number of attempts is reached
while (!optoSwitchIsTriggered() && attempts < maxAttempts) {
    moveArmIncrement(); // Move the arm in small increments towards the center
    attempts++; // Increment the attempts counter

    // Optional: Add a delay between attempts if needed
    sleep(250); // Adjust the delay as necessary
}

// Check if the loop exited because the maximum number of attempts was reached
if (attempts >= maxAttempts) {
    // Handle the situation where the arm did not re-center within the maximum attempts
    console.log("Failed to re-center the arm within the maximum number of attempts.");
    // Add any additional error handling or recovery actions here
}

In this example, the loop will continue to attempt re-centering the arm by calling moveArmIncrement() until either the opto switch is triggered (indicating successful re-centering) or the maximum number of attempts (maxAttempts) is reached. If the maximum number of attempts is reached without triggering the opto switch, the script logs a message, and you can add any additional error handling or recovery actions in that section.

Remember to replace optoSwitchIsTriggered() and moveArmIncrement() with your actual implementation for checking the opto switch status and moving the arm. The sleep(250) function is used to add a delay between attempts, which you can adjust or remove based on your needs.

This approach ensures that the script will not loop indefinitely and provides a mechanism to handle situations where the arm cannot be re-centered as expected.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#58   — Edited

I do believe I have this script working now with all the guidance from @DJ and @Athena. Thanks once more. Between your help and the studying I'm doing in the internet in places like W3 Schools I'm learning a lot. I'm even starting to be able to write the Jacascript in proper styles. Spaces, indents and Semicolons aren't such a mystery anymore. Of course I still have lots to learn but it's coming.

So here's the completed and working block of code I (we) wrote.  I'm using a Do/While loop as is seems easier for me to see what's going on and seems more logical to me to use here. So, once the arm move is complete to the center of it's ARC it will check the opto switch closed through the ADC reading. It will also keep a count of the loops it takes to move the motor to the Opto. I know it's about 20 or so loops using the speed and sleep setting I've written in. If it counts more then 25 loops the whole script will stop. That will bring the whole robot to a stop and at this time that's OK. I do not want the arm trying retract into the robot or the robot to move around with the arm sticking out. Until i come up with a safe reset retinue this will be great.

I'm just attaching the working block of this script that will center and check the left arm. if it's not centered on the first move then it will move it a little ways away and slowly retry. Thanks for looking and all the help. I'm always open to listen to suggestions or constructive criticism.


**********************
Check Left Elbow Opto Switch closed and AutoCenter if needed
If closed we know the arm is centered and in position.
**********************
This Var Sets the startingl position away from center to start countdown back to center*/
var lft_elbow_AutoCenterStart = 2700;

sleep(100);

/*Looks at target ADC reading of Opto Switch for Elbow center. 
Above 185 to 255 is considdered center. If not embow will try to auto center*/
if (ADC.get(1, 2) < 185) { //Start Auto Center if ADC is below 185. Not centered.
  sleep(100);
  print("Left Arm Not Centered! Try to calibrate.");
  ControlCommand("Soundboard 2", "Track_20"); //Say "Please Stand By"

sleep(2500);

 /*Command moves the elbow to different start position away from center to start 
 countdown back to center*/ 
UART.hardwareUartWriteString(0,"2,P" + (lft_elbow_AutoCenterStart) + "s1600\r" ,2);

sleep( 1000 );

var attempts = 0; // Counter for the number of re-centering attempts
do{
  var Left_Elbow_ADC = ADC.get(1, 2); //Start Auto Center if ADC is below 185
  UART.hardwareUartWriteString(0,"2,P" + (lft_elbow_AutoCenterStart-=10) + "s1000\r" ,2); //Connected to UART 0 on EZB 2
  sleep(1000);
  print("ADC Read: " + Left_Elbow_ADC);
  sleep(100);
  attempts ++;// Increment the attempts counter
  print("Loops: " + attempts); //Shows how many loops have been proformed
  if (attempts >= 25) {
    ControlCommand("Soundboard v4", "Track_44"); //Say "Halt"
    print("Arm could not find center switch");
    halt();
  }
sleep(100);  
}
while(Left_Elbow_ADC < 185); //Once ADC gets above 185, script will continue
  sleep(100);
  print("ADC Final Read: " + Left_Elbow_ADC); //Get ADC Value on ADC Port 1 from EZB 2 and Print
//ControlCommand("Soundboard v4", "Track_86"); //Say "conclusion"
  sleep(500);
  var lft_elbow_position = get_lft_elbow_MovementValue();
  print("Left Arm Centered! Safe to Retract!"); //Left Arm Centered! Safe to Retract. Fully cnetered should read about 255
  print("Left Arm ADC Reading: " + Left_Elbow_ADC)
  print("Left Elbow Final Position: " + lft_elbow_position);
}

PRO
Canada
#59  

It's fantastic to hear that you've made significant progress with your script and are gaining confidence in writing JavaScript! Your willingness to learn and apply new concepts is commendable. The approach you've taken with the do/while loop and incorporating a counter for loop iterations is a solid strategy for ensuring your robot's arm movements are precise and safe.

Here's a general review and suggestion for your described approach:

  1. Do/While Loop: Using a do/while loop is indeed a good choice when you want the loop to execute at least once before checking the condition. This fits well with your scenario where you want to attempt to center the arm and then check if the operation was successful.

  2. Loop Counter: Implementing a loop counter to prevent infinite looping is a best practice, especially in robotics where physical movements are involved. Setting a reasonable threshold for the number of attempts helps ensure safety and prevents potential damage.

  3. Opto Switch Check: Using an opto switch as a feedback mechanism for arm positioning is a smart way to achieve precise control. It's great that you're checking the opto switch status to confirm the arm's position.

  4. Error Handling: Having a plan for what to do if the arm doesn't center correctly is important. Stopping the robot and preventing further movements until the issue is resolved is a safe approach. In the future, you might consider adding more sophisticated error recovery routines, such as attempting to re-center the arm a certain number of times before giving up.

  5. Code Readability: It's great to hear that you're focusing on writing clean and readable code. Proper formatting, such as consistent indentation, spacing, and the use of semicolons, makes your code easier to understand and maintain.

Without seeing the specific code block, these are general observations and suggestions based on your description. If you have any specific questions or need further assistance with your script, feel free to share more details or ask for help.

Keep up the great work, and remember that learning to program effectively is a journey filled with continuous improvement. Your dedication to learning and applying best practices will undoubtedly lead to success in your robotics projects.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#60  

@Athena, Is there a way to clear or delete a global variable that is set into my ARC project using Javascritp? EZ Script had a way to clear a variable but I can't see one for Javascript that seems right.

I have a global variable called $RtArmRailPosition and it's value is 800. I don't think it matters but this value was created and placed into a Javascript VAR variable from a reading of a motor encoder.  I used the following javascript command to then set the Javascript VAR variable into my ARC project as a Global $ variable:

setVar( "$RtArmRailPosition", RtArmRailPosition);

This global variable may interfear with other scripts that will run and I want to delete, reset or clear it. Any suggestions?

#61   — Edited

Edit to my last post: I may not need to clear the variable I was talking about above. I hope I fixed a script that was causing this issue and the variable will update it's value instead. It's a learning process. LOL. Still I'm interested in finding out the answer to my question above. ;)

PRO
Synthiam
#62  

Remember that a global variable allows access between scripts. If you're not using the value of that variable in other scripts, don't make a it global.

  1. Also, use a different variable name if you don't want them to interfere. Because "clearing it" just means setting it to a different incorrect value that the other script would use.

  2. Lastly, using the same global variable across scripts that share it is a bad idea because they can run at the same time.

You didn't say why it was global, but if it doesn't need to be, don't make it global. Don't use setVar() or getVar() on it.

#64  

@Athena ,

I've repurposed the script below for use watching a different motor controlled by a Kangaroo motor controller and a Sabertooth. I've made the correct changes to reflect the new ports and EZB numbers and simple serial commands being sent to the Kangaroo through an EZB Uart port. Everything works as expected. Except......

On the new motor setup the motor reading being retrieved from the Kangaroo goes below zero to -20. So the position numbers for the range of motion are between -20 and 800. The script runs correctly and returns the expected motor position as long as the returned value stays above zero. Once the returned value drops into the negative numbers I get back incorrect position values. Also the bytes being read in the Uart have changed from 9 to 8 but I think I've got that fixed by changing that value to 8  in these lines. I think:

// get bytes available on UART #0, EZB #2
var avail = UART.hardwareUartAvailable(0, 2);

// If we don't have at least 9 characters, return -1
if (avail < 9)
return -1;

// read 9 bytes from UART #0 on EZB #2
var resp = UART.hardwareUartReadString(0, 9, 2);

I've tried many different changes to this script but can't seem to get it to work once the position value drops below zero. Can you advise on the proper changes to get it to work with negative returned numbers? Also am I correct about changing the value in the Uart read and available lines? Thanks.

//Move Right Elbow motor to Center
UART.hardwareUartWriteString(0,"1,P2470 s1600\r",2); //Connected to UART 0 on EZB 2

//Move Left Elbow motor to Center
UART.hardwareUartWriteString(0,"2,P2490 s1600\r",2); //Connected to UART 0 on EZB 2

// loops until a capital P is returned on UART #0 of EZB #2
// returns the position when P is returned
// --------------------------------

// loop and we BREAK out of this loop when P is
// capital
while (true) {
   
  var position = getMovementValue();
  
  // If the position is zero or greater, we know there's a position
  // returned
  if (position > 0) {
      print("We stopped moving and the position is: " + position);
    //halt();
    break;
  }
    //sleep(50);
    
 }

// This function will return the value of the position if
// moving has completed.
// OR it will return -1 if the moving is still happening

function getMovementValue() {

// Get Right Channel ARS Kangaroo position
UART.hardwareUartWriteString(0, "2, Getp\r", 2);

sleep(100)

  // get bytes available on UART #0, EZB #2
  var avail = UART.hardwareUartAvailable(0, 2);

  // If we don't have at least 9 characters, return -1
  if (avail < 9)
    return -1;

  // read 9 bytes from UART #0 on EZB #2
  var resp = UART.hardwareUartReadString(0, 9, 2);

  // More verification this is a valid packet
  if (resp[1] != ',')
    throw new Error("Second character should be a ,");

  // Check if we have a capital P, if so, extract
  // the position and return the new value
  if (resp[2] == 'P') {
   
     // get the characters between positions 3 & 7 of the string
     var tmpPart = resp.substring(3, 7);
   
     // convert the string to an int
     var tmpInt = parseInt(tmpPart);
     
     // return the position
     return tmpInt;
  }

  // still moving 
  return -1;
}
#65   — Edited

@Athena , Edit and In addition to my last question post, The returned high and low value from the Kangaroo looks like this:

1,P800

or

1,P-20

Another question about these values

Why does the command UART.hardwareUartAvailable(0, 2); return that there are 8 bytes in the Uart and I only see 6 characters?

#66  

sorry for the repost. Again fo Atheina will see it:

@Athena , Edit and In addition to my last question post, The returned high and low value from the Kangaroo looks like this:

1,P800

or

1,P-20

Another question about these values

Why does the command UART.hardwareUartAvailable(0, 2); return that there are 8 bytes in the Uart and I only see 6 characters?

PRO
Synthiam
#67  

Im' guessing its this...

 // get the characters between positions 3 & 7 of the string
     var tmpPart = resp.substring(3, 7);

Because if there's a "-" present, the substring range would be 3, 8

so u could do this..

var tmpPart = "";

if (resp.charAt(3) == '-')
  tmpPart = resp.substring(3, 8);
else
  tmpPart = resp.substring(3, 7);
PRO
Synthiam
#68  

Quote:

Why does the command UART.hardwareUartAvailable(0, 2); return that there are 8 bytes in the Uart and I only see 6 characters?

in the conversation earlier, i mentioned that the response incldues a \r and \n which are new line characters. you can't see new line characters. scroll up and reread for refresh

PRO
Synthiam
#69  

actually that code i posted checking for a - wont' work

there is no way for this to work at all with teh current ascii protocol. the trouble is you have no idea how many characters are in the buffer.

unless you read everything in the buffer. like the entire thing. and process that. but i dunno how that works. the trouble is that protocol ur using for ascii is made for human readible, not computers. it's impossible to predict if there will be a negative character or not, therefor not knowing how long teh string is going to be.

so reading the entire buffer and crossing your fingers would be...

function getMovementValue() {

  // Get Right Channel ARS Kangaroo position
  UART.hardwareUartWriteString(0, "2, Getp\r", 2);

  sleep(100)

  // get bytes available on UART #0, EZB #2
  var avail = UART.hardwareUartAvailable(0, 2);

  // If we don't have at least 9 characters, return -1
  if (avail < 9)
    return -1;

  // read ALL bytes from UART #0 on EZB #2 <- dunno?!
  var resp = UART.hardwareUartReadStringAvailable(0, 2);

  // More verification this is a valid packet
  if (resp[1] != ',')
    throw new Error("Second character should be a ,");

  // Check if we have a capital P, if so, extract
  // the position and return the new value
  if (resp[2] == 'P') {
   
    // get the characters between positions 3 & 7 of the string
      var tmpPart = "";
      
      if (resp.charAt(3) == '-')
        tmpPart = resp.substring(3, 8);
      else
        tmpPart = resp.substring(3, 7);
              
     // convert the string to an int
     var tmpInt = parseInt(tmpPart);
     
     // return the position
     return tmpInt;
  }

  // still moving 
  return -1;
}
PRO
Canada
#70  

For setting and using variables in JavaScript within ARC, the distinction between var (or let/const in modern JavaScript) and setVar() comes down to the scope and persistence of the variable you're working with.

  1. Using var (or let/const): These are standard JavaScript keywords for declaring variables. Variables declared with var, let, or const are local to the script in which they are declared. This means they are not accessible outside of the script they are defined in. They are useful for temporary data that only needs to exist within the context of a single script execution.

    Example:

    var localVariable = "I am local to this script";
    
  2. Using setVar(): This is an ARC-specific function that sets a global variable's value. Global variables in ARC are accessible across different scripts, robot skills, and even between ARC sessions if saved. Use setVar() when you need to store data that must be accessible globally across your ARC project.

    Example:

    setVar("$globalVariable", "I am accessible across scripts");
    

Regarding your question about the UART.hardwareUartAvailable(0,2) returning 8 bytes when you only see 6 characters, this discrepancy is likely due to the inclusion of non-visible control characters in the UART buffer. As DJ_Sures mentioned, the response includes \r (carriage return) and \n (newline) characters, which are counted as bytes but are not visible as characters when printed or displayed. These control characters are commonly used to mark the end of a line of text or a command in communication protocols.

For handling variable-length responses from devices like the Kangaroo, reading the entire buffer and processing the received string, as suggested by DJ_Sures, is a practical approach. This method allows you to dynamically handle responses of different lengths and extract the necessary information regardless of whether there are negative signs or additional characters.

Remember, when working with global variables in ARC, using getVar() and setVar() allows you to access and modify these variables from any script within your project, providing a powerful way to share data across your robot's behaviors.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#71  

Ah, ok. Athena mentions the response includes \r (a carriage return) that I can't see but is there. I had forgotten that.

Now, for reading everything in the buffer and process that, I'll give it a try. Thanks for the guidance! I'll be back.

#72   — Edited

@Athena ,

I'm struggling a bit trying to find a Javascript command that will read a one, two tor three digit number stored in a variable, extract each digit separately, then turn them into different variables so each can be used to trigger different events.

For example, I have been able to do an internet weather API call from an internet weather service and use the downloaded information to get my local weather conditions. I've extracted the temperature from that download and loaded it into a variable that I'm using in an ARC Javascript script. The variable's name is "numberIs", For example sake the temp stored in this variable is the number 82. I have been able to confirm the two digit number is indeed stored in the Variable by doing a JS print command. Next, the peace of the puzzle I need to find;  I need to split that number (82) and use the 8 digit (or what ever number is returned) to trigger my robot to say that number and the 2 digit (or what ever number is returned) to say it's number.

I just need to know how to get each number out of the variable, store it in it's own variable so I can use each one separately. From there I should be able to use each number's variable and finish the script as needed.

It seems there must be a simple answer. I've looked and can't seem to find the answer. Thanks in advance.

PRO
Canada
#73  

To achieve the task of splitting a number into its individual digits and storing each digit in its own variable in JavaScript, you can follow this approach. Given that you have the temperature stored in a variable called numberIs, you can convert the number to a string, then access each character of the string as individual digits. Here's how you can do it:

// Assuming numberIs is your variable that holds the number
var numberIs = 82;

// Convert the number to a string
var numberString = numberIs.toString();

// Now, you can access each digit using indexing
var firstDigit = numberString.charAt(0); // This will be '8'
var secondDigit = numberString.charAt(1); // This will be '2'

// If you need to use the digits as numbers again, convert them back
var firstDigitNumber = parseInt(firstDigit);
var secondDigitNumber = parseInt(secondDigit);

// Now you can use firstDigitNumber and secondDigitNumber as needed
console.log(firstDigitNumber); // Outputs: 8
console.log(secondDigitNumber); // Outputs: 2

This approach works for numbers with any number of digits. If you're dealing with a three-digit number, you can simply add another line to extract the third digit:

var thirdDigit = numberString.charAt(2); // For a three-digit number
var thirdDigitNumber = parseInt(thirdDigit);
console.log(thirdDigitNumber); // Outputs the third digit

Remember, when accessing characters using charAt(index), the index starts at 0. So, charAt(0) gets the first character, charAt(1) gets the second character, and so on.

This method allows you to dynamically handle numbers of varying lengths and use each digit individually in your script.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#74  

OK, thanks @Athena. That sounds pertty stright forward. I guess I can place that in a Function and use it from different parts of the script if wanted.

Another question. I currently live in the subtropics and seldom see the temperature drop below 40 degrees fahrenheit. However when I lived in Wisconsin the temp often would drop below zero in the deep winter. Is there a way for this script to recognize a negative number and deal with it? Would it be as simple as placing a "-" in the command somehow?

PRO
Canada
#75  

Yes, you can indeed place the code in a function and call it from different parts of your script to handle numbers of varying lengths, including handling negative numbers. To recognize and handle negative numbers, you can check if the number is less than zero and then proceed accordingly. Here's how you can modify the function to handle negative numbers:

function processNumber(numberIs) {
  // Check if the number is negative
  var isNegative = numberIs < 0;
  
  // Convert the number to a string and remove the negative sign if present
  var numberString = Math.abs(numberIs).toString();
  
  // Initialize an array to hold the digits
  var digits = [];
  
  // Extract each digit and add to the digits array
  for (var i = 0; i < numberString.length; i++) {
    digits.push(parseInt(numberString.charAt(i)));
  }
  
  // If the number was negative, handle the negative sign
  if (isNegative) {
    console.log("The number is negative.");
    // Perform any specific actions for negative numbers here
  }
  
  // Now you can use the digits array as needed
  console.log(digits); // Outputs the digits array
  
  // Example: Triggering events based on the digits
  digits.forEach(function(digit, index) {
    console.log("Digit " + (index + 1) + ": " + digit);
    // Here you can trigger events based on the digit
  });
}

// Example usage
processNumber(82); // For positive numbers
processNumber(-15); // For negative numbers

This function first checks if the number is negative and stores this information in the isNegative variable. It then converts the number to its absolute value (removing any negative sign) before proceeding to split it into digits. The function stores each digit in an array called digits, which you can then use as needed.

If the number was negative, you can add specific handling for negative numbers within the if (isNegative) block. This could involve setting a flag, printing a message, or performing any other action you need to account for the negative sign.

By encapsulating this logic in a function, you make your script more modular and reusable, allowing you to easily process and handle both positive and negative numbers from different parts of your script.


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.
#76  

I want to report that the method and commands that @Athena helped me with worked great. I didn't implement the negative number method yet as I really don't need it right now. However I have a few other things in mind for that one. Thanks for the help.

PRO
Canada
#77  

You're very welcome! I'm glad to hear that the method and commands worked well for your project. If you decide to implement the negative number handling or have any other questions or ideas you'd like to explore, feel free to reach out. Remember, there's a lot you can achieve with scripting, and I'm here to help you navigate through it. Good luck with your project, and don't hesitate to ask if you need further assistance or have new challenges to tackle. Happy building!


I am a customer support GPT-powered AI and still learning. If you have doubts about my response, please use the support documentation to verify my answer.