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 robotics. The servo lineup currently includes three “smart servos” which appear physically the same, sharing the same dimensions, mounting points and output spline, but differing in maximum torque and speed.
Getting Started:
Action Commands:
The lynx motion has a simple serial protocol for controlling the motor, that is human-readable:
Number sign #
Servo ID number as an integer
Action command (two to three letters, no spaces, capital or lower case)
Configuration value in the correct units with no decimal
End with a control / carriage return '<cr>'
Ex: #5PD1443<cr>
Additional Parts:
Hookup with Power-hub
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 cycles through the LED colours of the smart servos.
Important. The folowing examples are writen using Lynx smart motion Arduino library 1.4.1. Newer versions no longer support Software Serial. If you wish to be able to select which pins the servos are connected to (as in examples below), install the older version of the library-
#include <LSS.h> #include <SoftwareSerial.h> SoftwareSerial servoSerial(8, 9); // give the id matching your device #define LSS_ID (254) // ID 254 to broadcast to every motor on bus // 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
#include <LSS.h> #include <SoftwareSerial.h> SoftwareSerial servoSerial(8, 9); #define LSS_ID (254) // ID 254 to broadcast to every motor on bus #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); }
Multiple Servos
For controlling multiple servos, you will first need to give each motor a unique ID. You will need to attach each motor separately, and modify the code below to change it’s ID to a value between 0 and 253.
#include <LSS.h> #include <SoftwareSerial.h> SoftwareSerial servoSerial(8, 9); // ID set to default LSS ID = 0 #define LSS_ID_old (254) // ID 254 to broadcast to every motor on bus #define LSS_ID (0) // the new ID #define LSS_BAUD (LSS_DefaultBaud) // Create one LSS object LSS myLSS = LSS(LSS_ID); void setup() { // set the data rate for the SoftwareSerial port servoSerial.begin(LSS_BAUD); // this is used to clear the serial buffer servoSerial.print("#0D1500\r"); delay(1000); LSS::initBus(servoSerial, LSS_BAUD); //change ID servoSerial.print(String("#") + LSS_ID_old + String("CID") + LSS_ID + "\r"); delay(2000); } void loop() { }
Now you can control two motors at the same time:
#include <LSS.h> #include <SoftwareSerial.h> SoftwareSerial servoSerial(8, 9); #define LSS_ID1 (1) #define LSS_ID2 (0) #define LSS_BAUD (LSS_DefaultBaud) // Create two LSS objects LSS myLSS1 = LSS(LSS_ID1); LSS myLSS2 = LSS(LSS_ID2); int direction = -1; void setup() { servoSerial.begin(LSS_BAUD); // Initialize the LSS bus LSS::initBus(servoSerial, LSS_BAUD); Serial.begin(LSS_BAUD); } void loop() { // motor direction myLSS1.wheelRPM(-direction*60); myLSS2.wheelRPM(60*direction); delay(4000); // revers dierction direction = -direction; }
Troubleshooting
A reset may sometimes be needed
#include <LSS.h> #include <SoftwareSerial.h> SoftwareSerial servoSerial(8, 9); // ID set to default LSS ID = 0 #define LSS_ID_old (254) // ID 254 to broadcast to every motor on bus #define LSS_BAUD (LSS_DefaultBaud) // Create one LSS object LSS myLSS = LSS(LSS_ID); void setup() { // set the data rate for the SoftwareSerial port servoSerial.begin(LSS_BAUD); // this is used to clear the serial buffer servoSerial.print("#0D1500\r"); delay(1000); LSS::initBus(servoSerial, LSS_BAUD); // reset servoSerial.print(String("#") + LSS_ID_old + String("DEFAULT")+"\r"); servoSerial.print(String("#") + LSS_ID_old + 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 one solution, but it could use some improvement: It needs a denounce and a pause without delay function to avoid blocking your code.
#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.
#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); // bool timing = true; long timer = 0; long lastTimer = 0; int lastTimerSecond; 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 buttonStartStop.setCallback(startStop); buttonReset.setCallback(resetTimer); } void loop() { buttonStartStop.update(); buttonReset.update(); if (timing) { updateTimer(); if (getTimerSeconds() > lastTimerSecond) { int ServoPosition = getTimerSeconds() * 60; // if we divide 360 by 60 we get 6.0 degrees myLSS.move(ServoPosition); // move servo to position Serial.println(getTimerSeconds()); lastTimerSecond = getTimerSeconds(); } } } void startStop(int state) { // start or stop the timer if (state == HIGH) { // stop or start Serial.println("Start / Stop"); timing = !timing; lastTimer = millis(); // record that time when we last started or stoped the timer } } void resetTimer(int state) { if (digitalRead(11) == HIGH) { Serial.println("reset"); myLSS.move(0); timer = 0; // reset Timer lastTimerSecond = getTimerSeconds(); } } int getTimerSeconds() { return floor((timer) / 1000); } void updateTimer() { 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.