QR Code Generator icon QR Code Generator Create customizable QR codes for ARC, display/scan via Camera Control, trigger scripts on recognition and save decoded text to variables. Try it →
Asked

Gripper Servo JS Conversion

,

This is a Script Skill question - could you help convert some EZ-Script I used previously into a JavaScript (ARC Script) version?

Context: This is for a two-arm robot. Each arm uses an older VEX-style claw gripper driven by a servo. I have a small sharp IR detector near each gripper servo to start closing when an object is detected. That IR-based behavior already works. All sensors and servos are connected to an EZB (so ADC readings and servos are handled by the EZB).

Below are the EZ-Script routines I used in the past. I’d like a JavaScript equivalent for use in the ARC Script Robot Skill. The script names are included so you can match the functionality.

EZ-Script for opening/closing both grippers: "Open Grippers" Servo(V25,180) Servo(V9,180)

"Close Grippers" Servo(V25,1) Servo(V9,1)

Gripper IR detector scripts: Grip_detectL (the script name) :claw ADC_Wait(Adc2,lower, 35) servo(V25,30) #Return goto(claw)

Grip_detectR (the script name) :claw ADC_Wait(Adc1,lower, 35) servo(V9,30) #Return goto(claw)

New requirement (added hardware): For each gripper I added a small lever switch that should immediately stop the gripper servo when it contacts the object. This is the EZ-Script I started for the lever-switch stop (I think I’m missing a servo stop somewhere):

Gripper_Object_stop (the script name) :LeverSw #Object detect lever switches (2) $a=GetADC(ADC6) #Right hand lever switch if($a=0) SayEZB("Object now gripped") stop() endif $a=GetADC(ADC7) #Left hand lever switch if($a=0) SayEZB("Object now gripped") stop() endif goto(LeverSw)

Could you look at making a JavaScript version of all of this for use in the ARC Script robot skill (JavaScript)?



Related Hardware (view all EZB hardware)
EZ-B V4 by EZ-Robot
EZ-B v4/2 robot controller: dual Cortex ARM, Wi-Fi, audio/video, 24 servo/digital ports, I2C/UART, camera and Synthiam ARC control for custom robots
Wi-Fi / USB
Servos 24
Camera
Audio
UART 3
I2C
ADC 8
Digital 24

Related Robot Skill (view all robot skills)
Script by Synthiam
Multi-language ARC Script: build, run and debug Blockly, JavaScript, EZ-Script or Python with Intellisense, run/save/load and Roboscratch support

ARC Pro

Upgrade to ARC Pro

Don't limit your robot's potential – subscribe to ARC Pro and transform it into a dynamic, intelligent machine.

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#1  

Absolutely - here’s a clean ARC JavaScript version of your gripper routines, converted from the EZ-Script behavior you described.

A couple of important notes first:

  • In ARC JavaScript, Servo.setPosition() is used instead of Servo(...)
  • ADC.waitForLower() is the direct equivalent of ADC_Wait(Adc#,lower,#)
  • To stop a servo when the lever switch hits, you’ll typically use Servo.release() on that servo port
  • I’d recommend using JavaScript over EZ-Script going forward for this in ARC

1) Open/Close both grippers

// Open Grippers
Servo.setPosition(v25, 180)
Servo.setPosition(v9, 180)

// Close Grippers
Servo.setPosition(v25, 1)
Servo.setPosition(v9, 1)

2) Left gripper IR detect loop

This matches your old Grip_detectL behavior:

while (true) {
  ADC.waitForLower(ADC2, 35)
  Servo.setPosition(v25, 30)
}

3) Right gripper IR detect loop

while (true) {
  ADC.waitForLower(ADC1, 35)
  Servo.setPosition(v9, 30)
}

4) Lever-switch stop routine

Your EZ-Script version is close, but in JavaScript you’ll want to poll the ADC values and then release the servo when the lever switch is triggered.

Assuming:

  • ADC6 = right lever switch
  • ADC7 = left lever switch
  • lever switch reads 0 when pressed
while (true) {
  var rightLever = ADC.get(ADC6)
  if (rightLever == 0) {
    Audio.sayEZB("Object now gripped")
    Servo.release(v9)
    break
  }

  var leftLever = ADC.get(ADC7)
  if (leftLever == 0) {
    Audio.sayEZB("Object now gripped")
    Servo.release(v25)
    break
  }

  sleep(20)
}

Combined example: gripper close until lever switch hits

If you want the servo to move closed until the switch is pressed, this is usually the best pattern:

// Start closing both grippers
Servo.setPosition(v25, 1)
Servo.setPosition(v9, 1)

while (true) {
  var rightLever = ADC.get(ADC6)
  if (rightLever == 0) {
    Audio.sayEZB("Object now gripped")
    Servo.release(v9)
  }

  var leftLever = ADC.get(ADC7)
  if (leftLever == 0) {
    Audio.sayEZB("Object now gripped")
    Servo.release(v25)
  }

  // If both are triggered, stop checking
  if (rightLever == 0 && leftLever == 0) {
    break
  }

  sleep(20)
}

Important correction about "stop"

In ARC, there isn’t really a generic stop() for a servo the way EZ-Script may imply in some script patterns. For a servo, the usual way to stop holding position is:

Servo.release(v9)

or

Servo.release(v25)

That turns off torque/holding for that servo.


ARC Script Skill setup tip

If you’re placing this in a Script Robot Skill, you can use the kebab menu on the Script skill and open Settings, then choose JavaScript, paste the script, and save it.


One thing I’d like to confirm

To make sure the conversion behaves exactly right, can you confirm these two details?

  1. Are v25 and v9 definitely virtual servo ports from a servo plugin skill, or are those actual servo ports on the EZ-B?
  2. Do you want the lever switch to:
    • release the servo immediately when touched, or
    • hold at the current position by stopping movement some other way?

If you want, I can also rewrite this as a more complete single ARC JavaScript routine with:

  • openGrippers()
  • closeGrippers()
  • monitorGrippers()

so it’s easier to reuse in your project.


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.
#2  

I'm liking what I see here. To answer some of your questions....

>> When the gripper begins to close onto the object, it should just stop, still being able to have a good grip on the object (not letting it fall out of the grip unless I want it to release the object) >> When the gripper servo begins to close on the object, I'm thinking the gripper servo should "move slow" (like half speed)

>> The 2 servo ports v9 and v25 are from the SSC32 I am using for all arm servos >> ADC1 is for Right Gripper IR detect >> ADC2 is for Left Gripper IR detect >> ADC6 is for Right Gripper Lever stop >> ADC7 is for Left Gripper Lever stop

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#3  

Great - that helps a lot. Since v9 and v25 are SSC-32 virtual servo ports, the best approach is:

  • close slowly
  • stop when the lever switch is pressed
  • do not release the servo, so the claw keeps holding the object

That means we should use Servo.setSpeed() to slow the servo motion, and then leave torque/holding enabled. Servo.release() would let go, which you don’t want when the object is grabbed.

Below is a clean version you can paste into a Script Robot Skill in JavaScript.

// Ports
var rightGripperServo = v9;
var leftGripperServo = v25;

var rightIr = ADC1;
var leftIr = ADC2;

var rightLever = ADC6;
var leftLever = ADC7;

// Speed: 0 = fastest, 10 = slowest
// For "half speed", start with 5 and adjust as needed.
var closeSpeed = 5;

// -----------------------------------------------------------------------------
// Open both grippers
// -----------------------------------------------------------------------------
function openGrippers() {
  Servo.setSpeed(rightGripperServo, 0);
  Servo.setSpeed(leftGripperServo, 0);

  Servo.setPosition(rightGripperServo, 180);
  Servo.setPosition(leftGripperServo, 180);
}

// -----------------------------------------------------------------------------
// Close both grippers slowly until lever switch is hit
// -----------------------------------------------------------------------------
function closeGrippersSlowUntilSwitch() {
  // Set slow motion for the close
  Servo.setSpeed(rightGripperServo, closeSpeed);
  Servo.setSpeed(leftGripperServo, closeSpeed);

  // Start closing
  Servo.setPosition(rightGripperServo, 1);
  Servo.setPosition(leftGripperServo, 1);

  var rightStopped = false;
  var leftStopped = false;

  while (true) {
    // Right gripper lever switch
    if (!rightStopped && ADC.get(rightLever) == 0) {
      print("Right object now gripped");
      // Do NOT release - keep holding position
      rightStopped = true;
    }

    // Left gripper lever switch
    if (!leftStopped && ADC.get(leftLever) == 0) {
      print("Left object now gripped");
      // Do NOT release - keep holding position
      leftStopped = true;
    }

    // Stop only that side by commanding current position again
    // This helps prevent further closing once the switch is hit.
    if (rightStopped) {
      Servo.setPosition(rightGripperServo, Servo.getPosition(rightGripperServo));
    }

    if (leftStopped) {
      Servo.setPosition(leftGripperServo, Servo.getPosition(leftGripperServo));
    }

    if (rightStopped && leftStopped) {
      break;
    }

    sleep(20);
  }
}

// -----------------------------------------------------------------------------
// Close right gripper only when its IR sensor detects an object
// -----------------------------------------------------------------------------
function gripDetectRight() {
  while (true) {
    ADC.waitForLower(rightIr, 35);
    Servo.setSpeed(rightGripperServo, closeSpeed);
    Servo.setPosition(rightGripperServo, 1);

    while (true) {
      if (ADC.get(rightLever) == 0) {
        print("Right object now gripped");
        break;
      }
      sleep(20);
    }

    // Hold position; do not release
    Servo.setSpeed(rightGripperServo, 0);
  }
}

// -----------------------------------------------------------------------------
// Close left gripper only when its IR sensor detects an object
// -----------------------------------------------------------------------------
function gripDetectLeft() {
  while (true) {
    ADC.waitForLower(leftIr, 35);
    Servo.setSpeed(leftGripperServo, closeSpeed);
    Servo.setPosition(leftGripperServo, 1);

    while (true) {
      if (ADC.get(leftLever) == 0) {
        print("Left object now gripped");
        break;
      }
      sleep(20);
    }

    // Hold position; do not release
    Servo.setSpeed(leftGripperServo, 0);
  }
}

How I would improve this for your robot

For SSC-32 servos, the cleanest logic is:

  1. IR sensor detects object
  2. servo moves closed slowly
  3. lever switch triggers
  4. servo stops commanding further movement
  5. servo keeps holding the object

The important part is step 4. We do not use Servo.release() if the claw needs to keep gripping.

One caution

This line:

Servo.setPosition(rightGripperServo, Servo.getPosition(rightGripperServo));

is a simple way to re-command the current position, but depending on how the SSC-32 skill is configured, you may prefer to stop by simply breaking out of the loop and letting the servo keep the last commanded position. In many cases that is enough.

A cleaner version is:

while (true) {
  if (ADC.get(rightLever) == 0) {
    print("Right object now gripped");
    break;
  }
  sleep(20);
}

and then just exit. If the servo and SSC-32 are already holding position, that may be all you need.

Even better version: separate functions per arm

If you want, I can turn this into a more organized script like:

  • openRightGripper()
  • openLeftGripper()
  • closeRightGripperOnIR()
  • closeLeftGripperOnIR()
  • monitorLeverStops()

That would make the project easier to maintain.

ARC configuration note

Since this is the SSC-32 servo Controller skill, make sure:

  • the skill is added in ARC
  • the ports are mapped correctly to V9 and V25
  • you configure the script in the Script skill settings
  • use the kebab menu on the Script skill to open Settings
  • choose JavaScript
  • paste the script and save

SSC-32 skill manual for reference: https://synthiam.com/Support/Skills/Servo/SSC-32-Servo-Controller?id=16180

A question so I can tighten this up

Do you want:

  1. one script that manages both arms together, or
  2. separate scripts for left and right grippers?

If you want, I can give you the final polished ARC JavaScript in whichever style you prefer.


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.
#4  

So I just tried this script you created...

// Ports
var rightGripperServo = v9;
var leftGripperServo = v25;
var rightIr = ADC1;
var leftIr = ADC2;
var rightLever = ADC6;
var leftLever = ADC7;
// Speed: 0 = fastest, 10 = slowest
// For "half speed", start with 5 and adjust as needed.
var closeSpeed = 10;
// -----------------------------------------------------------------------------
// Open both grippers
// -----------------------------------------------------------------------------
function openGrippers() {
 Servo.setSpeed(rightGripperServo, 1);
 Servo.setSpeed(leftGripperServo, 1);
 Servo.setPosition(rightGripperServo, 180);
 Servo.setPosition(leftGripperServo, 180);
}
// -----------------------------------------------------------------------------
// Close both grippers slowly until lever switch is hit
// -----------------------------------------------------------------------------
function closeGrippersSlowUntilSwitch() {
 // Set slow motion for the close
 Servo.setSpeed(rightGripperServo, closeSpeed);
 Servo.setSpeed(leftGripperServo, closeSpeed);
 // Start closing
 Servo.setPosition(rightGripperServo, 1);
 Servo.setPosition(leftGripperServo, 1);
 var rightStopped = false;
 var leftStopped = false;
 while (true) {
 // Right gripper lever switch
 if (!rightStopped && ADC.get(rightLever) == 0) {
 print("Right object now gripped");
 // Do NOT release - keep holding position
 rightStopped = true;
 }
 // Left gripper lever switch
 if (!leftStopped && ADC.get(leftLever) == 0) {
 print("Left object now gripped");
 // Do NOT release - keep holding position
 leftStopped = true;
 }
 // Stop only that side by commanding current position again
 // This helps prevent further closing once the switch is hit.
 if (rightStopped) {
 Servo.setPosition(rightGripperServo, Servo.getPosition(rightGripperServo));
 }
 if (leftStopped) {
 Servo.setPosition(leftGripperServo, Servo.getPosition(leftGripperServo));
 }
 if (rightStopped && leftStopped) {
 break;
 }
 sleep(20);
 }
}
// -----------------------------------------------------------------------------
// Close right gripper only when its IR sensor detects an object
// -----------------------------------------------------------------------------
function gripDetectRight() {
 while (true) {
 ADC.waitForLower(rightIr, 35);
 Servo.setSpeed(rightGripperServo, closeSpeed);
 Servo.setPosition(rightGripperServo, 1);
 while (true) {
 if (ADC.get(rightLever) == 0) {
 print("Right object now gripped");
 break;
 }
 sleep(20);
 }
 // Hold position; do not release
 Servo.setSpeed(rightGripperServo, 0);
 }
}
// -----------------------------------------------------------------------------
// Close left gripper only when its IR sensor detects an object
// -----------------------------------------------------------------------------
function gripDetectLeft() {
 while (true) {
 ADC.waitForLower(leftIr, 35);
 Servo.setSpeed(leftGripperServo, closeSpeed);
 Servo.setPosition(leftGripperServo, 1);
 while (true) {
 if (ADC.get(leftLever) == 0) {
 print("Left object now gripped");
 break;
 }
 sleep(20);
 }
 // Hold position; do not release
 Servo.setSpeed(leftGripperServo, 0);
 }
}

But when I go and click start it immediately says Done. Why is this? is something missing here?

Author Avatar
PRO
Canada
Twitter YouTube GitHub
#5  

Yes - something is missing.

In an ARC Script Robot Skill, defining functions like:

function openGrippers() { ... }
function closeGrippersSlowUntilSwitch() { ... }

does not run them automatically. ARC executes the script from top to bottom, and if the script only contains function definitions, it finishes immediately, which is why you see Done right away.

Why it ends immediately

Your script currently only declares functions. It never calls one.


Fix

You need to call the function at the bottom of the script, for example:

closeGrippersSlowUntilSwitch();

Example: working version

Here’s a simple version that will actually run when you press Start:

var rightGripperServo = v9;
var leftGripperServo = v25;
var rightIr = ADC1;
var leftIr = ADC2;
var rightLever = ADC6;
var leftLever = ADC7;

var closeSpeed = 10;

function closeGrippersSlowUntilSwitch() {
  Servo.setSpeed(rightGripperServo, closeSpeed);
  Servo.setSpeed(leftGripperServo, closeSpeed);

  Servo.setPosition(rightGripperServo, 1);
  Servo.setPosition(leftGripperServo, 1);

  var rightStopped = false;
  var leftStopped = false;

  while (true) {
    if (!rightStopped && ADC.get(rightLever) == 0) {
      print("Right object now gripped");
      rightStopped = true;
    }

    if (!leftStopped && ADC.get(leftLever) == 0) {
      print("Left object now gripped");
      leftStopped = true;
    }

    if (rightStopped && leftStopped) {
      break;
    }

    sleep(20);
  }
}

closeGrippersSlowUntilSwitch();

Important note about "stopping" the servo

If you want the gripper to hold the object, do not use Servo.release().

Instead, what you usually want is:

  • keep the servo holding torque
  • stop sending further closing motion
  • or keep the servo at its current commanded position

Better approach for your case

Since you’re using an SSC-32, it may be better to close the gripper in a loop, and when the lever switch hits, simply break out of the loop without releasing the servo.

Example:

var rightGripperServo = v9;
var leftGripperServo = v25;
var rightLever = ADC6;
var leftLever = ADC7;

var closeSpeed = 10;

Servo.setSpeed(rightGripperServo, closeSpeed);
Servo.setSpeed(leftGripperServo, closeSpeed);

Servo.setPosition(rightGripperServo, 1);
Servo.setPosition(leftGripperServo, 1);

while (true) {
  var rightHit = ADC.get(rightLever) == 0;
  var leftHit = ADC.get(leftLever) == 0;

  if (rightHit) {
    print("Right object now gripped");
  }

  if (leftHit) {
    print("Left object now gripped");
  }

  if (rightHit && leftHit) {
    break;
  }

  sleep(20);
}

One more thing

Your old openGrippers() and gripDetectRight() / gripDetectLeft() functions also need to be called if you want them to run.

For example:

openGrippers();

or

gripDetectRight();

Quick question

How do you want this to behave when you press Start?

  1. Open the grippers
  2. Close both grippers and monitor the lever switches
  3. Run the IR detect loops continuously
  4. Have separate scripts/buttons for each action

If you want, I can give you a clean final ARC JavaScript script with:

  • openGrippers()
  • closeGrippers()
  • monitorGripperStops()

all wired so it runs properly when started.


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.
#6  

I added the last line you suggested.

closeGrippersSlowUntilSwitch();

but when I clicked Start, I immediately got this...

Start
Right object now gripped
Left object now gripped
Done (00:00:00.0012839)
Author Avatar
PRO
Canada
Twitter YouTube GitHub
#7  

That tells us the script is running correctly, but your lever inputs are already reading as triggered.

Since both messages appear instantly:

  • Right object now gripped
  • Left object now gripped

that means:

ADC.get(ADC6) == 0
ADC.get(ADC7) == 0

is already true at startup.

Most likely causes

1) The lever switches are wired as normally closed

If the switch is normally closed, 0 may mean not pressed instead of pressed.

2) The ADC ports are floating or miswired

If the sensor inputs are not connected properly, ADC can read as 0 or some unstable value.

3) The logic is inverted

You may need to trigger on > 0 or >= 35 instead of == 0.


Quick test script

Run this to see what the ADC values are doing:

while (true) {
  print("ADC6 Right Lever = " + ADC.get(ADC6));
  print("ADC7 Left Lever = " + ADC.get(ADC7));
  sleep(500);
}

What to look for:

  • If they stay at 0 all the time, the wiring or input mode needs checking
  • If they jump around, the input may be floating
  • If they go high when pressed, then the logic should be reversed

If the switch is active-high instead

If the lever switch reads 1 or higher when pressed, then use this instead:

var rightGripperServo = v9;
var leftGripperServo = v25;
var rightLever = ADC6;
var leftLever = ADC7;
var closeSpeed = 10;

Servo.setSpeed(rightGripperServo, closeSpeed);
Servo.setSpeed(leftGripperServo, closeSpeed);
Servo.setPosition(rightGripperServo, 1);
Servo.setPosition(leftGripperServo, 1);

while (true) {
  var rightHit = ADC.get(rightLever) > 0;
  var leftHit = ADC.get(leftLever) > 0;

  if (rightHit) {
    print("Right object now gripped");
  }

  if (leftHit) {
    print("Left object now gripped");
  }

  if (rightHit && leftHit) {
    break;
  }

  sleep(20);
}

If you want to use the IR sensor to start closing, then the lever to stop

A better structure would be:

var rightGripperServo = v9;
var leftGripperServo = v25;
var rightIr = ADC1;
var leftIr = ADC2;
var rightLever = ADC6;
var leftLever = ADC7;
var closeSpeed = 10;

while (true) {
  if (ADC.get(rightIr) < 35) {
    Servo.setSpeed(rightGripperServo, closeSpeed);
    Servo.setPosition(rightGripperServo, 1);

    while (ADC.get(rightLever) == 0) {
      sleep(20);
    }

    print("Right object now gripped");
  }

  if (ADC.get(leftIr) < 35) {
    Servo.setSpeed(leftGripperServo, closeSpeed);
    Servo.setPosition(leftGripperServo, 1);

    while (ADC.get(leftLever) == 0) {
      sleep(20);
    }

    print("Left object now gripped");
  }

  sleep(20);
}

What I need from you

Can you tell me what the raw ADC values are for:

  • ADC6 when the right lever is not pressed
  • ADC6 when the right lever is pressed
  • ADC7 when the left lever is not pressed
  • ADC7 when the left lever is pressed

That will let me give you the exact final JavaScript logic for your switch type.

If you want, I can also help you build a single polished ARC script that:

  • watches the IR sensors
  • closes slowly
  • stops on lever contact
  • keeps holding the object
  • and separately opens the grippers on command

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.
#8  

So I ran your test script to test the state of my grippers lever switches.....

while (true) {
  print("ADC6 Right Lever = " + ADC.get(ADC6));
  print("ADC7 Left Lever = " + ADC.get(ADC7));
  sleep(500);
}

This is the test results....

ADC7 Left Lever = 255
ADC6 Right Lever = 255
ADC7 Left Lever = 255
ADC6 Right Lever = 0
ADC7 Left Lever = 254
ADC6 Right Lever = 0
ADC7 Left Lever = 255

In idle state, the reading is a value of 255. When the lever switch is pressed it returns a value of 0. The Zero state is what I want to trigger the gripper servo to stop. So where does this get changes in the code you provided earlier?