1. Select the type of data reported: current/torque data

When the reported data type is torque (unit: Nm), the command issued is as follows:

00 01 00 02 00 02 46 00

When the reported data type is current (unit: A), the command issued is as follows:

00 01 00 02 00 02 46 01

Note: Regarding the type of the reporting data, please refer to page 37 of the xArm developer manual: the xArm developer manual

2. When the robotic arm executes the Blockly example below, execute the C++ example of Appendix 1 or Python example of Appendix 2 to get the joint torque data/joint current data of the robotic arm. It connects to controller port 30003 to get data report at 100Hz.

Typical joint torque diagram(joint 3)

Typical joint current diagram(joint 3)

Appendix-1

#include <unistd.h>  
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <unistd.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/tcp.h>
#include <arpa/inet.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
static float hex_to_fp32(unsigned char datahex[4]) {
union _fp32hex {
float dataf;
unsigned char datahex[4];
} fp32hex;
fp32hex.datahex[0] = datahex[0];
fp32hex.datahex[1] = datahex[1];
fp32hex.datahex[2] = datahex[2];
fp32hex.datahex[3] = datahex[3];
return fp32hex.dataf;
}
static void hex_to_nfp32(unsigned char *datahex, float *dataf, int n) {
for (int i = 0; i < n; ++i) dataf[i] = hex_to_fp32(&datahex[i * 4]);
}
int connect_remote_server(const char *server_ip, int port_num)
{
struct sockaddr_in server_addr;
int client_sockfd = socket(AF_INET, SOCK_STREAM, 0);
server_addr.sin_family = AF_INET;
server_addr.sin_addr.s_addr = inet_addr(server_ip);
server_addr.sin_port = htons(port_num);
if(connect(client_sockfd, (struct sockaddr *)&server_addr, sizeof(server_addr)))
{
fprintf(stderr, "Error connecting remote server!\n");
close(client_sockfd);
return -1;
}
return client_sockfd;
}
// Compile: $ g++ xArm_report_30003.cpp -o xArm_report_30003
// Run Example: $ ./xArm_report_30003 192.168.1.227 1
// Use "Ctrl-C" to terminate
int main(int argc, char** argv)
{
// PAY ATTENTION to this notice
fprintf(stderr, "\nMake sure robot is already ENABLED! Firmware version >= 1.5.2!\n\n");
if(argc!=3)
{
fprintf(stderr, "[Usage: ] argument 1: robot ip address (e.g. 192.168.1.227), argument 2: 0 for estimated torque report, 1 for actual motor current report\n");
return -1;
}
// connect to xArm control port
int client_sock = connect_remote_server(argv[1], 502);
unsigned char report_current_config[8] = {0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x46, 0x01};
unsigned char report_torque_config[8] = {0x00, 0x01, 0x00, 0x02, 0x00, 0x02, 0x46, 0x00};
unsigned char recv_chars[128] = {0};
std::string report_str;
float data[7] = {0};
int ret = 0;
if(client_sock!=-1)
{
// First set the report content as torque(0) or current(1), refer to the latest xArm developer manual at page 38 and 39
switch(atoi(argv[2]))
{
case 0:
ret = send(client_sock, report_torque_config, sizeof(report_torque_config), 0);
report_str = "estimated joint torques:\n";
break;
case 1:
ret = send(client_sock, report_current_config, sizeof(report_current_config), 0);
report_str = "feedback motor currents:\n";
break;
default:
fprintf(stderr, "[Error: ] Invalid argument 2, 0 for estimated torque report, 1 for actual motor current report\n");
return -1;
}
ret = recv(client_sock, recv_chars, 32, 0);

sleep(1);
// Connect to report port 30003 for High frequency (100Hz) report of joint torque or current. Refer to latest xArm Developer manual at page 62 (2.1.6. Automatic Reporting Format)
client_sock = connect_remote_server(argv[1], 30003);
if(client_sock!=-1)
{
while(true)
{
ret = recv(client_sock, recv_chars, 87, 0);
if(ret<0)
break;
hex_to_nfp32(&recv_chars[59], data, 7);
fprintf(stderr, "%s", report_str.c_str());
for(int i=0; i<7; i++)
fprintf(stderr, "%f\t", data[i]);
fprintf(stderr, "\n" );
}
}
else
{
fprintf(stderr, "Please check the robot connection!\n");
return -1;
}
}
return 0;
}

Appendix-2

import socket
import struct
def bytes_to_fp32(bytes_data, is_big_endian=False):
"""
bytes to float
:param bytes_data: bytes
:param is_big_endian: is big endian or not,default is False.
:return: fp32
"""
return struct.unpack('>f' if is_big_endian else '<f', bytes_data)[0]

def bytes_to_fp32_list(bytes_data, n=0, is_big_endian=False):
"""
bytes to float list
:param bytes_data: bytes
:param n: quantity of parameters need to be converted,default is 0,all bytes converted.
:param is_big_endian: is big endian or not,default is False.
:return: float list
"""
ret = []
count = n if n > 0 else len(bytes_data) // 4
for i in range(count):
ret.append(bytes_to_fp32(bytes_data[i * 4: i * 4 + 4], is_big_endian))
return ret

def bytes_to_u32(data):
data_u32 = data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]
return data_u32

robot_ip = '192.168.1.XXX' # IP of controller
robot_port = 30003 # Port of controller

# create socket to connect controller
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
sock.setblocking(True)
sock.settimeout(1)
sock.connect((robot_ip, robot_port))

while True:
data = sock.recv(4)
length = bytes_to_u32(data)
data += sock.recv(length - 4)
joint_date = bytes_to_fp32_list(data[59:87])
print(joint_date)
Did this answer your question?