AX-18A read_write_ax basics, servo not moving

Hello, this is my current equipment/setup:
OS: Windows 7
Servo: AX-18A
Board: OpenCM9.04 (Type-C)
Expansion: OpenCM 485
Power: Supplying 12V/0.58A to Expansion board and PC is connected to 9.04 with Micro USB to USB 2.0

Previous success: I was able to perform the Basics example to blink the LED.

Situation: In an attempt to learn to move the servo, I am following the example read_write_ax . My issue is after sending the letter “p” to the serial monitor, the motor does not move, it only repeatedly displays in the serial monitor [ID:1 GoalPos:100 PresPos0. After pressing p, nothing changes, it does not stop with q, and won’t break the loop. How can I get my servo to move?

Additional Question(s):

  1. Could my issue be related to the ID?
  • This setup originally had 6 AX’s set up in a daisy chain, but I am trying to understand how it works and currently only have one plugged in.
  1. How does the code know which port on the board the AX is plugged into on the CM9.04?

  2. My board feels quite warm in places, does this mean something is wrong?

  3. How much voltage do you supply to the board? The expansion board has a range of 5-30 volts, but the servos have a tighter range of 9-12 volts and the 9.04 has a range of 5-16 volts. In situations like this, which voltage range is the one to follow? Should we follow the range of the board we are directly supplying power to (the expansion board)?

I’m new to electronics and would appreciate any insights into the situation. Thank you for your time.

/*
 * Dynamixel : AX-series with Protocol 1.0
 * Controller : OpenCM9.04C + OpenCM 485 EXP
 * Power Source : SMPS 12V 5A
 * 
 * AX-Series are connected to Dynamixel BUS on OpenCM 485 EXP board or DXL TTL connectors on OpenCM9.04
 * http://emanual.robotis.com/docs/en/parts/controller/opencm485exp/#layout
 * 
 * This example will test only one Dynamixel at a time.
*/

#include <DynamixelSDK.h>

// AX-series Control table address
#define ADDR_AX_TORQUE_ENABLE           24                 // Control table address is different in Dynamixel model
#define ADDR_AX_GOAL_POSITION           30
#define ADDR_AX_PRESENT_POSITION        36

// Protocol version
#define PROTOCOL_VERSION                1.0                 // See which protocol version is used in the Dynamixel

// Default setting
#define DXL_ID                          1                   // Dynamixel ID: 1
#define BAUDRATE                        1000000
#define DEVICENAME                      "3"                 //DEVICENAME "1" -> Serial1(OpenCM9.04 DXL TTL Ports)
                                                            //DEVICENAME "2" -> Serial2
                                                            //DEVICENAME "3" -> Serial3(OpenCM 485 EXP)
#define TORQUE_ENABLE                   1                   // Value for enabling the torque
#define TORQUE_DISABLE                  0                   // Value for disabling the torque
#define DXL_MINIMUM_POSITION_VALUE      100                 // Dynamixel will rotate between this value
#define DXL_MAXIMUM_POSITION_VALUE      1000                // and this value (note that the Dynamixel would not move when the position value is out of movable range. Check e-manual about the range of the Dynamixel you use.)
#define DXL_MOVING_STATUS_THRESHOLD     20                  // Dynamixel moving status threshold

#define ESC_ASCII_VALUE                 0x1b



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


  Serial.println("Start..");


  // Initialize PortHandler instance
  // Set the port path
  // Get methods and members of PortHandlerLinux or PortHandlerWindows
  dynamixel::PortHandler *portHandler = dynamixel::PortHandler::getPortHandler(DEVICENAME);

  // Initialize PacketHandler instance
  // Set the protocol version
  // Get methods and members of Protocol1PacketHandler or Protocol2PacketHandler
  dynamixel::PacketHandler *packetHandler = dynamixel::PacketHandler::getPacketHandler(PROTOCOL_VERSION);

  int index = 0;
  int dxl_comm_result = COMM_TX_FAIL;             // Communication result
  int dxl_goal_position[2] = {DXL_MINIMUM_POSITION_VALUE, DXL_MAXIMUM_POSITION_VALUE};         // Goal position

  uint8_t dxl_error = 0;                          // Dynamixel error
  int16_t dxl_present_position = 0;               // Present position

  // Open port
  if (portHandler->openPort())
  {
    Serial.print("Succeeded to open the port!\n");
  }
  else
  {
    Serial.print("Failed to open the port!\n");
    Serial.print("Press any key to terminate...\n");
    return;
  }

  // Set port baudrate
  if (portHandler->setBaudRate(BAUDRATE))
  {
    Serial.print("Succeeded to change the baudrate!\n");
  }
  else
  {
    Serial.print("Failed to change the baudrate!\n");
    Serial.print("Press any key to terminate...\n");
    return;
  }

  // Enable Dynamixel Torque
  dxl_comm_result = packetHandler->write1ByteTxRx(portHandler, DXL_ID, ADDR_AX_TORQUE_ENABLE, TORQUE_ENABLE, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    packetHandler->getTxRxResult(dxl_comm_result);
  }
  else if (dxl_error != 0)
  {
    packetHandler->getRxPacketError(dxl_error);
  }
  else
  {
    Serial.print("Dynamixel has been successfully connected \n");
  }


  while(1)
  {
    Serial.print("Press any key to continue! (or press q to quit!)\n");


    while(Serial.available()==0);

    int ch;

    ch = Serial.read();
    if( ch == 'q' )
      break;

    // Write goal position
    dxl_comm_result = packetHandler->write2ByteTxRx(portHandler, DXL_ID, ADDR_AX_GOAL_POSITION, dxl_goal_position[index], &dxl_error);
    if (dxl_comm_result != COMM_SUCCESS)
    {
      packetHandler->getTxRxResult(dxl_comm_result);
    }
    else if (dxl_error != 0)
    {
      packetHandler->getRxPacketError(dxl_error);
    }

    do
    {
      // Read present position
      dxl_comm_result = packetHandler->read2ByteTxRx(portHandler, DXL_ID, ADDR_AX_PRESENT_POSITION, (uint16_t*)&dxl_present_position, &dxl_error);
      if (dxl_comm_result != COMM_SUCCESS)
      {
        packetHandler->getTxRxResult(dxl_comm_result);
      }
      else if (dxl_error != 0)
      {
        packetHandler->getRxPacketError(dxl_error);
      }

      Serial.print("[ID:");      Serial.print(DXL_ID);
      Serial.print(" GoalPos:"); Serial.print(dxl_goal_position[index]);
      Serial.print(" PresPos:");  Serial.print(dxl_present_position);
      Serial.println(" ");


    }while((abs(dxl_goal_position[index] - dxl_present_position) > DXL_MOVING_STATUS_THRESHOLD));

    // Change goal position
    if (index == 0)
    {
      index = 1;
    }
    else
    {
      index = 0;
    }
  }

  // Disable Dynamixel Torque
  dxl_comm_result = packetHandler->write1ByteTxRx(portHandler, DXL_ID, ADDR_AX_TORQUE_ENABLE, TORQUE_DISABLE, &dxl_error);
  if (dxl_comm_result != COMM_SUCCESS)
  {
    packetHandler->getTxRxResult(dxl_comm_result);
  }
  else if (dxl_error != 0)
  {
    packetHandler->getRxPacketError(dxl_error);
  }

  // Close port
  portHandler->closePort();

}

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

}

Hello CS, the power supply is a PASCO SF-9584A. For the amperage, It doesn’t really allow me to change the amount, it seems like specific voltages will just automatically set an amperage. When turning the amp knob, the value hardly changes. Do you think this is normal or could there be an issue?
Secondly, in an attempt to locate the ID of the one motor, I ran the example code o_find_dynamixel, but the code returns zero devices. As I mentioned earlier, I was able to run LED blink and can see a successful connection in my device manager. What could be the causing no dynamixel devices? My idea was that this code would tell me the ID or atleast show me info about the servos themselves. Am I understanding that example code’s purpose? I also tried connecting all six of the AX’s in their daisy chain configuration (3 directly plugged in and 3 others to plugged into one of the other three) and running the o_find code, but also returned zero devices. I also tried to locate the device using the Wizard 2.0, but I recently discovered it does not work with 9.04 with 485 Expansion board and my scans always turned up empty.
Some additional information: I am using Windows 7. The CM9.04 is connected through the Micro USB to a USB 2.0.
Lastly, thank you for your timely reply and easily understood information.

Do you have access to a U2D2 or comparable serial converter? That would allow us to easily verify the configuration of your servos via the Wizard.

Otherwise, before I offer more assistance I would like to confirm which exact ROBOTIS sample code you are using, we offer several different repos that can be used in the Arduino IDE, and I want to make sure that I am on the same page as you before I give you any incorrect information. A link to the source of the code in question would be perfect.

Hello Jonathon,

To your second point regarding the sample code, the current code I am using to attempt to gather information about the AX-18s is written below.

With respect to the serial converter, I do not have a Dynamixel U2D2 unfortunately. Is there a way that I can use the R+ Manager instead of Wizard 2.0? My understanding was Wizard 2.0 was incompatible with the CM9.04 + 485 expansion board. What does the U2D2 do? I have access to a lot electrical equipment, but I am unsure I have one comparable to U2D2.

Just to reiterate, my main issue is I am unable to get the servos to move. In an effort to debug, I followed the read_write_ax code (posted up above in the original post). Then, the reason I used the o_Find_Dynamixel was because after getting blink to work, read_write_ax did not move the motor. I have tried Wizard 2.0 but the scan was empty. I have uninstalled/reinstalled drivers for the CM many times. I also attempted to use R+ manager, but only had success in doing the firmware recovery, but the Update and Test option never worked. No matter what driver I had installed, the Update and Test always results in Cannot find device (when doing the scan). Sorry for the word dumps, but I want to provide as much information as I can. I’m not sure if the R+ manager is useful for my situation, but I was just trying everything.

I appreciate your effort and time.

Thank you,
Cameron

/*******************************************************************************
* Copyright 2016 ROBOTIS CO., LTD.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*     http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*******************************************************************************/

/* Authors: Taehun Lim (Darby) */

/*******************************************************************************
* WARNING
* DYNAMIXEL Workbench library is deprecated and will not be updated after 2020.
* Please use DYNAMIXEL2Arduino or DYNAMIXEL SDK instead.
* https://emanual.robotis.com/docs/en/parts/controller/opencm904/#library-api
*******************************************************************************/

#include <DynamixelWorkbench.h>

#if defined(__OPENCM904__)
  #define DEVICE_NAME "3" //Dynamixel on Serial3(USART3)  <-OpenCM 485EXP
#elif defined(__OPENCR__)
  #define DEVICE_NAME ""
#endif   

#define BAUDRATE_NUM 7

DynamixelWorkbench dxl_wb;

void setup() 
{
  Serial.begin(57600);
  while(!Serial); // Wait for Opening Serial Monitor

  const char *log;
  bool result = false;

  uint8_t scanned_id[100];
  uint8_t dxl_cnt = 0;

  uint32_t baudrate[BAUDRATE_NUM] = {9600, 57600, 115200, 1000000, 2000000, 3000000, 4000000};
  uint8_t range = 253;

  uint8_t index = 0;

  while (index < BAUDRATE_NUM)
  {
    result = dxl_wb.init(DEVICE_NAME, baudrate[index], &log);
    if (result == false)
    {
      Serial.println(log);
      Serial.println("Failed to init");
    }
    else
    {
      Serial.print("Succeed to init : ");
      Serial.println(baudrate[index]);  
    }

    dxl_cnt = 0;
    for (uint8_t num = 0; num < 100; num++) scanned_id[num] = 0;

    result = dxl_wb.scan(scanned_id, &dxl_cnt, range, &log);
    if (result == false)
    {
      Serial.println(log);
      Serial.println("Failed to scan");
    }
    else
    {
      Serial.print("Find ");
      Serial.print(dxl_cnt);
      Serial.println(" Dynamixels");

      for (int cnt = 0; cnt < dxl_cnt; cnt++)
      {
        Serial.print("id : ");
        Serial.print(scanned_id[cnt]);
        Serial.print(" model name : ");
        Serial.println(dxl_wb.getModelName(scanned_id[cnt]));
      }
    } 

    index++;
  }
}

void loop() 
{

}
1 Like

The U2D2 is an adapter allowing USB to Serial communication to control the DYNAMIXEL, it is the simplest way to troubleshoot any problems with the servos because it allows relatively direct communication and configuration.

R+ Manager is similarly incompatible with the OpenCM with the Expansion Board, both R+ Manager and DYNAMIXEL Wizard are designed to be used as configuration and diagnostic tools with the U2D2.

To exhaust one more possible cause of issues, have you completed the board installation steps for the OpenCM on our eManual?

If that is not the cause of your issue, would you mind posting the serial monitor output resulting from running the DYNAMIXEL detection code, as well as that of the movement example you are trying to run.

I really appreciate your comprehensive delivery of information, it makes assisting you much more straightforward.

If you are interested in using the Dynamixel2Arduino library instead, this post may be of help to you.

Your issue is very strange. If the AX series has not been reconfigured from the factory status. It should work (I just check)

Please share the image of your H/W setup & software result (Both upload & serial monitor)