Hi all, I am trying to use sync read to read different addresses (Current and position) from multiple MX106 (ID 0 and 1). I’m not sure how to add different parameters to be sent for bulk sync. This was modified from an example on bulk sync for a dynamixel shield connected to an MCU with 2 UART
#include <DynamixelShield.h>
DynamixelShield dxl(Serial2, 18); // Using Serial2 for Dynamixel communication
const uint8_t BROADCAST_ID = 254;
const float DYNAMIXEL_PROTOCOL_VERSION = 2.0;
const uint8_t DXL_ID_CNT = 2;
const uint8_t DXL_ID_LIST[DXL_ID_CNT] = {0, 1}; // Motor IDs 0 and 1
const uint16_t user_pkt_buf_cap = 128;
uint8_t user_pkt_buf[user_pkt_buf_cap];
// Starting addresses and lengths of data to read for each Dynamixel motor
const uint16_t SR_START_ADDRS[DXL_ID_CNT] = {132, 126}; // Present Position and Present Current
const uint16_t SR_ADDR_LENGTHS[DXL_ID_CNT] = {4, 2}; // Lengths of data for each starting address
typedef struct sr_data {
int32_t present_position;
int16_t present_current;
} __attribute__((packed)) sr_data_t;
sr_data_t sr_data;
DYNAMIXEL::InfoSyncReadInst_t sr_infos;
DYNAMIXEL::XELInfoSyncRead_t info_xels_sr[DXL_ID_CNT];
void setup() {
uint8_t i;
// pinMode(LED_BUILTIN, OUTPUT);
Serial.begin(115200); // Using Serial for printing debug information
dxl.begin(115200); // Using Serial2 for Dynamixel communication
dxl.setPortProtocolVersion(DYNAMIXEL_PROTOCOL_VERSION);
for (i = 0; i < DXL_ID_CNT; i++) {
dxl.torqueOff(DXL_ID_LIST[i]);
dxl.setOperatingMode(DXL_ID_LIST[i], OP_POSITION);
}
dxl.torqueOn(BROADCAST_ID);
// Fill SyncRead structure members using an external user packet buffer
sr_infos.packet.p_buf = user_pkt_buf;
sr_infos.packet.buf_capacity = user_pkt_buf_cap;
sr_infos.packet.is_completed = false;
sr_infos.p_xels = info_xels_sr;
sr_infos.xel_count = 0;
// Prepare SyncRead structure
for (i = 0; i < DXL_ID_CNT; i++) {
info_xels_sr[i].id = DXL_ID_LIST[i];
info_xels_sr[i].p_recv_buf = (uint8_t *)&sr_data + i * sizeof(sr_data_t); // Adjust parsing
sr_infos.addr = SR_START_ADDRS[i];
sr_infos.addr_length = SR_ADDR_LENGTHS[i];
sr_infos.xel_count++;
}
sr_infos.is_info_changed = true;
}
void loop() {
static uint32_t try_count = 0;
uint8_t recv_cnt;
// Transmit predefined SyncRead instruction packet
// and receive a status packet from each DYNAMIXEL
recv_cnt = dxl.syncRead(&sr_infos);
if (recv_cnt > 0) {
Serial.print("[SyncRead] Success, Received ID Count: ");
Serial.println(recv_cnt);
for (uint8_t i = 0; i < recv_cnt; i++) {
Serial.print(" ID: ");
Serial.print(sr_infos.p_xels[i].id);
Serial.print(", Error: ");
Serial.println(sr_infos.p_xels[i].error);
Serial.print("\t Present Position (raw): ");
Serial.println(sr_data.present_position, HEX);
Serial.print("\t Present Current (raw): ");
Serial.println(sr_data.present_current, HEX);
}
} else {
Serial.print("[SyncRead] Fail, Lib error code: ");
Serial.println(dxl.getLastLibErrCode());
}
Serial.println("=======================================================");
delay(750);
}
Last year, I found another way to do Sync-Read/Write that does not use that “packed data” structure in your current approach and it also uses the Dynamixel2Arduino Library directly (not via Dynamixel Shield Library). You want to try it? Here is the link to that post
Interesting! I only used either the OpenRB-150 or the MKR DXL Shield with MKR Zero and I did not have that issue.
I do not have the original DXL Shield and your types of Arduino board so I can’t help further - Sorry
Bulk Read:
This instruction is used for reading values of multiple MX series DYNAMIXEL’s simultaneously by sending a single Instruction Packet. The packet length is shortened compared to sending multiple READ commands, and the idle time between the status packets being returned is also shortened to save communication time. However, this cannot be used to read a single module. If an identical ID is designated multiple times, only the first designated parameter will be processed.
Hence we would have to read through all data between the smallest to largest address for each motor.