Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

The Lynxmotion Smart Servos (LSS) are compact, modular and configurable actuators designed to be an evolution of the standard RC servo for use in multi-degree-of-freedom roboticsthat provide greater control than standard PWM servos. The servo lineup currently includes three “smart servos” which appear physically the same, sharing the same dimensions , and mounting points and output spline, but differing in maximum torque and speed. 

Getting Started:

...

Overview

...

Power: The servos need 6-12V, and 12v for maximum speed and torque.

Getting Started:

Action Commands:

The lynx motion has a simple serial protocol for controlling the motor, that is human-readable:

  1. Number sign #

  2. Servo ID number as an integer

  3. Action command (two to three letters, no spaces, capital or lower case)

  4. Configuration value in the correct units with no decimal

  5. End with a control / carriage return '<cr>'

Ex: #5PD1443<cr>

Additional Parts:

Example Code for Arduino

While the Arduino library is not necessarily needed to control the smart servos, some of these examples make use of it.

This example is for changing the ID of the servo motor.

...

Hookup with Power-hub

The power hub is the most universal way of connecting to the motors. You will need an external power source with a 5mm jack for 12v. Care should be taken when connecting the VIN pin, as this will be 12 volts!

...

Example Code for Arduino

Ther is a custom LSS library for Arduino, but it's not necessarily needed to control the smart servos, and it is not compatible with the IAD shields for both MKR and Arduino Uno.

This example cycles through the LED colours of the smart servos.

Code Block
languagec#
#include <SoftwareSerial.h>

#define rxPin 8
#define txPin 9
SoftwareSerial servoSerialmySerial(8rxPin, 9txPin);  // IDCreate setthe tonew defaultsoftware LSSserial ID =instance
0
#define LSS_ID_old 254 // ID 254 to broadcast to every motor on bus
#define
LSS_ID 1


void setup()
{
  mySerial.begin(115200); // set Important! this is the datastandard ratespeed for thetalking SoftwareSerialto port,LSS
115200 is default for lynxmotion
  servoSerial.begin(115200);
 mySerial.print("#0D1500\r");  // this is used to clear the serial buffer
}

servoSerial.print("#0D1500\r");
  delay(1000);
  void loop()
{
	// changeLoop IDthrough each of  servoSerial.print(String("#") + LSS_ID_old + String("CID") + LSS_ID + "\r");
  // Uncomment next line for factory reset  
  //servoSerial.print(String("#") + LSS_ID_old + String("DEFAULT")+"\r");
  delay(2000);
  // a reset is required for the changes to take effect
}

This example cycles through the LED colours of the smart servos.

Code Block
languagec#
#include <LSS.h>
#include <SoftwareSerial.h>

SoftwareSerial servoSerial(8, 9);
// give the id matching your device
#define LSS_ID   (0)
// Create one LSS object
LSS myLSS = LSS(LSS_ID);

void setup()
{
  servoSerial.begin(LSS_DefaultBaud);
  LSS::initBus(servoSerial, LSS_DefaultBaud);
}

void loop()
{
	// Loop through each of the 8 LED color (black = 0, red = 1, ..., white = 7)
	for (uint8_t i = LSS_LED_Black; i <= LSS_LED_White; i++){
	// Set the color (session only) of the LSS
    //> https://www.robotshop.com/info/wiki/lynxmotion/view/lynxmotion-smart-servo/lss-communication-protocol/#H14.LEDColor28LED29
    // Options are:
    // LSS_LED_Black = 0
    // LSS_LED_Red = 1
    // LSS_LED_Green = 2
    // LSS_LED_Blue = 3
    // LSS_LED_Yellow = 4
    // LSS_LED_Cyan = 5
    // LSS_LED_Magenta = 6
    // LSS_LED_White = 7
	  myLSS.setColorLED((LSS_LED_Color) i);
	 delay(1000);
	}
}

This example goes through the basic setup and movement

Code Block
languagecpp
#include <LSS.h>
#include <SoftwareSerial.h>
SoftwareSerial servoSerial(8, 9);

// ID set to default LSS ID = 0
#define LSS_ID		(0)
#define LSS_BAUD	(LSS_DefaultBaud)

// Create one LSS object
LSS myLSS = LSS(LSS_ID);

void setup() {
  servoSerial.begin(LSS_BAUD);
  // Initialize the LSS bus
  LSS::initBus(servoSerial, LSS_BAUD);
  Serial.begin(LSS_BAUD);
}

void loop() {
  // Move the LSS continuously in one direction
  myLSS.wheelRPM(10);
  delay(5000);
  // Move the LSS continuously in the oposite direction
  myLSS.wheelRPM(-10);
  delay(5000);
  // faster!
  myLSS.wheelRPM(-60);
  delay(3000);
  // go Limp!
  myLSS.limp();
  delay(5000);
  // move relative from current position in 1/10° (i.e 100 = 10 degrees)
  myLSS.moveRelative(100);
  delay(5000);
  // Move to specific position in 1/10° (i.e 100 = 10 degrees)
  myLSS.move(400);
  delay(7000);
}

Exercise:

Build a stopwatch with the smart servo and two buttons.

The movement of servo indicates the seconds elapsed. 

Clicking the first button starts and stops the stopwatch. The 2nd button resets the stopwatch.

TIP: Use the millis() function to find the elapsed time.

...

Code Block
languagec#
#include <LSS.h>
#include <SoftwareSerial.h>
SoftwareSerial servoSerial(8, 9the 8 LED color (black = 0, red = 1, ..., white = 7)
	for (uint8_t LEDCode = 0; LEDCode <= 7; LEDCode++){
	// Set the color (session only) of the LSS
    // Options are:
    // LSS_LED_Black = 0
    // LSS_LED_Red = 1
    // LSS_LED_Green = 2
    // LSS_LED_Blue = 3
    // LSS_LED_Yellow = 4
    // LSS_LED_Cyan = 5
    // LSS_LED_Magenta = 6
    // LSS_LED_White = 7
	  mySerial.print(String("#") + LSS_ID + String("LED") + LEDCode + "\r"); // set LED
	 delay(1000);
	}
}

This example goes through the basic setup and movement

Code Block
languagecpp
#include <SoftwareSerial.h>

#define rxPin 8
#define txPin 9
SoftwareSerial mySerial(rxPin, txPin);  // Create the new software serial instance

#define LSS_ID 254 // ID 254 to broadcast to every motor on bus

void setup()
{
  mySerial.begin(115200); // Important! this is the standard speed for talking to LSS
  mySerial.print("#0D1500\r");  // this is used to clear the serial buffer
}

void loop() {
  // Move the LSS continuously in one direction
  mySerial.print(String("#") + LSS_ID + String("WR") + 10  + "\r"); // RPM move
  delay(5000);
  // Move the LSS continuously in the oposite direction
  mySerial.print(String("#") + LSS_ID + String("WR") + -10  + "\r"); // RPM move
  delay(5000);
  // faster!
  mySerial.print(String("#") + LSS_ID + String("WR") + -60  + "\r"); // RPM move
  delay(3000);
  // go Limp!
 mySerial.print(String("#") + LSS_ID + String("L") + "\r"); // Limp
  delay(5000);
  // move relative from current position in 1/10° (i.e 100 = 10 degrees)
  mySerial.print(String("#") + LSS_ID + String("D") + int(60*10)  + "\r"); // move 100 degrees
  delay(5000);
  // Move to specific position in 1/10° (i.e 100 = 10 degrees)
  mySerial.print(String("#") + LSS_ID + String("D") + int(360*10)  + "\r"); // move 360 degrees
  delay(7000);
}

Multiple Servos

For controlling multiple servos, you will first need to give each motor a unique ID. You must attach each motor separately and modify the code below to change its ID to a value between 0 and 253. Afterwards, the servo will always remember it’s new ID.

Code Block
languagec#
#include <SoftwareSerial.h>

SoftwareSerial mySerial(8, 9);

// ID set to default LSS ID = 0
#define LSS_ID_old 354 // ID 254 to broadcast to every motor on bus
#define LSS_ID  0 // the new ID 


// Create one LSS object
LSS myLSS = LSS(LSS_ID);

void setup()
{
  mySerial.begin(115200); // Important! this is the standard speed for talking to LSS
  mySerial.print("#0D1500\r");  // this is used to clear the serial buffer
  delay(1000);
  //change ID 
  mySerial.print(String("#") + LSS_ID_old + String("CID") + LSS_ID + "\r");
  delay(2000);
}
void loop() {
}

Now you can control two motors at the same time:

Code Block
languagecpp
#include <SoftwareSerial.h>

SoftwareSerial mySerial(8, 9);

#define LSS_ID1  1 
#define LSS_ID2  0


int direction = -1;

void setup() {
  mySerial.begin(115200); // Important! this is the standard speed for talking to LSS
  mySerial.print("#0D1500\r");  // this is used to clear the serial buffer
}

void loop() {
  // motor direction 
  mySerial.print(String("#") + LSS_ID + String("WR") +-direction*60) + "\r"); // RPM move
  mySerial.print(String("#") + LSS_ID + String("WR") + 60*direction  + "\r"); // RPM move
  delay(5000);
  // reverse direction 
  direction = -direction;
}

Troubleshooting

A reset may sometimes be needed

Code Block
languagec#
#include <SoftwareSerial.h>

SoftwareSerial servoSerial(8, 9);

// ID set to default LSS ID = 0
#define LSS_ID 254 // ID 254 to broadcast to every motor on bus

void setup()
{
mySerial.begin(115200); // Important! this is the standard speed for talking to LSS
  mySerial.print("#0D1500\r");  // this is used to clear the serial buffer
  delay(1000);
  //  reset
  mySerial.print(String("#") + LSS_ID + String("DEFAULT")+"\r");
  delay(500);
  mySerial.print(String("#") + LSS_ID + String("CONFIRM")+"\r");
  delay(2000);
}
void loop() {
}

Exercise:

Build a stopwatch with the smart servo and two buttons.

The movement of servo indicates the seconds elapsed. 

Clicking the first button starts and stops the stopwatch. The 2nd button resets the stopwatch.

TIP: Use the millis() function to find the elapsed time.


Possible Solution:  This is one solution but it could use some improvement: It needs a denounce and a pause without delay function to avoid blocking your code. This solution uses an older arduino library that might need to be updated.

Code Block
languagec#
#include <LSS.h>
#include <SoftwareSerial.h>
SoftwareSerial servoSerial(8, 9);

// ID set to default LSS ID = 0
#define LSS_ID    (0)
#define LSS_BAUD  (LSS_DefaultBaud)

// Create one LSS object
LSS myLSS = LSS(LSS_ID);
int ServoPosition = 0;
bool counting = true;
int resetTime = 0;
int lastMovement;

void setup() {
  servoSerial.begin(LSS_BAUD);
  // Initialize the LSS bus
  LSS::initBus(servoSerial, LSS_BAUD);
  Serial.begin(LSS_BAUD);
  myLSS.move(0);
  // allow time to move to 0 position
  delay(3000);
  myLSS.setMaxSpeed(600, LSS_SetConfig);
  //buttons 
  pinMode(11, INPUT);
  pinMode(10, INPUT);
}

void loop() {
 delay(1000);
  if (counting) {
    int seconds = (millis() - resetTime)/1000; // see below for an explanation of resetTime 
    ServoPosition = seconds * 60;  // if we divide 360 by 60 we get 6.0 degrees
    myLSS.move(ServoPosition); // move servo to position
    Serial.println(seconds);
    lastMovement = millis();
  } else {
    resetTime = millis() - lastMovement; // this helps us return to the last position of the clock movement
  }
  // buttons 
  if (digitalRead(10) == HIGH) {
      // stop or start
     counting = !counting;
     Serial.println("Start/Stop");
     // this could be improved on with a debounce!
  }
   if (digitalRead(11) == HIGH) {
    // reset
      Serial.println("reset");
      myLSS.move(0);
      delay(2000);
      resetTime = millis();  // we use this to restart our counter from 0 
  }
}

Here is a better solution, that is non-blocking and implements debouncing with a debounce library.

Code Block
#include <LSS.h>
#include <SoftwareSerial.h>
#include <ButtonDebounce.h>

#define pinStopStart 10
#define pinReset 11

SoftwareSerial servoSerial(8, 9);
ButtonDebounce buttonStartStop(pinStopStart, 250);
ButtonDebounce buttonReset(pinReset, 250);

// ID set to default LSS ID = 0
#define LSS_ID    (0)
#define LSS_BAUD  (LSS_DefaultBaud)

// Create one LSS object
LSS myLSS = LSS(LSS_ID);
int ServoPosition//
bool timing = 0true;
boollong countingtimer = true0;
intlong resetTimelastTimer = 0;
int lastMovementlastTimerSecond;

void setup() {
  servoSerial.begin(LSS_BAUD);
  // Initialize the LSS bus
  LSS::initBus(servoSerial, LSS_BAUD);
  Serial.begin(LSS_BAUD);
  myLSS.move(0);
  // allow time to move to 0 position
  delay(3000);
  myLSS.setMaxSpeed(600, LSS_SetConfig);
  //buttons
   pinMode(11, INPUTbuttonStartStop.setCallback(startStop);
  pinMode(10, INPUTbuttonReset.setCallback(resetTimer);
}

void loop() {
  buttonStartStop.update();
 delay buttonReset.update(1000);
  if (countingtiming) {
    int seconds = (millisupdateTimer();
    if (getTimerSeconds() -> resetTimelastTimerSecond)/1000; // see below for an explanation of resetTime 
     {
      int ServoPosition = secondsgetTimerSeconds() * 60;  // if we divide 360 by 60 we get 6.0 degrees
      myLSS.move(ServoPosition); // move servo to position
    Serial.println(seconds); position
    lastMovement = millisSerial.println(getTimerSeconds());
  } else {     resetTimelastTimerSecond = millisgetTimerSeconds();
- lastMovement; // this helps}
us return to}
the}
last
positionvoid of the clock movement
  }
  // buttonsstartStop(int state) {
  // start or stop the timer 
  if (digitalRead(10)state == HIGH) {

     // stop or start
    Serial.println("Start / Stop");
    countingtiming = !countingtiming;
    lastTimer = Serial.println("Start/Stop");
     // this could be improved on with a debounce!
  }
millis(); // record that time when we last started or stoped the timer 
  }
}

void resetTimer(int state) {
  if (digitalRead(11) == HIGH) {
   HIGH) {
    Serial.println("reset");
    myLSS.move(0);
    timer = 0;  // reset Timer
     Serial.println("reset"lastTimerSecond = getTimerSeconds();
  }
}

int myLSS.movegetTimerSeconds(0); {
  return floor((timer) / delay(20001000);
}

    resetTime = millisvoid updateTimer();  // we use this to restart our counter from 0 
  }
}{
  timer += millis() - lastTimer;
  lastTimer = millis();
}

Wifi and Lynx Smart Motion

Here is an example for connecting processing to Arduino wifi rev 2 wirelessly with shiftr.io.

View file
nameWiFiLynxMotion.zip