Code Monkey home page Code Monkey logo

dynamixel2arduino's Introduction

DYNAMIXEL2Arduino Build Status

Serial and Direction Pin definitions of ROBOTIS controllers

  • When running DYNAMIXEL without DYNAMIXEL Shields on OpenCM9.04, OpenCR or custom boards, you might need to change the Serial and DYNAMIXEL Direction Pin.

  • We provide the information below to make it easier to define Serial and Direction pins for specific hardware.

    Board Name Serial Direction Pin Note
    OpenCM9.04 Serial1 28 Uploading Arduino Sketch will erase the factory firmware. The firmware can be recovered with DYNAMIXEL Wizard 2.0
    OpenCM485EXP Serial3 22
    OpenCR Serial3 84 OpenCR has an FET switch to control power supply to DYNAMIXEL. (Reference link)
    OpenRB-150 Serial1 (-1)Automatic -

How to add new DYNAMIXEL model.

  • For the convenience of the user, Dynamixel2Arduino API hardcodes some information in the control table and stores it in flash.
  • To do this, you need to add code to some files. In this regard, please refer to PR#3 and PR#7

How to create custom PortHandler Class

  • Please refer to port_handler.h
  • Create a new class by inheriting PortHandler as public. (Like SerialPortHandler and USBSerialPortHandler)

dynamixel2arduino's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dynamixel2arduino's Issues

Dynamixel XL 320

ISSUE TEMPLATE ver. 1.1.1

BE CAREFUL!! FOLLOW THE RULES AS FOLLOWS, OR YOUR ISSUE WILL BE WON'T FIX ANYWAY

STEP 1. Check what you are suffering from :

  • I'm using DynamixelSDK ver. 3.5.4

    • [3.4.1], [3.5.2], etc.
  • I'm using C++ Language

    • [C] / [C++] / [C#] / [Python] / [Java] / [MATLAB] / [LABVIEW] / [ROS] / [Arduino]
  • I'm using USB2Dynamixel2 serial converter

    • [USB2Dynamixel] / [USB2Dynamixel2] or [OpenCM904] / [OpenCR] / [CM700s] / [CM500s] or other ROBOTIS product only
  • I'm using XM430-W210-R

    • [MX-28], [AX-12W], [H54-200W], etc.
  • and I'm having an issue like what

    • 'My motor doesn't work', etc.

STEP 2. Write Title as [3.5.4][C++][USB2Dynamixel2][XM430-W210-R] Issue : My motor doesn't work

  • Now, if you think :

    • Hey, I'm using RoboPlus2.0, and having an issue, but how can I write that kind of Title?

    • Hey, I'm using USB2AX serial converter, and having an issue, but how can I write that kind of Title?

    • or more that is not listed on above.

  • , You should write your issue on http://en.robotis.com/BlueAD/board.php?bbs_id=old_qna

STEP 3. Delete all written here, and describe what your problem is

  • Any PICTURES or VIDEOS?

    ![]( Link the PICTURES or VIDEOS here, if necessary )

  • Any SOURCE SAMPLES?

    []( Link the SOURCE SAMPLES here, if necessary )

Velocity Mode Reverse

Hello,
I recently wanted to use a joystick for my robot arm to control a XL320, it's working perfectly but when I modify the code to make it move in reverse nothing is happening. I really don't understand why in velocity mode with RAW UNIT it's not working but with percent it's working. Since I use a joystick I need to use the RAW unit. I post the code I use below. Btw I use a PS5 controller as the joystick in bluetooth with a shield. Even when I put a negative number instead of the input of the ps5 controller nothing is happening

#include <PS5BT.h>
#include <usbhub.h>

// Satisfy the IDE, which needs to see the include statment in the ino too.
#ifdef dobogusinclude
#include <spi4teensy3.h>
#endif
#include <SPI.h>

USB Usb;
//USBHub Hub1(&Usb); // Some dongles have a hub inside
BTD Btd(&Usb); // You have to create the Bluetooth Dongle instance like so

/* You can create the instance of the PS5BT class in two ways */
// This will start an inquiry and then pair with the PS5 controller - you only have to do this once
// You will need to hold down the PS and Share button at the same time, the PS5 controller will then start to blink rapidly indicating that it is in pairing mode
PS5BT PS5(&Btd, PAIR);
bool printAngle = false, printTouch = false;
uint16_t lastMessageCounter = -1;
uint8_t player_led_mask = 0;
bool microphone_led = false;
uint32_t ps_timer;

#include <Dynamixel2Arduino.h>
#include <DynamixelShield.h>
#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA2560)
  #include <SoftwareSerial.h>
  SoftwareSerial soft_serial(7, 8); // DYNAMIXELShield UART RX/TX
  #define DEBUG_SERIAL soft_serial
#elif defined(ARDUINO_SAM_DUE) || defined(ARDUINO_SAM_ZERO)
  #define DEBUG_SERIAL SerialUSB
#else
  #define DEBUG_SERIAL Serial 
#endif

const uint8_t DXL_ID = 1;
const float DXL_PROTOCOL_VERSION = 2.0;
int val = 0;
int sensVal = 0;
int sensValR3 = 0;
DynamixelShield dxl;

//This namespace is required to use Control table item names
using namespace ControlTableItem;

void setup() {
  // put your setup code here, to run once:
  
  // For Uno, Nano, Mini, and Mega, use UART port of DYNAMIXEL Shield to debug.
  DEBUG_SERIAL.begin(115200);
  
  // Set Port baudrate to 57600bps. This has to match with DYNAMIXEL baudrate.
  dxl.begin(57600);
  // Set Port Protocol Version. This has to match with DYNAMIXEL protocol version.
  dxl.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
  // Get DYNAMIXEL information
  dxl.ping(DXL_ID);


  // Turn off torque when configuring items in EEPROM area
  dxl.torqueOff(DXL_ID);

  dxl.setOperatingMode(DXL_ID, OP_VELOCITY);

  dxl.torqueOn(DXL_ID);

  
   #if !defined(__MIPSEL__)
  while (!Serial); // Wait for serial port to connect - used on Leonardo, Teensy and other boards with built-in USB CDC serial connection
#endif
  if (Usb.Init() == -1) {
    Serial.print(F("\r\nOSC did not start"));
    while (1); // Halt
  }
  Serial.print(F("\r\nPS5 Bluetooth Library Started"));
}
 
void loop() {
       Usb.Task();
   if (PS5.connected() && lastMessageCounter != PS5.getMessageCounter()) {
    lastMessageCounter = PS5.getMessageCounter();  
    if (PS5.getButtonPress(PS)) {
      if (millis() - ps_timer > 1000)
        PS5.disconnect();
    } else
      ps_timer = millis();
 

  
  sensVal = (PS5.getAnalogButton(L2));
  val = constrain(sensVal, 0, 180);
  sensValR3 = (val) - (2*(val));
  // Please refer to e-Manual(http://emanual.robotis.com) for available range of value. 
  // Set Goal Velocity using RA unit
 dxl.setGoalVelocity(DXL_ID, sensValR3);

 

}
}

Thanks,
WilliamH07

OpenCM 9.04 hangs when using Serial Port

Good afternoon, in our work we use the OpenCM 9.04, 3 ax-12a board, and when we display the state of the dynamics in Serial, then at some point the goal position values are not correct and the controller quickly freezes after that.
Only restart helps. What is it and how to fix the situation?
image

When I set the angle to all the engines, I check in a loop to see if they have completed the command. Only then does the code continue.

void WaitServosPosPerformed() {
  int* servosPos = new int[JOINT_N];
  if (DEBUG_LEVEL >= 1) DEBUG_SERIAL.println("Current servos position: ");
  while (true) {
    int* servosPos = GetServosPos();
    bool* isMoving = GetServosMoving();
    if (DEBUG_LEVEL >= 1) {
      for (byte i = 0; i < JOINT_N; i++) {
        DEBUG_SERIAL.print(servosPos[i]);
        if (i < JOINT_N - 1) DEBUG_SERIAL.print(", ");
        else DEBUG_SERIAL.println();
      }
    }
    if (DEBUG_LEVEL >= 2) {
      for (byte i = 0; i < JOINT_N; i++) { // 1 - движение, 0 - движения нет
        DEBUG_SERIAL.print(isMoving[i]);
        if (i < JOINT_N - 1) DEBUG_SERIAL.print(", ");
        else DEBUG_SERIAL.println();
      }
    }
    if ((isMoving[0] == 0 && isMoving[1] == 0 && isMoving[2] == 0)) break;
    delay(10);
  }
  DEBUG_SERIAL.print("Motors performed position: ");
  for (byte i = 0; i < JOINT_N; i++) {
    DEBUG_SERIAL.print(servosPos[i]);
    if (i < JOINT_N - 1) DEBUG_SERIAL.print(", ");
    else DEBUG_SERIAL.println();
  }
}
int* GetServosPos() {
  int *pos = new int[JOINT_N];
  for (byte i = 0; i < JOINT_N; i++) {
    pos[i] = dxl.getPresentPosition(i + 1);
  }
  return pos;
}

int GetServoMoving(byte servoId) {
  return dxl.readControlTableItem(MOVING, servoId);
}

bool* GetServosMoving() {
  bool *moving = new bool[JOINT_N];
  for (byte i = 0; i < JOINT_N; i++) {
    moving[i] = dxl.readControlTableItem(MOVING, i + 1);
  }
  return moving;
}

I set different baud rates for Serial communication with the computer, for
DEBUG_SERIAL.begin(9600); dxl.begin(1000000); and even for all servos, but it still happens. The controller freezes.

https://community.robotis.us/t/opencm-9-04-hangs-when-using-serial-port/855

Problem with ax-12

Hello,
I tried the code below to move from 0 to 300 an ax-12, but I was not able to make it work. Still, I have no problem with an XL430 or an XM430.

#include <Dynamixel2Arduino.h>
#define DXL_SERIAL Serial1

const uint8_t TEST_ID = 2;
const uint8_t DXL_DIR_PIN = 43;
const float DXL_PROTOCOL_VERSION = 1.0;
Dynamixel2Arduino dxl(DXL_SERIAL, DXL_DIR_PIN);
void setup() {
Serial.begin(115200);
dxl.begin(1000000);
dxl.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
dxl.ping(TEST_ID);
dxl.torqueOn(TEST_ID);
}

void loop() {
dxl.setGoalPosition(TEST_ID, 0);
delay(2000);
dxl.setGoalPosition(TEST_ID, 500);
delay(2000);

}

Match HardwareSerial begin signature

Hi!

It would be incredibly helpful if the signature of Dynamixel2Arduino's

void begin(unsigned long baud = 57600);

matched Arduino's HardwareSerial

void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL);

In my particular case I'm using an ESP32 as a control interface and I need to remap the pins for UART2, but because the call to begin is behind Dynamixel2Arduino::begin I have to alter the library to enable this functionality.

Cheers.

Dynamixel2Arduino does not compile for STM32

Issue
Any Ardunio sketch for STM32 CPUs/Boards that tries to #include <Dynamixel2Arduino.h> fails to compile/build.

Reason
actuator.h defines the enum "ControlTableItemIndex" which uses the keyword "LED_GREEN".
For Arduino boards using the STM32 core "LED_GREEN" is defined as macro for the Arduino pin number of the onboard LED. In case of Nucleo-64 / Nucleo F446RE it simply evaluates to 200 and hence cannot be (re)used as a keyword in an enum.

Solution

  • Adding #undef LED_GREEN right in front of the definition of ControlTableItemIndex in actuator.h (might have side effects)
  • Or rename keyword to e.g. "LED_GREE" in actuator.h, actuator.cpp and keywords.txt

setGoalVelocity with UNIT_PERCENT not mapping to actual max velocity

When using setGoalVelocity with unit set to UNIT_PERCENT I would expect it to be mapped to the servos max velocity. But instead the servo reaches max speed at around 21% and setGoalVelocity returns false for values above.

Tested on Arduino MKR WiFi 1010 with Dynamixel Shield for Arduino Series.
Servo: DYNAMIXEL XL330-M288-T
Power Supply: 5V (external through Shield)

Broadcast ID does not work correctly.

The reboot function does not work when you use broadcast id.
Those lines in the reboot function in master.cpp prevent it
if (id == DXL_BROADCAST_ID){ last_lib_err_code_ = DXL_LIB_ERROR_NOT_SUPPORT_BROADCAST; return false; }
When they are commented out the reboot works fine for all connected dynamixels. Why is it in the code?

In the same function the reboot code does not work at all if this is left as is
last_lib_err_code_ = dxlTxPacketInst(&packet_, id, INST_REBOOT, tx_param, 1);
once it is changed to
last_lib_err_code_ = dxlTxPacketInst(&packet_, id, INST_REBOOT, tx_param, 0);
the reboot starts working.
When you try to set the torqueOn to broadcast ID it does not work either.

Custom Port Handlers and other minor suggestions

I am starting to play again with Dynamixel servos, and am in the process of trying to convert using some code that uses my version of the old Bioloid library (https://github.com/kurte/bioloidserial) to a current Robotis Servo library. And I wish to have this work on both OpenCM/OpenCR as well as with some other processors, in particular with Teensy boards (PJRC) such as the T4.1.

As per previous discussions, at least at the time, non-Arduino/Robotis brand hardware changes were not supported in other libraries such as the Dynamixel SDK library so working with this library now.

Some simple suggestions for this library.

a) https://emanual.robotis.com/ - Under the Software tab should include a link to this library. The only place you find details is if you go to the https://emanual.robotis.com/docs/en/parts/interface/dynamixel_shield/ page...

b) To use with Teensy boards, In most cases I will probably need to use a Custom Port handler. So started playing with example.
Suggestion: Change private to protected... That is:

class SerialPortHandler : public DXLPortHandler
{
  public:
    SerialPortHandler(HardwareSerial& port, const int dir_pin = -1);

    virtual void begin() override;
    virtual void end() override;
    virtual int available(void) override;
    virtual int read() override;
    virtual size_t write(uint8_t) override;
    virtual size_t write(uint8_t *buf, size_t len) override;

    virtual void begin(unsigned long baud);
    virtual unsigned long getBaud() const;

  protected:
    HardwareSerial& port_;
    const int dir_pin_;
    unsigned long baud_;
};

Then your example sketch does not have to replicate both the port_ and dir_pin_ variables. That is you would not need those two variables defined in your NewSerialPortHandler, nor would your constructor have to set them.

c) still wish at times that the port handler write functions had a way to say this completes my data or not. That way you don't have to buffer up all of the data into some secondary buffer, just to do one write, to minimize how many times you set/clear the IO pin and or do flush operations.

d) Wish that there were some of the ControlTableItem data that was public and not private. That is suppose I want to setup code that uses SyncWrite to output the GOAL_POSITION for the servos. Sometimes I will be building for a Hex robot that uses AX servos (Protocol 1). Sometimes I will build for XL-430 servos (Protocol 2). Right now I have to do my own detect of servo type and have my own information for which register it is and the length of it...

Sorry I know that this is more than one thing... But thought I would mention all of this now which I was thinking about it.

Kurt

Protocol 2 FastSyncRead - API should be added to the library

I am not sure when this was added and what servos support it. I did update my Hexapod with XL430-W250 servos to the current released firmware... There is also a fast bulk read, which I have not tried yet.

I have been playing around a little lately, with the Saleae Logical Analyzer stuff. Earlier I created a Low level analyzer for Dynamixels...
But thought it might be interesting to try to create a new High Level Analyzer for the new Logic Software...
It is taking me awhile as I really don't know Python language... But I do have a version working reasonably well.. Needs some cleanup.

While doing this I noticed a new? servo Command Fast Sync Read, so I hacked up a version of the SyncReadWrite example sketch and added new section of code to perform this on 6 servos... To get an idea of how well it might work... I have not put in the code to decode it fully within test sketch: Which I included, although not complete...

sync_read_write_position.zip

I was curious to see the differences in speed.
Looking at it from LA:

The normal sync read:
image
Closer up showing my HLA output (blue line)
image

The fast Sync Read
image
The difference in timing was pretty good went down from 6.6ms for the 6 servos down to 1.8ms

Side Note: I have not yet released the HLA into their Market Place, probably will soon...
But it is up at: https://github.com/KurtE/SaleaeDynamixelAnalyzer_HLA

Master::ping Function should have a longer timeout when using Broadcast ID

When using broadcast ID, if there's no dynamixel ID within #1 or #2 IDs, the ping seems to fail (tested on 2mb baud). So if I have ID #1 and #5, it seems to works fine, but if I only have ID #5 if fails to find it. I ran same ping with a 50ms timeout and it worked. I think the default timeout should be increased correctly for broadcast ID so we don't have to manually set it when using Broadcast ID on ping.

Protocol 1 Syncwrite Goal Position as well as Moving Speed to AX-12A

Hello,

I am trying to synchronously write to 12 motors at a time using Dynamixel Arduino Shield on Arduino Uno. I am using a separate usb2serial converter to read data on PC.

I want to write Goal Position as well as Moving Speed to all the motors. (Starting address 30, data length 4 bytes).

I am getting the wrong robot pose. I have previously tested similar (the only difference is in the library functions of Dynamixel SDK vs Dynamixel2Arduino) code using Dynamixel SDK in C++ language using USB2Dynamixel. It worked perfectly fine.

Something is going wrong while defining the sync write packet. Also, there is no example of sync write with multiple sequential control table items written together, e.g., cw compliance slope + ccw compliance slope + goal position + moving speed.

Kindly help me debug the sync write part of the code:

// Bioloid 12 DOF
#include <DynamixelShield.h>

#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA2560)
#include <SoftwareSerial.h>
SoftwareSerial soft_serial(7, 8);  // DYNAMIXELShield UART RX/TX
#define DEBUG_SERIAL soft_serial
#elif defined(ARDUINO_SAM_DUE) || defined(ARDUINO_SAM_ZERO)
#define DEBUG_SERIAL SerialUSB
#else
#define DEBUG_SERIAL Serial
#endif
/***********************************************************************************************/
// Macros
#define DXL_LOBYTE(w) ((uint8_t)(((uint64_t)(w)) & 0xff))
#define DXL_HIBYTE(w) ((uint8_t)((((uint64_t)(w)) >> 8) & 0xff))
/***********************************************************************************************/
// Control table address
const uint8_t ADDR_AX_TORQUE_ENABLE = 24;
const uint8_t ADDR_AX_GOAL_POSITION = 30;
const uint8_t ADDR_AX_MOVING_SPEED = 32;
const uint8_t ADDR_AX_PRESENT_POSITION = 36;
const uint8_t ADDR_AX_CW_COMP_MARGIN = 26;
const uint8_t ADDR_AX_CCW_COMP_MARGIN = 27;
const uint8_t ADDR_AX_CW_COMP_SLOPE = 28;
const uint8_t ADDR_AX_CCW_COMP_SLOPE = 29;
const uint8_t ADDR_AX_PRESENT_LOAD = 40;
const uint8_t ADDR_AX_LOCK_EEPROM = 47;
const uint8_t ADDR_AX_RDT = 5;

// Data Byte Length
const uint8_t LEN_AX_GOAL_POSITION = 2;
const uint8_t LEN_AX_MOVING_SPEED = 2;
const uint8_t LEN_AX_PRESENT_POSITION = 2;
const uint8_t LEN_AX_CW_COMP_MARGIN = 1;
const uint8_t LEN_AX_CCW_COMP_MARGIN = 1;
const uint8_t LEN_AX_CW_COMP_SLOPE = 1;
const uint8_t LEN_AX_CCW_COMP_SLOPE = 1;
const uint8_t LEN_AX_PRESENT_LOAD = 2;
const uint8_t LEN_AX_LOCK_EEPROM = 1;
const uint8_t LEN_AX_RDT = 1;

const uint8_t TORQUE_ENABLE = 1;
const uint8_t TORQUE_DISABLE = 0;
const uint8_t LOCK_EEPROM = 1;

// Default pose
const uint16_t HY_MIN = 620;
const uint16_t HY_MAX = 720;
const uint16_t HY_NOM = 666;

const uint16_t HR_MIN = 472;
const uint16_t HR_MAX = 552;
const uint16_t HR_NOM = 512;

const uint16_t HP_MIN = 490;
const uint16_t HP_MAX = 780;
const uint16_t HP_NOM = 550;

const uint16_t KP_MIN = 560;
const uint16_t KP_MAX = 885;
const uint16_t KP_NOM = 590;

const uint16_t AP_MIN = 300;
const uint16_t AP_MAX = 500;
const uint16_t AP_NOM = 460;

const uint16_t AR_MIN = 472;
const uint16_t AR_MAX = 552;
const uint16_t AR_NOM = 512;

const uint8_t NMOTOR = 12;
const uint8_t MOTOR_ID_LIST[NMOTOR] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 };

// Homing position and return to home velocity
uint16_t home_pos_list[NMOTOR] = { HY_NOM, HR_NOM, HP_NOM, KP_NOM, AP_NOM, AR_NOM, HY_NOM, HR_NOM, HP_NOM, KP_NOM, AP_NOM, AR_NOM };
uint16_t home_vel_list[NMOTOR] = { 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50, 50 };

/***********************************************************************************************/
// Protocol version
const float PROTOCOL_VERSION = 1.0;  // See which protocol version is used in the Dynamixel
// Starting address of the Data to write; Goal Position = 30
const uint16_t SW_START_ADDR = ADDR_AX_GOAL_POSITION;
// Debug: Length of the Data to write: 2 bytes: Goal Position
// Length of the Data to write: 4 bytes: Goal Position + Goal Velocity
const uint16_t SW_ADDR_LEN = 4;
uint8_t myswdata[SW_ADDR_LEN] = { 0, 0, 0, 0 };
/***********************************************************************************************/
/*
  typedef struct InfoSyncWriteInst{
    uint16_t addr;
    uint16_t addr_length;
    XELInfoSyncWrite_t* p_xels;
    uint8_t xel_count;
    bool is_info_changed;
    InfoSyncBulkBuffer_t packet;
  } __attribute__((packed)) InfoSyncWriteInst_t;
*/
DYNAMIXEL::InfoSyncWriteInst_t allmotorSW;

/* syncWrite
  Structures containing the necessary information to process the 'syncWrite' packet.

  typedef struct XELInfoSyncWrite{
    uint8_t* p_data;
    uint8_t id;
  } __attribute__((packed)) XELInfoSyncWrite_t;
*/
DYNAMIXEL::XELInfoSyncWrite_t all_info_xels_sw[NMOTOR];
// Create an instance of Master class/ Dynamixel2Arduino class/ whatever has all the required functions
DynamixelShield dxl;
//This namespace is required to use Control table item names
using namespace ControlTableItem;
/***********************************************************************************************/
int debug_motor_pose;
bool sync_write_feedback, pos_write_feedback, vel_write_feedback;
int inputpos;
/***********************************************************************************************/
void setup() {
  // put your setup code here, to run once:

  // Communication with PC starts---------------------------->>
  DEBUG_SERIAL.begin(9600);

  // Communication starts------------------------------------>>
  dxl.begin(1000000);  // dxl baudrate
  dxl.setPortProtocolVersion(1.0);
  uint8_t motor_id;
  // Write control Table Items
  for (int i = 0; i < NMOTOR; i++) {
    motor_id = MOTOR_ID_LIST[i];
    // Redefine the packet return delay time (1 ms)
    dxl.writeControlTableItem(RETURN_DELAY_TIME, motor_id, 5);
    //delay(50);
    // Lock the EEPROM
    dxl.writeControlTableItem(LOCK, motor_id, LOCK_EEPROM);
    //delay(50);
    // Set compliance margin and compliance slope
    dxl.writeControlTableItem(CW_COMPLIANCE_MARGIN, motor_id, 2);
    //delay(50);
    dxl.writeControlTableItem(CCW_COMPLIANCE_MARGIN, motor_id, 2);
    //delay(50);
    dxl.writeControlTableItem(CW_COMPLIANCE_SLOPE, motor_id, 16);
    //delay(50);
    dxl.writeControlTableItem(CCW_COMPLIANCE_SLOPE, motor_id, 16);
    //delay(50);
    // Enable Torques one by one
    dxl.torqueOn(motor_id);
    //delay(50);
  }
  
  /***********************************************************************************************/
  // Fill the members of structure to syncWrite using internal packet buffer
  // All motors sync write
  allmotorSW.packet.p_buf = nullptr;
  allmotorSW.packet.is_completed = false;
  allmotorSW.addr = SW_START_ADDR;
  allmotorSW.addr_length = SW_ADDR_LEN;
  allmotorSW.p_xels = all_info_xels_sw;
  allmotorSW.xel_count = 0;

  // AddParam equivalent: Go to the home pose
  // SOME ISSUE HERE
  for (int i = 0; i < NMOTOR; i++) {
    myswdata[0] = DXL_LOBYTE(home_pos_list[i]);  // low byte
    myswdata[1] = DXL_HIBYTE(home_pos_list[i]);  // high byte
    myswdata[2] = DXL_LOBYTE(home_vel_list[i]);  // low byte
    myswdata[3] = DXL_HIBYTE(home_vel_list[i]);  // high byte
    all_info_xels_sw[i].id = MOTOR_ID_LIST[i];
    all_info_xels_sw[i].p_data = myswdata;
    allmotorSW.xel_count++;
    allmotorSW.is_info_changed = true;
  }
  dxl.syncWrite(&allmotorSW);
  // Allow some time for going to home position
  delay(1000);
}
/***********************************************************************************************/
void loop() {
  // put your main code here, to run repeatedly:
  // Debugging: Read motor positions and print it on the screen
  for (int i = 0; i < NMOTOR; i++) {
    debug_motor_pose = dxl.readControlTableItem(PRESENT_POSITION, MOTOR_ID_LIST[i]);
    DEBUG_SERIAL.print(debug_motor_pose);
    DEBUG_SERIAL.print(" ");
  }
  DEBUG_SERIAL.println();

}


/***********************************************************************************************/

Also, can you elaborate on when to update the following structure elements?

.is_info_changed 
.is_completed

Slow communication rate for protocol 1.0

Hi OpusK,
Thanks for working on this library. It works perfectly for my XL430 and XM430. But for AX12A and AX18A, the control frequency can only reach to 10Hz. (Interestingly, it is precisely 10Hz). I guess it might be a common problem for protocol 1.0, but got lost in reading the code.

Here is my simple testing code:

#include <Dynamixel2Arduino.h>
#define DXL_SERIAL   Serial1
#define DEBUG_SERIAL Serial
const uint8_t DXL_DIR_PIN = 2;
const uint8_t DXL_ID = 1;
const float DXL_PROTOCOL_VERSION = 1.0;
Dynamixel2Arduino dxl(DXL_SERIAL, DXL_DIR_PIN);

void setup() {
    DEBUG_SERIAL.begin(115200);
    dxl.begin(1000000);
    dxl.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
    dxl.ping(DXL_ID);
    dxl.torqueOff(DXL_ID);
    dxl.setOperatingMode(DXL_ID, OP_POSITION);
    dxl.torqueOn(DXL_ID);
}

unsigned long prev_time;
void loop() {
    dxl.setGoalPosition(DXL_ID, 512);
    DEBUG_SERIAL.println(micros() - prev_time);
    prev_time = micros();
}

The number printed (the time spent in every loop) is around 100000 us = 100 ms. I guess that is too much time for any smooth operation. For XL430 and XM430, this number is less than 500 us. Do you have an idea why this happens? Or, could you please point out where in the library I should have a look?

(BTW, I am using Teensy 3.6 and a custom shield with pin 2 as the direction pin.)

Best,
Tianjian

Teensy 3.2 with RS485 Breakout and MX-28AR

Hello,
I am having trouble with connecting the following together and getting data from my mx-28ar DYNAMIXEL.
i have a teensy 3.2, which is connected to the computer through micro-usb.
the teensy is connected to my RS485 Breakout through 4 pins:
teensy 3.2 <---> RS485:

  • 3.3 [V] <---> 3-5 [V] (pin 1)
  • TX2 (pin 10) <---> RX-I (pin 2)
  • pin 2 <---> RTS (pin 4)
  • GND <---> GND (pin 5)

the RS485 is connected to the MX-28AR through 3 pins:
RS485 <---> MX-28AR

  • G (pin 3) <---> GND (pin 1)
  • A (pin 2) <---> DATA+ (pin 3)
  • B (pin 1) <---> DATA- (pin 4)

and the mx-28ar is connected to a 12V power supply through smps2dynamixel

My problem is that i cant get any information from the mx-28ar with the teensy, i tried to use the "ping" example from the arduino2dynamixel library and in my monitor i get the "error 3" (which i dont understand at the moment).
my mx-28ar is set to 57600 baud and his id is 3, protocol 2.0 - Double checked it via DYNAMIXEL wizard
I'm using the following code:

#include <Dynamixel2Arduino.h>
//#include <SoftwareSerial.h>
  //SoftwareSerial soft_serial(9, 10); // DYNAMIXELShield UART RX/TX
  #define DXL_SERIAL   Serial2
  const int DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
 #define DEBUG_SERIAL Serial

const uint8_t DXL_ID = 3;
const float DXL_PROTOCOL_VERSION = 2.0;

Dynamixel2Arduino dxl(DXL_SERIAL, DXL_DIR_PIN);

//This namespace is required to use Control table item names
using namespace ControlTableItem;

void setup() {
  // put your setup code here, to run once:
  
  // Use Serial to debug.
  DEBUG_SERIAL.begin(115200);

  // Set Port baudrate to 57600bps. This has to match with DYNAMIXEL baudrate.
  dxl.begin(57600);
  // Set Port Protocol Version. This has to match with DYNAMIXEL protocol version.
  dxl.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
}

void loop() {
  // put your main code here, to run repeatedly:

  DEBUG_SERIAL.print("PROTOCOL ");
  DEBUG_SERIAL.print(DXL_PROTOCOL_VERSION, 1);
  DEBUG_SERIAL.print(", ID ");
  DEBUG_SERIAL.print(DXL_ID);
  DEBUG_SERIAL.print(": ");
  if(dxl.ping(DXL_ID) == true){
    DEBUG_SERIAL.print("ping succeeded!");
    DEBUG_SERIAL.print(", Model Number: ");
    DEBUG_SERIAL.println(dxl.getModelNumber(DXL_ID));
  }else{
    DEBUG_SERIAL.print("ping failed!, err code: ");
    DEBUG_SERIAL.println(dxl.getLastLibErrCode());
  }
  delay(500);

  FindServos();
}


DYNAMIXEL::InfoFromPing_t ping_info[32];
void FindServos(void) {
  Serial.println("  Try Protocol 2 - broadcast ping: ");
  Serial.flush(); // flush it as ping may take awhile... 
      
  if (uint8_t count_pinged = dxl.ping(DXL_BROADCAST_ID, ping_info, 
    sizeof(ping_info)/sizeof(ping_info[0]))) {
    Serial.print("Detected Dynamixel : \n");
    for (int i = 0; i < count_pinged; i++)
    {
      Serial.print("    ");
      Serial.print(ping_info[i].id, DEC);
      Serial.print(", Model:");
      Serial.print(ping_info[i].model_number);
      Serial.print(", Ver:");
      Serial.println(ping_info[i].firmware_version, DEC);
      //g_servo_protocol[i] = 2;
    }
  }else{
    Serial.print("Broadcast returned no items : ");
    Serial.println(dxl.getLastLibErrCode());
  }
}```

Wishlist: As I am converting from using Dynamixel SDK...

Hi @OpusK,

I am trying to get myself going again on the updating of some of Hexapod code base, to now use this library instead of Dynamixel SDK. The main board that I believe Trossen Robotics will use, is the OpenCM9.04... But I would also for my own usage like for it to work well with Teensy boards by PJRC (with my own carrier boards). As I do some of this conversions, I run into different things and or wish things were ... So not sure if this is best place to ask/mention these. Would you prefer that each by separate, so can easily close off as answered?

So far some of the things I have seen include:

a) Wish more (all) of the examples had more complete options for different boards. Example the scan_dynamixel sketch does not have any example of how to configure up to run on OpenCM or OpenCR boards. I did see OpenCM stuff in read_write_ControlTableItem.ino.

b) Wish you would automatically handle somethings like:

#define DXL_SERIAL Serial3 //OpenCM9.04 EXP Board's DXL port Serial. (To use the DXL port on the OpenCM 9.04 board, you must use Serial1 for Serial. And because of the OpenCM 9.04 driver code, you must call Serial1.setDxlMode(true); before dxl.begin();.)

That is maybe on first call to dxl.begin() if compiled for OpenCM and Serial port is Serial1, do the setDXLMode(True)... Or could test again pin 28 in this case...

c) Wishing for some of the member functions including some of the constructors, you allowed pass by pointer as well as by reference. Including ones like:

  1. Master::setPort - I may have a set of ports in an arry so may want to do something like: dxl.setPort( with a pointer to port object)... Will see how hard to get arround.
    Interesting you have a getPort which returns a pointer, but not a way to then use it to set it back...
    Not sure if this would work or not:
PortHandler *previous_port = dxl.getPort();
dxl.setPort(my_port);
...
dxl.setPort(*previous_port);

  1. SerialPortHandler::SerialPorthandler - WIsh I could pass in HardwareSerial port by pointer...)

  2. Dynamixel2Arduino::Dynamixel2Arduino - maybe should allow to pass in port by address and default to nullptr? If I going to setup more than one HardwareSerial objects to pass in a different times, then maybe should be able to initially just be able to declare the main object like:
    Dynamixel2Arduino dxl;

And when I am ready to use it do something like:
dxl.setPort(port_list[index_port_list]);

  1. Wish there was easy way to setup to do other forms of SerialPortHandler (subclass?) That is the current version assumes you are using RX, TX and direction pin... But for example with Teensy, I may wish to either use direction pin, in that case I can tell the SerialPort to handle it for me, or I may wish to use half duplex mode (TX Pin), in which case I need to setup in init and set a register bit for which direction I am going ...

Likewise for AVR boards, like Trossen Robotics has the Arbotix boards, which don't use a buffer chip or the like but again toggle states of enable RX or TX pin depending on direction. Obviously I think I could write my own full subclass of the port object to handle this for me, or wonder if ether some of this should be built into default SerialPortHandler and/or setup to easily sub-class...

d) keywords.txt needs a pass through to update with all of the member names like:
setPortProtocolVersionUsingIndex

That is all for now...

OPERATING_MODE enums not correct numbers?

When I use "mode = dynamixel.readControlTableItem(OPERATING_MODE, id)" on an XH430, I get "3" when it's set to Position Mode, but in code, when I check "mode == OP_POSITION" OP_POSITION is 0 and OP_VELOCITY is actually "3". Am I doing something wrong? On Serial.print(OP_POSITION) = 0, but in DynamixelWizard "Operating Mode(11)" = 3 Position Mode.

slave.cpp baudrate register

By definition a slave device should communicate over the Dynamixel bus, therefore I think it would be logical to include the baudrate as a default register in the class along with the ID, protocol, model number and firmware version.

I would recommend using the register id 8, which keeps it consistent with other devices. Also I would use the mapping table for baudrates based on the latest devices.

I think also we should implement the return delay time, as this is a common feature of the Dynamixel communication and all devices should accommodate it in case the master requires this delay. Typically the return delay time is register 9 that is already used by the protocol, so I suggest we use 10.

I can put a PR if this is ok.

slave: handling of 'ROM' control items

At this moment the slave class does not include any retrieval / save of control items to ROM (ex. ID, protocol, baud-rate, etc.). If devices are really supposed to be build with this library we would need support for saving these configuration items into ROM (like they happen for Dynamixel servos). Is that planned to be added at any time?

Communication Problem between Portenta H7 and MKR Dynamixel Shield

I noticed some time ago that even if all codes, coming from Dynamixel2Arduino or DynamixelShield, compile well, in the end there is no way to find the dynamixel attached to the system Portentah7+MKRDynamixelShield. Thus, I can't drive the dynamixel with portenta H7.
Thank You for the availability.

Dual Core usage of D2A Library on Portenta H7

Hello there,

I am using Dynamixel2Arduino (D2A) Library V. 0.6.1 and Arduino Core 3.4.1 for Portenta H7, and I am encountering an interesting issue:

  1. I can use D2A Library fine on EITHER Core M7 OR Core M4 by themselves.
  2. However, I cannot use D2A on both cores AT THE SAME TIME. The codes on both cores would compile OK, would run OK, except that ONLY M7 code would work correctly with D2A Method Calls. While M4 code would yield a COMMUNICATION error whenever M4 tried to WRITE/READ into the Dynamixel Network.

Is an issue with Mbed-OS? Or is it due to the way D2A Library had been written, i.e., for the case of a Single-Core Controller only?

Update 11/12/2022
After more tests, I am 100% sure that simple Read Present Position commands do not work when called from M4 Core (no error messages) but Write Goal Position/Velocity commands worked fine. Is this something that the user can fix?

Dynamixel MX-28T and MX-106T (2.0)+Arduino Uno+IDE_Extended Position Control Mode+Velocity limit

ISSUE TEMPLATE ver. 1.2.0

Please fill this template for more accurate and prompt support.

  1. Which DYNAMIXEL SDK version do you use?
  • ex) 3.4.1
  1. Which programming language/tool do you use?
    Arduino

  2. Which operating system do you use?
    Windows 10

  3. Which USB serial converter do you use?
    Arduino Uno

  4. Which DYNAMIXEL do you use?
    MX-28T(2.0)

  5. Have you searched the issue from the closed issue threads?

  6. Please describe the issue in detail

Hi everyone,

I am controlling MX servos using Arduino Uno and working on the Extended position control mode, now the problem is I don't know how to set the velocity limit/control velocity for MX servo protocol (2.0) under extended position control mode. However, I have tried with the below code and it seems the code is working and the velocity is controlled only for protocol (1.0) .

`void setup() {

DEBUG_SERIAL.begin(115200);
dxl.begin(57600);
dxl.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
dxl.ping(DXL_ID);

// Turn off torque when configuring items in EEPROM area
dxl.torqueOff(DXL_ID);
dxl.setOperatingMode(DXL_ID, OP_VELOCITY);
dxl.torqueOn(DXL_ID);

//Set Goal Velocity using RPM
dxl.setGoalVelocity(DXL_ID, 20, UNIT_RPM);
delay(100);

DEBUG_SERIAL.print("Present Velocity(rpm) : ");
DEBUG_SERIAL.println(dxl.getPresentVelocity(DXL_ID, UNIT_RPM));
delay(1000);

}

void loop() {

// Extended Position Control Mode in protocol2.0,
//dxl.torqueOff(DXL_ID);
dxl.setOperatingMode(DXL_ID, OP_EXTENDED_POSITION);
dxl.torqueOn(DXL_ID);
if(dxl.setGoalPosition(DXL_ID, 0)){
delay(5000);
DEBUG_SERIAL.print("Present Extended Position1 : ");
DEBUG_SERIAL.println(dxl.getPresentPosition(DXL_ID)); DEBUG_SERIAL.println();
}
// Extended Position Contorl Mode in protocol2.0,
//dxl.torqueOff(DXL_ID);
dxl.setOperatingMode(DXL_ID, OP_EXTENDED_POSITION);
dxl.torqueOn(DXL_ID);
if(dxl.setGoalPosition(DXL_ID, 5000)){
delay(5000);
DEBUG_SERIAL.print("Present Extended Position2 : ");
DEBUG_SERIAL.println(dxl.getPresentPosition(DXL_ID)); DEBUG_SERIAL.println();
}
}`

The code can control the extended position and velocity of servo having version (0.1), but the same code failed for version (2.0) because the dynamixel servo (2.0) rotates with max.velocity (where as it's velocity should be according to the goal velocity) following the extended position limits.

Please, if someone knows what wrong I am doing! and how to modify the code... it will be great help and thanks.

Regards,
Danaish Rathore

  1. How can we reproduce the issue?

Non blocking sync read / bulk read / read in general

Hi,

I have 30ish XM dynamixels to control and I try to find easy way to pull actual position and hardware errors on all of them(2 separate actions)
I am using sync read on a teensy 4.1 to do that.
Using the exact same functions than the example from the library.
I am getting a lot of "[SyncRead] Fail, Lib error code: 0" meaning I don't have libs error because of the 0 but I also don't have any responses from the dynamixels, recv_cnt = 0.
Some time that works and I get responses, most of the time I get this error.
Do I do something wrong? should I increase the timeout value?
I am not sure if it's a problem or not but for the moment I think the sync read function should be a non blocking one, sending the request then running a listener on the background until the packets have been all received then setup a flag that we can check to then read the values.
On the SDK they have a similar approach:
https://emanual.robotis.com/docs/en/software/dynamixel/dynamixel_sdk/sample_code/python_sync_read_write_protocol_2_0/

groupSyncWriteAddParam() function stores the Dynamixel ID and its LEN_PRO_GOAL_POSITION bytes goal position dxl_goal_position to the syncwrite target Dynamixel list.

groupSyncWriteTxPacket() function sends an instruction to the Dynamixel #DXL1_ID and #DXL2_ID at the same time through #port_num, making it possible to write same pre-listed length bytes to same pre-listed address. The function checks Tx/Rx result. getLastTxRxResult() function gets it, and then printTxRxResult() function shows result on the console window if any communication error has been occurred.

groupSyncWriteClearParam() function clears the Dynamixel list of groupsyncwrite.

groupSyncReadTxRxPacket() function sends an instruction to the Dynamixel #DXL1_ID and #DXL2_ID at the same time through #port_num port, making it possible to read same pre-listed length(LEN_PRO_PRESENT_POSITION) of bytes from same pre-listed address(ADDR_PRO_PRESENT_POSITION). The function checks Tx/Rx result. getLastTxRxResult() function gets it, and then printTxRxResult() function shows result on the console window if any communication error has been occurred.

groupSyncReadIsAvailable() function checks if available data is in the groupsyncread data storage. The function returns false if no data is available in the storage.

groupSyncReadGetData() function pop the data received by groupSyncReadTxRxPacket() function out. In the example, it stores LEN_PRO_PRESENT_POSITION byte data got from ADDR_PRO_PRESENT_POSITION address of DXL1_ID andDXL2_ID DYNAMIXEL.

groupSyncReadClearParam() function clears the Dynamixel list of groupsyncread.

Thank you for your help

Using SPI_1 and SPI_2 on OpenCM-904 in Arduino mode

In Arduino mode, the OpenCM-904 already has drawn out nicely 2 SPI Ports on its two headers.
In the file "SPI.h", Line 114, I saw that SPI is defined as extern SPIClass SPI;
Then in the file "SPI.cpp", Line 25, I saw that only SPI1 is used by default. So I added SPI2 on Line 26 (and commented out Line 25).

Added_SPI2_904

With this setup, I can use EITHER SPI1 or SPI2 Port fine, but I need to use BOTH SPI Ports at the same time for my project. Header pins wise, there are no problems, but software wise how should I approach this issue?

I also saw the comments on Lines 63-66 - is that relevant/workable?

image

The way multiple SPI devices are handled as shown in "Arduino Cookbook" is very different from the way ROBOTIS is handling this issue for OpenCM-904. The use of "extern SPIClass SPI" - is that really needed? Did ROBOTIS write the OpenCM-904 library so that only ONE SPI can be used at any one time?

Thank you for any pointer.

Sync Write ax18 not working in OpenCM 9.04 with dynamixel2arduino

hi,

I am trying to sync write a goal position into 2 different servos. this is the code I am using

#include <Dynamixel2Arduino.h>

// Please modify it to suit your hardware.
#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA2560) // When using DynamixelShield
  #include <SoftwareSerial.h>
  SoftwareSerial soft_serial(7, 8); // DYNAMIXELShield UART RX/TX
  #define DXL_SERIAL   Serial
  #define DEBUG_SERIAL soft_serial
  const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_SAM_DUE) // When using DynamixelShield
  #define DXL_SERIAL   Serial
  #define DEBUG_SERIAL SerialUSB
  const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_SAM_ZERO) // When using DynamixelShield
  #define DXL_SERIAL   Serial1
  #define DEBUG_SERIAL SerialUSB
  const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#elif defined(ARDUINO_OpenCM904) // When using official ROBOTIS board with DXL circuit.
  #define DXL_SERIAL   Serial3 //OpenCM9.04 EXP Board's DXL port Serial. (Serial1 for the DXL port on the OpenCM 9.04 board)
  #define DEBUG_SERIAL Serial
  const uint8_t DXL_DIR_PIN = 22; //OpenCM9.04 EXP Board's DIR PIN. (28 for the DXL port on the OpenCM 9.04 board)
#elif defined(ARDUINO_OpenCR) // When using official ROBOTIS board with DXL circuit.
  // For OpenCR, there is a DXL Power Enable pin, so you must initialize and control it.
  // Reference link : https://github.com/ROBOTIS-GIT/OpenCR/blob/master/arduino/opencr_arduino/opencr/libraries/DynamixelSDK/src/dynamixel_sdk/port_handler_arduino.cpp#L78
  #define DXL_SERIAL   Serial3
  #define DEBUG_SERIAL Serial
  const uint8_t DXL_DIR_PIN = 84; // OpenCR Board's DIR PIN.    
#else // Other boards when using DynamixelShield
  #define DXL_SERIAL   Serial1
  #define DEBUG_SERIAL Serial
  const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#endif

ParamForSyncWriteInst_t sync_write_param;
int32_t set_position = 512;
const float DXL_PROTOCOL_VERSION = 1.0;
Dynamixel2Arduino dxl(DXL_SERIAL, DXL_DIR_PIN);

void setup() {
  dxl.begin(1000000);
  dxl.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
  dxl.scan();

  sync_write_param.addr = 30; //Goal position of DYNAMIXEL-AX series
  sync_write_param.length = 4;
  sync_write_param.xel[0].id = 1;
  sync_write_param.xel[1].id = 2;
  sync_write_param.id_count = 2;

  dxl.torqueOff(1);
  dxl.setOperatingMode(1, OP_POSITION);
  dxl.torqueOn(1);
  dxl.torqueOff(2);
  dxl.setOperatingMode(2, OP_POSITION);
  dxl.torqueOn(2);
  memcpy(sync_write_param.xel[0].data, (uint8_t*)set_position, sizeof(set_position));
  memcpy(sync_write_param.xel[1].data, (uint8_t*)-set_position,sizeof(set_position));

  dxl.syncWrite(sync_write_param);
}

void loop() {

}

could you tell me where is the wrong part. thanks in advance

DynamixelShield SoftwareSerial DIRPIN

Hello guys 👍,
First of all, thanks for your amazing works it help me a lot in my progression.
Actually, I use a Dynamixel Shield with a Cnc Shield on it for controlling Nema 17 stepper motor, and for controlling everything it's an Arduino Mega.
But, there is a problem, some of the motor use same pin of Dynamixel Shield in the code and it create conflit. The only way to solve this problem is to change the RX TX and DIR PIN of the Dynamixel Shield.
In the library SoftwareSerial you can change the RX and TX, I try but it's not working, and for the Dynamixel Shield DIRPIN I don't know if I can change that.
Can you tell me if it's possible to do ? And how I can to do it ?
Thanks a lot,
WilliamH07

slave.cpp processInstrWrite() no support for validating data other than ID and protocol version

When using user_write_callback_ for custom defined registers we have the option to check the values and return a packet_err and the response packet produced by processInstrWrite() will correctly reflect this error. But the copy code here already updates the data in the register's values and these are not back-ed up. This means, although the response of the communication message is that there was an error, the internal register is updated with the fault data.

I think the backed up approach should be generalized and be performed before the copy of data and then in the restore part it could copy back the back-ed up data to the register in a generic way.

Ping the motor every time you send a command?

Hello Kei,

Thanks for providing this library. I have a question: why do you want to ping() the motor every time you send a command? I guess pinging once in the setup to gather all model numbers and IDs is enough? I am afraid that too much communication slow things down because the computing power of Arduino is very limited. (Or, if I read your code wrong please also let me know)

Thanks so much,
Tianjian

if(ping(id) == true){

Seeeduino XIAO RP2040 outputs wrong CRC in packet

I wrote a simple arduino sketch to ping ID#1 for the Seeeduino XIAO and it works great. When I compile the exact same sketch for the XIAO RP2040 the output is different on the CRC value in packet as follows:

Seeeduino XIAO = "FF FF FD 0 1 3 0 1 19 4E" (which is correct and the dynamixel responds to)

Seeeduino XIAO RP2040 = "FF FF FD 0 1 3 0 1 2D 1" (wrong CRC?)

Can you guys look into this?

Multiple Control Dynamixel XL430 XL320

Hello everyone,
I'm starting to code a code with Dynamixel2Arduino library to control multiple xl430 and x320 (2x xl430 2x x320).
I use : position_mode to control my dynamixels, it works fine with only 1 dynamixel but I want to control 4 dynamixels in all. To control another dynamxiel I duplicate the code (I post the code I modified below). But with this only 1 dynamixel works (DXL_1). I don't understand why, can someone please help me?
Thank you,
WilliamH07


#include <Dynamixel2Arduino.h>

// Please modify it to suit your hardware.
#if defined(ARDUINO_AVR_UNO) || defined(ARDUINO_AVR_MEGA2560) // When using DynamixelShield
  #include <SoftwareSerial.h>
  SoftwareSerial soft_serial(7, 8); // DYNAMIXELShield UART RX/TX
  #define DXL_SERIAL   Serial
  #define DEBUG_SERIAL soft_serial
  const uint8_t DXL_DIR_PIN = 2; // DYNAMIXEL Shield DIR PIN
#endif
 

const uint8_t DXL_ID = 1;
const uint8_t DXL_ID2 = 10;
const float DXL_PROTOCOL_VERSION = 2.0;

Dynamixel2Arduino dxl(DXL_SERIAL, DXL_DIR_PIN);

//This namespace is required to use Control table item names
using namespace ControlTableItem;

void setup() {
  // put your setup code here, to run once:
  
  // Use UART port of DYNAMIXEL Shield to debug.
  DEBUG_SERIAL.begin(115200);

  // Set Port baudrate to 57600bps. This has to match with DYNAMIXEL baudrate.
  dxl.begin(1000000);
  // Set Port Protocol Version. This has to match with DYNAMIXEL protocol version.
  dxl.setPortProtocolVersion(DXL_PROTOCOL_VERSION);
  // Get DYNAMIXEL information
  dxl.ping(DXL_ID);
  dxl.ping(DXL_ID2);
  // Turn off torque when configuring items in EEPROM area
  dxl.torqueOff(DXL_ID);
  dxl.torqueOff(DXL_ID2);
  dxl.setOperatingMode(DXL_ID, OP_POSITION);
  dxl.setOperatingMode(DXL_ID2, OP_POSITION);
  dxl.torqueOn(DXL_ID);
  dxl.torqueOn(DXL_ID2);
  
}

void loop() {
  // put your main code here, to run repeatedly:
  
  // Please refer to e-Manual(http://emanual.robotis.com/docs/en/parts/interface/dynamixel_shield/) for available range of value. 
  // Set Goal Position in RAW value
  dxl.setGoalPosition(DXL_ID, 512);
  dxl.setGoalPosition(DXL_ID2, 512);
  delay(1000);
  // Print present position in raw value
  DEBUG_SERIAL.print("Present Position(raw) : ");
  DEBUG_SERIAL.println(dxl.getPresentPosition(DXL_ID));
  DEBUG_SERIAL.print("Present Position(raw)Dynamixel2 : ");
  DEBUG_SERIAL.println(dxl.getPresentPosition(DXL_ID2));
  delay(1000);

  // Set Goal Position in DEGREE value
  dxl.setGoalPosition(DXL_ID, 5.7, UNIT_DEGREE);
  dxl.setGoalPosition(DXL_ID2, 5.7, UNIT_DEGREE);
  delay(1000);
  // Print present position in degree value
  DEBUG_SERIAL.print("Present Position(degree) : ");
  DEBUG_SERIAL.println(dxl.getPresentPosition(DXL_ID, UNIT_DEGREE));
  DEBUG_SERIAL.print("Present Position(degree)Dynamxiel2 : ");
  DEBUG_SERIAL.println(dxl.getPresentPosition(DXL_ID2, UNIT_DEGREE));
  delay(1000);
}

Dynamixel2Arduino::begin() hangs if called after creating FreeRTOS tasks

The problem is actually in SerialPortHandler::begin(), which calls delay(). This redirects to HAL_Delay(), which ultimately relies on the STM32 HAL's timer tick ISR running. However, calling into the FreeRTOS API apparently disables interrupts until the scheduler is started. Per https://www.freertos.org/FAQHelp.html:

If a FreeRTOS API function is called before the scheduler has been started then interrupts will deliberately be left disabled, and not re-enable again until the first task starts to execute.

HAL_Delay() spins until the tick count reaches the necessary value, but since the tick ISR is not running, the tick count never increments, and therefore HAL_Delay() never returns.

The following code demonstrates the problem:

#include <RTOS.h>
#include <Dynamixel2Arduino.h>

void setup() {
    Serial.begin(57600);
    while ( !Serial ) delay(10);

    Serial.print("Creating task 1: ");
    auto res = xTaskCreate([](void*) { while (true); }, "task1", 512, nullptr, 3, nullptr );
    Serial.println( (res == pdPASS) ? "succeeded" : "failed" );

    Dynamixel2Arduino   dxl {Serial3};
    dxl.begin(57600);                           // <---------------- ** hangs here **

    Serial.print("Creating task 2: ");
    res = xTaskCreate([](void*) { while (true); }, "task2", 512, nullptr, 3, nullptr );
    Serial.println( (res == pdPASS) ? "succeeded" : "failed" );

    Serial.println("Starting scheduler");
    vTaskStartScheduler();
    Serial.println("Failed to start scheduler");
}

void loop() {}  // No-op under FreeRTOS

The comment ** hangs here ** shows the location of the problem. Dynamixel2Arduino::begin() calls SerialPortHandler::begin(). I added some instrumentation to the latter function to trace execution by turning on board LEDs:

void SerialPortHandler::begin(unsigned long baud)
{
digitalWrite(BDPIN_LED_USER_1, LOW);                                    // <---- This line executes
#if defined(ARDUINO_OpenCM904)
  if(port_ == Serial1 && getOpenState() == false){
    Serial1.setDxlMode(true);
  }
#elif defined(ARDUINO_OpenRB)
  if(port_ == Serial1 && getOpenState() == false){
    pinMode(BDPIN_DXL_PWR_EN, OUTPUT);
    digitalWrite(BDPIN_DXL_PWR_EN, HIGH);
    delay(300); // Wait for the FET to turn on.
  }
#elif defined(ARDUINO_OpenCR)
  if(port_ == Serial3 && getOpenState() == false){
    pinMode(BDPIN_DXL_PWR_EN, OUTPUT);
    digitalWrite(BDPIN_DXL_PWR_EN, HIGH);
  }
digitalWrite(BDPIN_LED_USER_2, LOW);                                    // <---- This line executes
  delay(300); // Wait for the DYNAMIXEL to power up normally.
digitalWrite(BDPIN_LED_USER_3, LOW);                                    // <---- This line is never reached
#endif
digitalWrite(BDPIN_LED_USER_4, LOW);

  baud_ = baud;
  port_.begin(baud_);
  mbedTXdelayus = 24000000 / baud;

  if(dir_pin_ != -1){
    pinMode(dir_pin_, OUTPUT);
    digitalWrite(dir_pin_, LOW);
    while(digitalRead(dir_pin_) != LOW);
  }

  setOpenState(true);
}

slave.cpp ``setPacketBuffer`` typo?

In slave.cpp I think there is typo in the setPacketBuffer:

bool 
Slave::setPacketBuffer(uint8_t* p_buf, uint16_t buf_capacity)
{
  if(p_packet_buf_ == nullptr){
    last_lib_err_ = DXL_LIB_ERROR_NULLPTR;
    return false;

...

shouldn't this be instead:

bool 
Slave::setPacketBuffer(uint8_t* p_buf, uint16_t buf_capacity)
{
  if(p_buf == nullptr){
    last_lib_err_ = DXL_LIB_ERROR_NULLPTR;
    return false;

...

The check should be against p_buf argument and not against p_packet_buf_ attribute?

The library simply does not work

Try the following:

XM430-W350-T
12V DC without Jumper (external power)
LED.ino Compilation and upload successful

I changed to AX-12A, changed to protocol 1.0 and nothing.

instead using
https://github.com/descampsa/ardyno
AX-12A with protocol 1.0 the shield works!

what is the difference between the DynamixelShield and Dynamixel2Arduino libraries, is very confusing.

Something am I doing wrong?

Sync Read Write Position Example Not Responding

I try to sync write position on AX-18 with opencm 9.04 using example. And nothing happen.

Serial Monitor :

=======================================================

Sync Instruction Test : 576
[SyncWrite] Success
ID: 1
Goal Velocity: 85
ID: 2
Goal Velocity: 185

[SyncRead] Fail, Lib error code: 2

Can not scan the Dynamixel 2xl430-w250-t

Hi
I recently purchased one 2xl430-w250-t and one Arduino shield. My goal is to use Arduino to control the Dynamixel motor. I have installed the Dynamixel2Arduino library through library manager. I have mounted the Arduino shield on top of Arduino Mega 2560. The Arduino Mega 2560 is connected to my Mac through a cable (USB-B to USB-C), the TTL cable is connecting the Arduino shield and one port of the Dynamixel 2xl430-w250-t (ID 1). I see the LED blink once when I turn on the switch of the Arduino shield. After I have uploaded the code, I switch the UART switch. The picture of my setup can be checked here.
However, I have encountered the problem:

  1. When I run the scan Dynamixel, the system tell me they found 0 motor. (I have to choose Arduino Mega ADK to have a proper print), the screenshot can be found here.
  2. When I do same thing but choosing Mega 2560, the print message is a bunch of unreadable “?” .
  3. I try to use Arduino UNO to do the same thing, the print message is a bunch of unreadable “?”
    The screenshot of problem 2 and 3 can be found here.

I have searched the forum, but I didn’t find anything useful. Can you give me some advice on this?

Best

Yuan

Reading Present Position Value too slow

I have an OpenCM9.04 + OpenCM485 EXP and using Dynamixel2Arduino library to talk to my MX-106T (2.0) servo. When i set the goal position and try to read present pos it's very slow/quite delayed.

bool success = dxl.setGoalPosition(hardwareId, pos); 
presentPos = dxl.getPresentPosition(hardwareId); 

For example, if I am trying to open from 2100 to 3200, the mx-106t will move and the pos you can see in real life is 3180 but the present pos being read is still ~2100 (previous position instead of present position). Even after doing a do-while loop like this:

 do{
    presentPos = dxl.getPresentPosition(hardwareId); 
  }while(abs(pos-presentPos)>20);
 

presentPos is delayed, if the servo moves slow enough. I changed moving speed to 60, and it cannot read position data properly in this speed. But at faster speeds like 150, it can keep up with the position a little bit better.

Additionally, Talking to servo is only succesful at 57600. Any baud rate greater than that, the mx-106t is unresponsive. Is there a reason why this happens? And how to fix?

Something confused about `byte_stuffing_cnt`

Hi there,

Thanks for your code. When I was reading your code, I noticed that you declared byte_stuffing_cnt as a private variable of the function:

static DXLLibErrorCode_t parse_dxl2_0_packet(InfoToParseDXLPacket_t* p_parse_packet, uint8_t recv_data)
{
DXLLibErrorCode_t ret = DXL_LIB_PROCEEDING;
uint16_t byte_stuffing_cnt = 0;

as far as I know from your repo, this function parse_dxl2_0_packet is called when a byte is received. So each time it is called, the variable byte_stuffing_cnt would reset to 0, which, I think, may cause bad influence on this line if there are many 'byte stuffing' in the packet:

if(p_parse_packet->recv_param_len+byte_stuffing_cnt+3 == p_parse_packet->packet_len){ // 3 = Instruction(1)+CRC(2)

Is it a bug or is there something wrong with my understanding? Hope for your reply sincerely.

XM540 Motors are not moving/responding

Hi,
I'm was using the outdated OpenCM IDE. However, I decided to transfer to Arduino I realized that my old code does not work anymore. I tried looking at Dyanmixel2Arduino and use the documentation to convert the code. However, it appears my motors are not responding. I tried running the example code and even then I am getting no response from the motors. I was wondering if anyone can help me with this? What library was the old OpenCM IDE using? I can't tell because I don't have any include statements. It uses Dynamixel.h but the Arduino version does not include methods such as writeDword and readByte. Please any help would be greatly appreciated!
Arduino Files.zip

XL430 and AX12A not working with dynamixel shield on Arduino MEGA/ UNO

Hello,
I'm working on one project.
Mainly I will be working with dynamixel xl430.
Currently i have ax12a along with xl430.
Few days before I had Arbotix M controller, through which i used to control AX12A. So i know ax12a are in working state.
I recently bought Dynamixelshield and XL430.
I did set up everything as per eManual.
I also got USB to to serial converter and its working perfectly with shield and i can see texts on serial monitor.
(Note: Now with mega, as per this post, im using serial on mega only for monitoring and that is working fine
#31 )
But main issue is the motors are not working with the shield.
i can see LED on servo blinks once after powering on.
Scan program shows 0 dynamixels found (Tried both with AX12A and XL430)
I have tried many possible solutions, but nothing is working.
I checked with multimeter, shield is getting enough power.
Also while uploading the sketch, switch was in uart mode and power turned off.
And i assume XL430 have ID 1 and baudrate of 57600 as they are brand new and no any code has worked on them.
Please help me solving this issue, Running the servos.
Attaching the serial monitors output and my hardware setup for better understanding.

Screenshot (199)
DynamixelShield-MEGA-AX12A

setOperatingMode does not work

I set the hinge mode to the 3rd ax-12a in the loop, but as it turned out that motors with id 2 and 3 did not set this mode.
All motors were connected and the port monitor displayed the model number according to their ID.
The motors were not working correctly, the motor was working correctly 1.
Then I opened the RoboPlus application and looked at their mode of operation. 2 and 3 had wheel mode.

Segmentation fault

Hi,

I have a compilation problem with the arduino. I can not understand why I have this problem. All I know is that it comes from the library Dynamixel2Arduino, I looked in the files given by the compiler. But I do not understand where the mistake is.

report error

OpenCM and MPU6050

Hi everyone, I am working with MPU6050 sensor connected with OPenCM9.04 board and using Arduino IDE to upload the code. I had used the same MPU6050 code (attached below) on Arduino Uno and it worked fine, but now the problem is when I uploaded the same code on OpenCM and opened the serial monitor the data from accelerometer fine but the gyro data is some different (photo attached).

Hardware setup:
MPU6050 OpenCM
MPU SCL -> pin24
MPU SDA -> pin25
MPU VIN -> 3V
MPU GND -> GND

MPU6050 code
`#include <Wire.h>
#include <math.h>
const int MPU = 0x68; // MPU6050 I2C address
float AccX, AccY, AccZ;
float GyroX, GyroY, GyroZ;
float accAngleX, accAngleY, gyroAngleX, gyroAngleY, gyroAngleZ;
float phiFold=0, phiFnew,thetaFold=0, thetaFnew;
float roll, pitch, yaw;
float AccErrorX=0, AccErrorY=0, GyroErrorX=0, GyroErrorY=0, GyroErrorZ=0;
float elapsedTime, currentTime, previousTime;
int c = 0;
int sample=1000;
float AcceX=0, AcceY=0, AcceZ=0;

/--------------------------------//void setup//----------------------------
void setup() {
Serial.begin(115200);
while(!Serial);
Wire.begin(); // Initialize communication
Wire.beginTransmission(MPU); // Start communication with MPU6050 // MPU=0x68
Wire.write(0x6B); // Talk to the register 6B
Wire.write(0x00); // Make reset - place a 0 into the 6B register
Wire.endTransmission(true); //end the transmission
calculate_IMU_error();
delay(20);
}

//--------------------------------//void loop//----------------------------
void loop() {
// === Read accelerometer data === //
Wire.beginTransmission(MPU);
Wire.write(0x3B); // Start with register 0x3B (ACCEL_XOUT_H)
Wire.endTransmission(false);
Wire.requestFrom(MPU, 14, true);

AccX = (Wire.read() << 8 | Wire.read()) / 16384.0;
AccY = (Wire.read() << 8 | Wire.read()) / 16384.0;
AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0;

// Calculating Roll and Pitch from the accelerometer data
accAngleX = (atan(AccY / sqrt(pow(AccX, 2) + pow(AccZ, 2))) * 180 / PI)+ -1AccErrorX;
accAngleY = (atan(-1 * AccX / sqrt(pow(AccY, 2) + pow(AccZ, 2))) * 180 / PI)-1
AccErrorY;

//low filter for accelerometer data
phiFnew=.9 * phiFold + .1 * accAngleX;
thetaFnew=.9 * thetaFold + .1 * accAngleY;

// === Read gyroscope data === //
previousTime = currentTime;
currentTime = millis();
elapsedTime = (currentTime - previousTime) / 1000;

Wire.beginTransmission(MPU);
Wire.write(0x43);
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);

GyroX = (Wire.read() << 8 | Wire.read()) / 131.0;
GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;
GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;

// Correct the outputs with the calculated error values
GyroX = GyroX -1 * GyroErrorX;
GyroY = GyroY -1 * GyroErrorY;
GyroZ = GyroZ -1 * GyroErrorZ;

// Currently the raw values are in degrees per seconds, deg/s, we need to multiply by sendonds (s) to get the angle in degrees
gyroAngleX = gyroAngleX + GyroX * elapsedTime; // deg/s * s = deg
gyroAngleY = gyroAngleY + GyroY * elapsedTime;
yaw = yaw + GyroZ * elapsedTime;

// Complementary filter - combine acceleromter and gyro angle values
gyroAngleX = 0.96 * gyroAngleX + 0.04 * phiFnew;
gyroAngleY = 0.96 * gyroAngleY + 0.04 * thetaFnew;

roll = gyroAngleX;
pitch = gyroAngleY;
float Yaw = yaw;

phiFold=phiFnew;
thetaFold=thetaFnew;

Serial.print(roll); Serial.print(" ");Serial.print(pitch); Serial.print(" ");Serial.println(Yaw);
delay (10);
}

//---------------------------------//Calculate IMU error//---------------------------------
void calculate_IMU_error() {

c=0;
while (c < sample) {
Wire.beginTransmission(MPU);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);

 AccX = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
 AccY = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
 AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0 ;

// Sum all readings
 AcceX = AcceX+AccX*9.8;
 AcceY = AcceY+AccY*9.8;
 AcceZ = AcceZ+AccZ*9.8;
c++;

}

//Divide the sum by 200 to get the error value
AcceX = AcceX / sample;
AcceY = AcceY / sample;
AcceZ = AcceZ / sample;

Serial.print("AcceX: ");
Serial.println(AcceX);
Serial.print("AcceY: ");
Serial.println(AcceY);
Serial.print("AcceZ: ");
Serial.println(AcceZ);
Serial.println(" ");
delay (1000);

// Read accelerometer values 200 times to calculate the accelerometer data error
c=0;
while (c < sample) {
Wire.beginTransmission(MPU);
Wire.write(0x3B);
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);

AccX = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
AccY = (Wire.read() << 8 | Wire.read()) / 16384.0 ;
AccZ = (Wire.read() << 8 | Wire.read()) / 16384.0 ;

// Sum all readings
AccErrorX = AccErrorX + ((atan((AccY) / sqrt(pow((AccX), 2) + pow((AccZ), 2))) * 180 / PI));
AccErrorY = AccErrorY + ((atan(-1 * (AccX) / sqrt(pow((AccY), 2) + pow((AccZ), 2))) * 180 / PI));
c++;

}

//Divide the sum by 200 to get the error value
AccErrorX = AccErrorX / sample;
AccErrorY = AccErrorY / sample;

// Read gyro values 200 times to calculate the gyro data error
c = 0;
while (c < sample) {
Wire.beginTransmission(MPU);
Wire.write(0x43);
Wire.endTransmission(false);
Wire.requestFrom(MPU, 6, true);

GyroX = (Wire.read() << 8 | Wire.read()) / 131.0;
GyroY = (Wire.read() << 8 | Wire.read()) / 131.0;
GyroZ = (Wire.read() << 8 | Wire.read()) / 131.0;

// Sum all readings
GyroErrorX = GyroErrorX + (GyroX);
GyroErrorY = GyroErrorY + (GyroY);
GyroErrorZ = GyroErrorZ + (GyroZ);
c++;

}

Serial.print("GyroX: ");
Serial.println(GyroX);
Serial.print("GyroY: ");
Serial.println(GyroY);
Serial.print("GyroZ: ");
Serial.println(GyroZ);
Serial.println(" ");
delay (2000);

//Divide the sum by 200 to get the error value
GyroErrorX = GyroErrorX / sample;
GyroErrorY = GyroErrorY / sample;
GyroErrorZ = GyroErrorZ / sample;

// Print the error values on the Serial Monitor
Serial.print("AccErrorX: ");
Serial.println(AccErrorX);
Serial.print("AccErrorY: ");
Serial.println(AccErrorY);
Serial.print("GyroErrorX: ");
Serial.println(GyroErrorX);
Serial.print("GyroErrorY: ");
Serial.println(GyroErrorY);
Serial.print("GyroErrorZ: ");
Serial.println(GyroErrorZ);
Serial.println(" ");
delay (2000);
}`

//---------------------------------//Serial monitor//---------------------------------
Arduino Uno (MPU data):

AcceX: 0.51
AcceY: -0.21
AcceZ: 9.09

GyroX: -1.92
GyroY: 1.18
GyroZ: -2.05

AccErrorX: -1.35
AccErrorY: -3.23
GyroErrorX: -1.70
GyroErrorY: 0.98
GyroErrorZ: -2.01

roll pitch yaw
0.33 -0.34 -1.42
0.31 -0.33 -1.42
0.30 -0.32 -1.42
0.29 -0.31 -1.42
0.28 -0.29 -1.42

OpenCM (MPU data):

AcceX: 0.39
AcceY: 0.61
AcceZ: 9.03

GyroX: 499.52

GyroY: 1.24

GyroZ: 499.30

AccErrorX: 3.85
AccErrorY: -2.46
GyroErrorX: 499.43
GyroErrorY: 1.29
GyroErrorZ: 499.36

roll pitch yaw
0.01 3.82 -1.52
0.01 3.67 -1.52
0.01 3.52 -1.52
//----------------------------------------------------------------------

I don't know what is wrong here using MPU with OpenCM... why the gyro values (OpenCM) are so different from those of arduino Uno data! these gyro values are not correct therefore I am not getting the pitch, yaw and roll correctly. I tried a lot but couldn't solve the problem and even I don't know where I am doing the mistake using OpenCM.
It would be great if any one can help and thanks.

ESP32 support

I was able to get Dynamixel2Arduino to work with ESP32 by making a custom SerialPortHandler that allowed me to re-assign the RX and TX pins on the ESP32. Could you please consider integrating my simple changes into a future version of the library?

Also, I noticed that changing baud rates on the ESP32 can cause the ESP32 to hang. But there is a special method to call for changing baud rate and I added that to my custom driver as well.

https://github.com/maehem/ESP32-Dynamixel

ControlTableItem not pointing to the right adress in EEPROM for AX-12A motors

I've been trying to dynamically change between wheel mode and joint mode for a couple days without success and looking through the library i noticed that when i call :

dxl.setOperatingMode(id, OP_POSITION)

the function writes to the wrong addresses in the EEPROM. It writes to 10 and 11 and should write to 6 and 8 on both these lines:

if(writeControlTableItem(ControlTableItem::CW_ANGLE_LIMIT, id, 0))
ret = writeControlTableItem(ControlTableItem::CCW_ANGLE_LIMIT, id, 1023);

pointing to actuator.h :

CW_ANGLE_LIMIT,
CCW_ANGLE_LIMIT,

I saw in actuator.cpp that there is the old control table for the AX-12A with the right addresses :

const ModelControlTableInfo_t control_table_1_0[] PROGMEM = {
#if (ENABLE_ACTUATOR_AX \
|| ENABLE_ACTUATOR_DX \
|| ENABLE_ACTUATOR_RX \
|| ENABLE_ACTUATOR_EX)
{ControlTableItem::MODEL_NUMBER, 0, 2},
{ControlTableItem::FIRMWARE_VERSION, 2, 1},
{ControlTableItem::ID, 3, 1},
{ControlTableItem::BAUD_RATE, 4, 1},
{ControlTableItem::RETURN_DELAY_TIME, 5, 1},
{ControlTableItem::CW_ANGLE_LIMIT, 6, 2},
{ControlTableItem::CCW_ANGLE_LIMIT, 8, 2},
{ControlTableItem::TEMPERATURE_LIMIT, 11, 1},
{ControlTableItem::MIN_VOLTAGE_LIMIT, 12, 1},
{ControlTableItem::MAX_VOLTAGE_LIMIT, 13, 1},
{ControlTableItem::MAX_TORQUE, 14, 2},
{ControlTableItem::STATUS_RETURN_LEVEL, 16, 1},
{ControlTableItem::ALARM_LED, 17, 1},
{ControlTableItem::SHUTDOWN, 18, 1},
{ControlTableItem::TORQUE_ENABLE, 24, 1},
{ControlTableItem::LED, 25, 1},
{ControlTableItem::CW_COMPLIANCE_MARGIN, 26, 1},
{ControlTableItem::CCW_COMPLIANCE_MARGIN, 27, 1},
{ControlTableItem::CW_COMPLIANCE_SLOPE, 28, 1},
{ControlTableItem::CCW_COMPLIANCE_SLOPE, 29, 1},
{ControlTableItem::GOAL_POSITION, 30, 2},
{ControlTableItem::MOVING_SPEED, 32, 2},
{ControlTableItem::TORQUE_LIMIT, 34, 2},
{ControlTableItem::PRESENT_POSITION, 36, 2},
{ControlTableItem::PRESENT_SPEED, 38, 2},
{ControlTableItem::PRESENT_LOAD, 40, 2},
{ControlTableItem::PRESENT_VOLTAGE, 42, 1},
{ControlTableItem::PRESENT_TEMPERATURE, 43, 1},
{ControlTableItem::REGISTERED, 44, 1},
{ControlTableItem::MOVING, 46, 1},
{ControlTableItem::LOCK, 47, 1},
{ControlTableItem::PUNCH, 48, 2},
#endif
{ControlTableItem::LAST_DUMMY_ITEM, 0, 0}
};

Is there a way to replace the control table in actuator.h with this one during the sketch initialisation so i can use the higer level functions of the library like dxl.setOperatingMode(id, OP_POSITION) ???

Thanks for your help.

MX-28 and MX64 library compatibility

I have tested 2 MX-28's and an MX-64 with the provided library and have been having issues with getting examples to work. The LED example works for all three servos, meaning the id, servo baud_rate, and protocol (1 for all) are all correct. I also verified these values through the dynamixel wizard, and they all correspond to the defaults. For one of the 28's, velocity_mode works as well, which is promising. However, the most important example I would like to get working is position_mode, and that doesn't work for any of them. Any feedback would be appreciated, thanks.

My control environment is a Dynamixel Shield, Arduino UNO, the Dynamixel2Arduino library (on one laptop included through arduino's ide and on another manually added), the MX-28/64 servo models, and a SMPS 12V 5A for power connected to the arduino itself.

Get factory limits / defaults from Servo

I need to get the range of numbers possible for the Min and Max limits but the function "getModelDependencyFuncInfo" is private and not sure how to use it. I would love to have something like "readControlTableItemDefaultValue(MAX_POSITION_LIMIT, DXL_ID)" to find out what the factory ranges are on a particular setting, without changing the settings. I can then use this to make some calculations.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.