Sign In

Remember Me

Sabertooth Kangaroo Question

Home Forums Electrical & Controls Sabertooth Kangaroo Question



This topic contains 9 replies, has 3 voices, and was last updated by  SuperDroid 2 months ago.

Viewing 10 posts - 1 through 10 (of 10 total)
  • Author
    Posts
  • #1299

    tomega3
    Participant

    Hi, does anyone have any example sketches for an arduino
    driving the dimension engineering kangaroo in mixed mode
    using packetized serial commands?

    I am not a C++ expert and can’t figure out how to use
    their error and status reporting or how to use their monitoring objects.

    I have my 2 wheel differential drive robot driving and turning
    using their packetized serial commands using an arduino
    mega 2560 and the Serial1 hardware uart.
    I plan to bump the baud rate up to 115200.
    I have written instruction on how to autotune the kangaroo
    with my sabertooth and gear motors. Dimension Engineering calls this Drive Mode autotune for 2 wheel differential drive robots.

    Thanks

    #1300

    SuperDroid
    Keymaster

    I have not personally retrieved status updates from the kangaroo, but from the reference links I’ve included below, it looks like the KangarooMonitor class is used to pull the information from the kangaroo itself.

    Reference:
    http://www.dimensionengineering.com/software/KangarooArduinoLibrary/html/class_kangaroo_monitor.html
    http://www.dimensionengineering.com/software/KangarooArduinoLibrary/html/class_kangaroo_status.html

    Something like the below might work, but I haven’t tested it.

    KangarooMonitor kMon;  // The monitor
    KangarooStatus kStat;  // Holds status information
    kMon.update();         // Retrieves most recent data from the kangaroo
    kStat = kMon.status(); // Places the retrieved status information into kStat
    
    Serial.print("Busy: ");
    Serial.print(kStat.busy());
    Serial.print("  Error: ");
    Serial.println(kStat.error());
    • This reply was modified 2 years, 11 months ago by  SuperDroid.
    #1302

    tomega3
    Participant

    Hi, thank you very much for the example code.
    I tried to compile it on my arduino mega 2560

    declaring kMon as a kangaroo object fails with:
    no matching function for call to
    KangarooMonitor::KangarooMonitor()
    I think this means the monitor has no constructor

    KagarooStatus kStat compiles OK

    In my code I have:

    HardwareSerial  KangarooSerialPort(Serial1);
    KangarooSerial  K(KangarooSerialPort);
    // Mixed mode differential drive
    KangarooChannel Drive(K, 'D');
    KangarooChannel Turn(K, 'T');

    I wonder how to associate my Drive and Turn channels with the kStat and the monitor. I think I will google c++ friendclass to see what I can find out and try to figure out what the author of the Kangaroo class library is doing.

    I think I have error checking figured out using this code:
    it appears that these channel commands return an error code: start, home, units, powerdown, powerdownall, serialTimeout, and systemcommand

    void DriveChannelStart()
    {
      int8_t kerr;
      kerr = Drive.start();
      err = processKangarooError("Drive", "Start", kerr);
      if (err)
      {
        do something
      }
    }
    boolean processKangarooError(char* channelname, char* channelcommand, int8_t ke)
    {
      boolean errorfound = false;
      switch (ke)
      {
        case KANGAROO_NO_ERROR:
          errorfound = false;
          //showKangarooError(channel._name, channel._command, "KANGAROO_NO_ERROR");
          showKangarooError(channelname, channelcommand, "KANGAROO_NO_ERROR");
        break;
        
        case KANGAROO_NOT_STARTED:
          errorfound = true;
          showKangarooError(channelname, channelcommand, "KANGAROO_NOT_STARTED");
        break;
        
        case KANGAROO_NOT_HOMED:
          errorfound = true;
          showKangarooError(channelname, channelcommand, "KANGAROO_NOT_HOMED");
        break;
        
        case KANGAROO_CONTROL_ERROR:
          errorfound = true;
          showKangarooError(channelname, channelcommand, "KANGAROO_CONTROL_ERROR");
        break;
        
        case KANGAROO_WRONG_MODE:
          errorfound = true;
          showKangarooError(channelname, channelcommand, "KANGAROO_WRONG_MODE");
        break;
        
        case KANGAROO_UNRECOGNIZED_CODE:
          errorfound = true;
          showKangarooError(channelname, channelcommand, "KANGAROO_UNRECOGNIZED_CODE");
        break;
        
        case KANGAROO_SERIAL_TIMEOUT:
          errorfound = true;
          showKangarooError(channelname, channelcommand, "KANGAROO_SERIAL_TIMEOUT");
        break;
        
        case KANGAROO_INVALID_STATUS:
          errorfound = true;
          showKangarooError(channelname, channelcommand, "KANGAROO_INVALID_STATUS");
        break;
        
        case KANGAROO_TIMED_OUT:
          errorfound = true;
          showKangarooError(channelname, channelcommand, "KANGAROO_TIMED_OUT");
        break;
        
        case KANGAROO_PORT_NOT_OPEN:
          errorfound = true;
          showKangarooError(channelname, channelcommand, "KANGAROO_PORT_NOT_OPEN");
        break;
        
        default:
          errorfound = true;
          showKangarooError(channelname, channelcommand, "UNKNOWN_ERROR");
        break;
      }
      return errorfound;  
    }
    void showKangarooError( char* channelname, char* channelcommand, char* errortext)
    {  
      if (SERIAL_DEBUG)
      {   
        char  buffer[MAXARRAYSIZE]; 
        snprintf_P(buffer, (MAXARRAYSIZE - 1), PSTR("%s % %s"),channelname, channelcommand, errortext);
        //showText(0, 0, false, false, tempoutString1);
        Serial.println(buffer);
      }
    }

    Thanks again, maybe someone can help us with this C++ friendclass usage.

    • This reply was modified 2 years, 11 months ago by  SuperDroid. Reason: Formatting
    #1304

    SuperDroid
    Keymaster

    The code found below should be sufficient to ramp the motors back and forth. I will need to look more into how they have their monitoring setup.

    Be sure that you have the kangaroo and Sabertooth configured properly. I would suggest using Dimension Engineering’s DELink USB to TTL converter and their DeScribe software to set them to the correct address and baud rate. Also be sure that you do not have Tx and Rx mixed up on Serial1.

    
    //=========================HEADER=============================================================
    /*
    
       Kangaroo Example 
       AUTHOR: Jason Traud
       DATE: October 28, 2014
       
       This firmware will demonstrate control of a Kangaroo using an Arduino Mega 2560
       
       Hardware: Arduino MEGA 2560 R3                (MCU-049-000)
                 Sabertooth Dual 25A Motor Driver    (TE-091-225)
                 Kangaroo x2 Motion Controller       (TE-180-000) 
    
    			
       License: CCAv3.0 Attribution-ShareAlike (http://creativecommons.org/licenses/by-sa/3.0/)
       You're free to use this code for any venture. Attribution is greatly appreciated. 
    
    //============================================================================================
    */
    
    // ****************************************************
    // Libraries
    // ****************************************************
    #include <Kangaroo.h>            
    #include "Arduino.h"
    
    // ****************************************************
    // Hardware Pin Definitions
    // ****************************************************
    
    // ****************************************************
    // Initialize software serial for the motor controller
    // ****************************************************
    
    KangarooSerial  K(Serial1);
    KangarooChannel Drive(K, 'D');
    KangarooChannel Turn(K, 'T');
    
    // ****************************************************
    // Initial setup function, called once
    // RETURNS: none
    // ****************************************************
    void setup() {	
     
      Serial.begin(115200);    // Debug output to computer
      Serial1.begin(115200);   // Serial COM to Kangaroo
    
      // Let everything boot  
      delay(2000);
      
      Drive.start();
      Drive.home();
      Turn.start();
      Turn.home();
    
    }
    
    // ****************************************************
    // Main program loop
    // RETURNS: none
    // ****************************************************
    void loop() {
      int x;
      
      for (x=0; x<5000; x=x+10) {
        Drive.s(x); 
        delay(200);
      }
      
      for (x=5000; x>-5000; x=x-10) {
        Drive.s(x);   
        delay(200);
      }
      
      for (x=-5000; x<0; x=x+10) {
        Drive.s(x);    
        delay(200);
      }
    }
    #1305

    tomega3
    Participant

    Hi Jason,
    Really appreciate you taking a look into this.
    I have a sketch the can drive and turn my robot and report certain errors. I found some ways to run certain channel.monitor functions I think but still do not know how to process their return values and am still lost with what to do to get status values via kangaroostatus object.

    I am attaching my sketch that drive and turns my bot
    I put in a lot of comments at the top so maybe you can try it

    see the following function for my attempts to process errors, channel monitor functions and channel status data:
    nitKangarooMixedMode
    processKangarooError
    showKangarooError
    Forward
    and
    showDTCommands

    Maybe you can use it as a test bed to figure out how to check channel status and do channel monitoring.

    Thanks again

    #1306

    tomega3
    Participant

    I had to zip up the sketch to upload it
    see A_MY_MIXEDMODE_DEMO_TEST_1.zip

    Attachments:
    You must be logged in to view attached files.
    #1308

    tomega3
    Participant

    I made some progress with retrieving the status of the channel drive and turn commands. I put together a txt file showing the changes to the A_MY_MIXEDMODE_DEMO_TEST1 ino file that I made to get and report the status

    see attached file: Kangaroo_Status_Monitoring_Examples.zip

    Changes made to the Forward() function
    added showDTStatusInfo() procedure

    I think I aam getting close to figuring this out. Still have some questions:
    1: How can I monitor the status of a channels motion commands
    after issuing the motion command without reissuing the motion
    command ?

    2: How do I test to see if the monitors status info is valid?
    see class KangarooMonitor public member function: boolean valid() const;
    see class kanagroostatus KangarooStatus KangarooStatus::createFromError(KangarooError error)

    3: How do I test to see if the returned value from the get commands
    is a valid value or the command reports an error condition

    Thanks for your help.

    Attachments:
    You must be logged in to view attached files.
    #1310

    tomega3
    Participant

    Thanks to Dimension Engineering’s help desk support I have written some test code to check the status of a monitored kangaroo channel:

    see below:

    KanagrooMonitor info
    Here is how to use a kangaroomonitor:
    Note: as of V105 of the dimension engineering kangaroo arduino library the KangarooMonitor class does not
    have a default constructor so have to instanciate a kangaroomonitor instance like this below:

    KanagrooMonitor m = Drive.s(v);

    KamgarooStatus s;
    s = m.status();

    m.valid() only tests if it is the most recent KangarooMonitor for a particular channel —
    only the one corresponding to the most recent command on that channel is valid.
    Here is an example:

    KangarooMonitor M1 = Drive.p(1234); // M1.valid() == true
    KangarooMonitor M2 = Drive.p(2345); // M1.valid() == false && M2.valid() == true
    Not sure how to check for channel status or how to monitor channel operation.

    see void TestForward() and TestGetSpeed () functions for example code that reports on the status of a monitored channel.

    void initKangarooSerialPort()
    {
    KangarooSerialPort.begin(9600);
    // the below only needed when using softwareserial
    #ifdef USESOFTWARESERIAL
    KangarooSerialPort.listen();
    #endif
    }

    void initKangarooMixedMode()
    {
    // default command reply timeout is INFINITE
    // unless serial timeout set to some lower condition
    // the Drive.start command will wait forever when not connected to a powered kangaroo

    boolean err = false;
    int8_t kerr;
    kerr = Drive.start();
    err = processKangarooError(“Drive”, “Start”, kerr); // start, home, units, powerdown, powerdownall, serialTimeout, systemcommand
    //err = processKangarooError(Drive(K,’D’), kerr); // start, home, units, powerdown, powerdownall, serialTimeout, systemcommand
    if (err)
    {
    ;; // an error occurred see output on Serial Monitor
    }
    Drive.si(0); // 0 is stop, positive numbers turn right, negative numbers turn left

    kerr = Turn.start();
    err = processKangarooError(“Turn”, “Start”, kerr);
    if (err)
    {
    ;; // an error occurred see output on Serial Monitor
    }
    Turn.si(0); // 0 is stop, positive numbers turn right, negative numbers turn left

    TOBEBOTMODE = BOTSTOP;
    DRIVEMODE = DSTOP;
    TURNMODE = TSTOP;
    }

    void TestForward(int32_t v)
    {
    // create an instance of a kangaroomonitor object for a kangaroo channel

    KangarooMonitor m = Drive.s(v); // create a monitor for the channel command
    //KangarooMonitor m;
    // m = Drive.s(v); // create a monitor for the channel command

    /***************
    m.valid() only tests if it is the most recent KangarooMonitor for a particular channel —
    only the one corresponding to the most recent command on that channel is valid.
    Here is an example:

    KangarooMonitor M1 = Drive.p(1234); // M1.valid() == true
    KangarooMonitor M2 = Drive.p(2345); // M1.valid() == false && M2.valid() == true
    ***********************/

    if (m.valid())
    {
    KangarooStatus s; // create an instance of kangaroo status object
    s = m.status(); // populate the kangaroo status instance with last known status

    m.update(); // updates the monitored status to most current status
    s = m.status(); // gets the most curent monitored status after the update

    if (showDTStatusInfo(s))
    {
    //the kangaroo reported an error
    }
    }
    else
    {
    ;
    // the monitor is invalid for the channel
    }
    }

    void TestGetSpeed(int32_t v)
    {
    int32_t curSpeed;

    KangarooMonitor m = Drive.s(v);
    //KangarooMonitor m;
    //m = Drive.s(v);

    KangarooStatus s;
    if (m.valid())
    {
    m.update(); // updates the monitored status to most current status
    s = m.status();

    s = Drive.gets();
    if (s.ok()) // Kangaroo_No_Error is a 0 could also do if (!s.error()) which is what s.ok effectively does
    {
    curSpeed = s.value();
    }
    else
    {
    ; // an error occurred
    //processError();
    }
    }
    else
    {
    ;
    // the monitor is invalid for the channel
    }
    }

    boolean showDTStatusInfo( KangarooStatus lkStat)
    {
    /************
    boolean isValidKstat = lkStat.valid(); // ??
    boolean isBusyKstat = lkStat.busy(); // returns true if the channel is busy.
    boolean isDoneKstat = lkStat.done(); // returns true if the command is done
    boolean isOKKstat = lkStat.ok(); // returns true if not an error and kStat.value is the requested value
    boolean isTimedOutKstat = lkStat.timedOut(); // returns True if the KangarooStatus::error() equals KANGARO_TIMED_OUT.

    char channelname = lkStat.channel(); // returns the channel name
    int8_t kerr = lkStat.error(); // returns the error, or KANGAROO_NO_ERROR if the response is not an error.
    int32_t retValue = lkStat.value(); // returns the value associated with a get command
    *****************************/

    char buffer[MAXARRAYSIZE];
    boolean err = false;

    if (SERIAL_DEBUG)
    {
    char wbuffer[10];
    wbuffer[0] = lkStat.channel(); // channel is a single char not a string
    wbuffer[1] = ”;

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %s”), “Channel Name”, wbuffer);
    Serial.println(buffer);

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s”), lkStat.channel());
    err = processKangarooError(buffer, “From Channel Status”, lkStat.error());

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %s”), “Timed Out”, lkStat.timedOut() ? “true” : “false”);
    Serial.println(buffer);

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %s”), “Valid”, lkStat.valid() ? “true” : “false”);
    Serial.println(buffer);

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %s”), “Busy”, lkStat.busy() ? “true” : “false”);
    Serial.println(buffer);

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %s”), “Done”, lkStat.done() ? “true” : “false”);
    Serial.println(buffer);

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %s”), “OK”, lkStat.ok() ? “true” : “false”);
    Serial.println(buffer);

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %ld”), “Channel Value”, lkStat.value());
    Serial.println(buffer);
    }
    return err;
    }

    void showKangarooError( char* channelname, char* channelcommand, char* errortext)
    {
    if (SERIAL_DEBUG)
    {
    char buffer[MAXARRAYSIZE];
    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %s %s”),channelname, channelcommand, errortext);
    Serial.println(buffer);
    }
    }

    boolean processKangarooError(char* channelname, char* channelcommand, int8_t ke)
    {
    boolean errorfound = false;
    switch (ke)
    {
    case KANGAROO_NO_ERROR:
    errorfound = false;
    showKangarooError(channelname, channelcommand, “KANGAROO_NO_ERROR”);
    break;

    case KANGAROO_NOT_STARTED:
    errorfound = true;
    showKangarooError(channelname, channelcommand, “KANGAROO_NOT_STARTED”);
    break;

    case KANGAROO_NOT_HOMED:
    errorfound = true;
    showKangarooError(channelname, channelcommand, “KANGAROO_NOT_HOMED”);
    break;

    case KANGAROO_CONTROL_ERROR:
    errorfound = true;
    showKangarooError(channelname, channelcommand, “KANGAROO_CONTROL_ERROR”);
    break;

    case KANGAROO_WRONG_MODE:
    errorfound = true;
    showKangarooError(channelname, channelcommand, “KANGAROO_WRONG_MODE”);
    break;

    case KANGAROO_UNRECOGNIZED_CODE:
    errorfound = true;
    showKangarooError(channelname, channelcommand, “KANGAROO_UNRECOGNIZED_CODE”);
    break;

    case KANGAROO_SERIAL_TIMEOUT:
    errorfound = true;
    showKangarooError(channelname, channelcommand, “KANGAROO_SERIAL_TIMEOUT”);
    break;

    case KANGAROO_INVALID_STATUS:
    errorfound = true;
    showKangarooError(channelname, channelcommand, “KANGAROO_INVALID_STATUS”);
    break;

    case KANGAROO_TIMED_OUT:
    errorfound = true;
    showKangarooError(channelname, channelcommand, “KANGAROO_TIMED_OUT”);
    break;

    case KANGAROO_PORT_NOT_OPEN:
    errorfound = true;
    showKangarooError(channelname, channelcommand, “KANGAROO_PORT_NOT_OPEN”);
    break;

    default:
    errorfound = true;
    showKangarooError(channelname, channelcommand, “UNKNOWN_ERROR”);
    break;
    }
    return errorfound;
    }

    void showDTCommand( char* dir, int32_t velocity, char* lmt, int32_t ramp, boolean pwait)
    {
    if (SERIAL_DEBUG)
    {
    char wbuffer[10];
    snprintf_P(wbuffer, (MAXARRAYSIZE – 1), PSTR(“%s”), pwait ? “WAIT” : “NOWAIT”);

    char buffer[MAXARRAYSIZE];
    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %ld%s %ld %s”), dir, velocity, lmt, ramp, wbuffer);
    Serial.println(buffer);

    wbuffer[0] = Drive.name(); // name is a single char not a string
    wbuffer[1] = ”;

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %s”), “Channel Name”, wbuffer);
    Serial.println(buffer);

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %d”), “Kangaroo Address”, Drive.address());
    Serial.println(buffer);

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %ld”), “Command Retry Interval”, Drive.commandRetryInterval());
    Serial.println(buffer);

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %ld”), “Command Timeout”, Drive.commandTimeout());
    Serial.println(buffer);

    snprintf_P(buffer, (MAXARRAYSIZE – 1), PSTR(“%s %s”), “Streaming”, Drive.streaming() ? “true” : “false”);
    Serial.println(buffer);
    }
    }

    Thanks for you help also

    #4491

    Daniel Phelps
    Participant

    I’m having a similar problem with the Kangaroo code. I’m adding the Kangaroo x2’s to the Sabertooth 2×32 on a IG42 Mecanum that I just received. The Kangaroo has it’s own library as well as the Sabertooths. I spoke with dimension and they pointed out that I need to swap the Sabertooth calls out for the Kanga X2 calls in the arduino sketch, then tune with both addresses at 128, then change the addresses back to 128 and 129.

    Any advice or resources for converting the Sabertooth code library with the Kangaroo code library? I’m using: https://github.com/SuperDroidRobots/RC_Mecanum_Sabertooth for the mecanum..

    should I be using: https://github.com/SuperDroidRobots/QuadWheelATR

    Thanks!

    #4492

    SuperDroid
    Keymaster

    You should be able to use the Kangaroo library instead of the Sabertooth library for speed control.

    Here is an example: https://github.com/SuperDroidRobots/QuadWheelATR/tree/master/Firmware/Quad_ATR_Mecanum_Kangaroo

Viewing 10 posts - 1 through 10 (of 10 total)

You must be logged in to reply to this topic.

Skip to toolbar