Manual de Usuario del Motor Serie HighTorque
Guía de Inicio Rápido del Motor Serie HighTorque
Este documento presentará cómo comenzar rápidamente con los motores de la serie HighTorque.

Especificaciones Técnicas
Tabla de Comparación de Parámetros del Módulo de Articulación Planetaria
Descarga de Especificaciones Técnicas | HTDW-5047-36-NE | HTDW-4438-32-NE |
---|---|---|
Relación de Reducción | 36 | 30 |
Torque Pico (Nm) | 16 | 6 |
Torque Nominal (Nm) | 4 | 1.5 |
Torque de Bloqueo (Nm) | 24 | 10 |
Velocidad Nominal (RPM) | 40 | 36 |
Velocidad sin Carga (RPM) | 60 | 75 |
Potencia Nominal (W) | 17 | 13 |
Constante de Torque (Nm/A) | 0.062 | 0.039 |
Pares de Polos | 14 | - |
Voltaje Nominal (V) | 12-48 | 12-48 |
Corriente Nominal (A) | 2 | 1 |
Corriente Pico (A) | 10 | 5 |
Precisión de Control de Torque | ±10% | ±20% |
Precisión de Control de Velocidad | ±8% | ±10% |
Tiempo de Respuesta (μs) | ≤200 | ≤200 |
Resolución del Encoder de Alta Velocidad | 14bit | 14bit |
Resolución del Encoder de Baja Velocidad | 12bit | 12bit |
Velocidad de Baudios de Comunicación (Mbps) | 5 | 5 |
Frecuencia de Control (Hz) | 3k | 3k |
Dimensiones de Instalación del Motor
- HTDM-4438-32:

- HTDM-5047-36:

Preparación de PC con Windows
- Descargar Asistente de Depuración de Motor v1.2.1
- Descargar Manual de Depuración de PC
- Comprar Placa de Controlador CAN-USB
Análisis de Protocolo
Análisis de Protocolo
1.1 Instrucciones Relacionadas con CAN
- Velocidad de transmisión CAN:
- Segmento de arbitraje: 1 Mbps
- Segmento de datos: 1 Mbps
- ID: Consiste en 16 bits, donde 0x7F es la dirección de difusión.
- 8 bits altos: Representan la dirección de origen:
- El bit más alto es 1: Requiere una respuesta, actuando como un interruptor maestro. Habilitarlo sin enviar un comando de consulta devolverá una trama con una longitud de segmento de datos de 0.
- El bit más alto es 0: No se necesita respuesta.
- Los 7 bits restantes: Dirección de origen de la señal.
- 8 bits bajos: Representan la dirección de destino:
- El bit más alto es 0.
- Los 7 bits restantes representan la dirección de destino.
- 8 bits altos: Representan la dirección de origen:
Por ejemplo:
- ID: 0x8001
- La dirección de origen de la señal es 0.
- La dirección de destino es 1.
- El bit más alto es 1, indicando que se requiere una respuesta, es decir, el interruptor maestro de respuesta está activado.
- ID: 0x100
- La dirección de origen de la señal es 1.
- La dirección de destino es 0.
- El bit más alto es 0, indicando que no se necesita respuesta, es decir, el interruptor maestro de respuesta está desactivado.
1.2 Instrucciones de Modo
1.2.1 Modo Normal (La posición y la velocidad no se pueden controlar simultáneamente)
uint8_t cmd[] = {0x07, 0x07, pos1, pos2, val1, val2, tqe1, tqe2};
El protocolo normal está compuesto por: bits de comando (2 bytes) + posición (2 bytes) + velocidad (2 bytes) + torque (2 bytes), totalizando 8 bytes.
0x07 0x07: Modo normal, que puede controlar velocidad y torque, o posición y torque (ver [[#2.1 Modo Normal]]).
Los datos de posición, velocidad y torque en el protocolo están en modo little-endian, lo que significa que el byte bajo se envía primero, seguido del byte alto. Por ejemplo, si pos = 0x1234, entonces pos1 = 0x34 y pos2 = 0x12.
Este modo se puede dividir en dos métodos de control:
- Control de posición y torque (en este momento, val = 0x8000, indicando sin límite).
- Control de velocidad y torque (en este momento, pos = 0x8000, indicando sin límite).
1.2.2 Modo de Torque
uint8_t cmd[] = {0x05, 0x13, tqe1, tqe2};
El protocolo del modo de torque consiste en: bits de comando (2 bytes) + torque (2 bytes).
0x05 0x13: Modo de torque puro, seguido por dos bytes de datos de torque (ver [[#2.3 Modo de Torque]]).
Los datos de torque en el protocolo están en modo little-endian, es decir, el byte bajo se envía primero, seguido por el byte alto. Por ejemplo, si tqe = 0x1234, entonces tqe1 = 0x34 y tqe2 = 0x12.
1.2.3 Modo de Control Cooperativo (La posición, velocidad y torque pueden controlarse simultáneamente)
uint8_t cmd[] = {0x07, 0x35, val1, val2, tqe1, teq2, pos1, pos2};
El protocolo del modo de control cooperativo: bits de comando (2 bytes) + velocidad (2 bytes) + torque (2 bytes) + posición (2 bytes), totalizando 8 bytes.
0x07 0x35: Modo de control cooperativo, que especifica rotar a una velocidad especificada hasta una posición especificada y limitar el torque máximo.
En este modo, usar el parámetro 0x8000 indica sin límite (sin límite en velocidad y torque significa el valor máximo). Por ejemplo, val = 5000, tqe = 1000, pos = 0x8000: Significa que el motor rota a una velocidad de 0.5 rotaciones por segundo, con un torque máximo de 0.1 NM.
Los datos de posición, velocidad y torque en el protocolo están todos en modo little-endian, es decir, el byte bajo se envía primero, seguido del byte alto. Por ejemplo, si pos = 0x1234, entonces pos1 = 0x34 y pos2 = 0x12.
1.3 Lectura de Datos de Estado del Motor
- El protocolo para leer la parte del estado del motor es el mismo que el protocolo en CAN-FD, con la única diferencia de que CAN está limitado por un segmento de datos de 8 bytes.
- Para la dirección del registro y las instrucciones de función, consulte el archivo "Register Function, Motor Operation Mode, Error Code Instructions.xlsx".
- Debido a la limitación del segmento de datos de 8 bytes de CAN, una sola trama CAN puede devolver una cantidad limitada de información del motor:
- Una información del motor de tipo float o int32_t en un registro.
- Tres informaciones consecutivas del motor de tipo int16_t.
- Seis informaciones consecutivas del motor de tipo int8_t.
- El programa de ejemplo proporciona funciones de muestra para consultar información de posición, velocidad y torque del motor de tipo int16_t y análisis de información del motor (el programa de ejemplo usa una unión en lenguaje C para copiar directamente los datos del 3er al 8vo byte en CAN).
1.3.1 Instrucciones del Protocolo de Envío
uint8_t tdata[] = {cmd, addr, cmd1, addr1, cmd2, add2};
El significado general es: Leer cmd[0, 1] número de datos de tipo cmd[3, 2] desde addr.
cmd:
- Cuatro bits altos [7, 4]: 0001 indica lectura.
- Bits 2-3 [3, 2]: Indican el tipo.
- 00: tipo int8_t.
- 01: tipo int16_t.
- 10: tipo int32_t.
- 11: tipo float.
- 2 bits bajos [1, 0]: Indican la cantidad.
- 01: Un dato.
- 10: Dos datos.
- 11: Tres datos.
addr: La dirección inicial a adquirir.
Múltiples cmds y addrs pueden concatenarse para leer datos con direcciones discontinuas y diferentes tipos de una sola vez.
1.3.2 Instrucciones del Protocolo de Recepción
Asuma que los datos adquiridos son uint16_t.
uint8_t rdata[] = {cmd, addr, a1, a2, b1, b2, ..., cmd1, addr1, c1, c2, c3, c4}
cmd:
- Cuatro bits altos [7, 4]: 0010 indica respuesta.
- Bits 2-3 [3, 2]: Indican el tipo.
- 00: tipo int8_t.
- 01: tipo int16_t.
- 10: tipo int32_t.
- 11: tipo float.
- 2 bits bajos [1, 0]: Indican la cantidad.
- 01: Un dato.
- 10: Dos datos.
- 11: Tres datos.
addr: La dirección inicial a adquirir.
a1, a2: Dato 1, en modo little-endian.
b1, b2: Dato 2, en modo little-endian.
1.3.3 Ejemplo
- Necesitamos leer datos de posición, velocidad y torque.
- De la tabla excel de registros, sabemos que las direcciones de datos para posición, velocidad y torque son: 01, 02, 03.
- De esto, podemos ver que podemos leer 3 datos consecutivos comenzando desde la dirección 01. Considerando que CAN puede transmitir un máximo de 8 bytes de datos a la vez, y cmd + addr ocupa dos bytes, el tipo de dato puede ser como máximo tipo int16_t.
- De lo anterior, el binario de cmd es: 0001 0111, y el hexadecimal es: 0x17.
- Es necesario comenzar a leer desde la dirección 01, por lo que addr es 0x01.
- Los datos totales a enviar son uint8_t tdata[] = 1.
El código de ejemplo es el siguiente:
/**
* @brief Read the motor
* @param id
*/
void motor_read(uint8_t id)
{
static uint8_t tdata[8] = {0x17, 0x01};
CAN_Send_Msg(0x8000 | id, tdata, sizeof(tdata));
}
uint8_t cmd[] = {0x17, 0x01};
El significado general es: Comenzar desde la dirección 0x01 y leer 3 registros int16_t (según la tabla, los registros en las direcciones 0x01 a 0x03 representan posición, velocidad y torque respectivamente). Por lo tanto, este comando es para consultar la información de posición, velocidad y torque del motor.
0x17: El binario de 0x17[7:4] es 0001: indica lectura. El binario de 0x17[3:2] es 01: indica que el tipo de datos es int16_t. El binario de 0x17[1:0] es 11: indica que el número de datos es 3. 0x01: Comenzar desde la dirección 0x01.
Ejemplo de datos recibidos correspondiente:
uint8_t rdata[] = {0x27, 0x01, 0x38, 0xf6, 0x09, 0x00, 0x00, 0x00};
0x27: Corresponde al 0x17 enviado. 0x01: Iniciar desde la dirección 0x01. 0x38 0xf6: Datos de posición: 0xf638, es decir, -2505. 0x09 0x00: Datos de velocidad: 0x0009, es decir, 9. 0x00 0x00: Datos de torque: 0x0000, es decir, 0.
1.4 Parada del Motor
Instrucciones:
- Detener el motor.
- Corresponde a la instrucción d stop del ordenador anfitrión.
/**
* @brief Stop the motor
*/
void motor_stop(uint8_t id)
{
uint8_t tdata[] = {0x01, 0x00, 0x00};
CAN_Send_Msg(0x8000 | id, tdata, sizeof(tdata));
}
1.5 Restablecer Posición Cero del Motor
Instrucciones:
- Establecer la posición actual como la posición cero del motor.
- Esta instrucción solo la modifica en RAM y necesita ser usada con la instrucción conf write para guardarla en flash.
- Se recomienda enviar la instrucción conf write aproximadamente 1s después de usar esta instrucción.
void rezero_pos(uint8_t id)
{
uint8_t tdata[] = {0x40, 0x01, 0x04, 0x64, 0x20, 0x63, 0x0a};
CAN_Send_Msg(0x8000 | id, tdata, sizeof(tdata));
HAL_Delay(1000); // It is recommended to delay for 1s
conf_write(id); // Save the settings
}
1.6 Guardar Configuración del Motor (conf write)
Instrucciones:
- Guardar la configuración del motor en RAM a la memoria flash.
- Se recomienda reiniciar el motor después de usar esta instrucción.
void conf_write(uint8_t id)
{
uint8_t tdata[] = {0x05, 0xb3, 0x02, 0x00, 0x00};
CAN_Send_Msg(0x8000 | id, tdata, sizeof(tdata));
}
1.7 Leer Estado del Motor
Instrucciones:
- Leer los datos de posición, velocidad y torque del motor una vez.
- Para el análisis de los datos de información del estado de retroalimentación del motor, consulte el código en la función de interrupción HAL_FDCAN_RxFifo0Callback en el ejemplo.
* @brief Instruction to read motor position, speed, and torque
* @param id Motor ID
*/
void motor_read(CAN_HandleTypeDef *hcan, uint8_t id)
{
static uint8_t tdata[8] = {0x17, 0x01};
can_send(hcan, 0x8000 | id, tdata, sizeof(tdata));
}
1.8 Devolver Periódicamente Datos de Estado del Motor
Instrucciones:
- Devolver periódicamente datos de posición, velocidad y torque del motor.
- El formato de datos devuelto es el mismo que el obtenido usando la instrucción 0x17, 0x01 (es decir, 1.7 Lectura de Estado de Posición).
- La unidad del período es ms.
- El período mínimo es 1ms.
- Para detener el retorno periódico de datos, establezca el período en 0 o apague el motor.
- Para el análisis de los datos de información de estado de retroalimentación del motor, consulte el código en la función de interrupción HAL_FDCAN_RxFifo0Callback en el ejemplo.
void timed_return_motor_status(uint8_t id, int16_t t_ms)
{
uint8_t tdata[] = {0x05, 0xb4, 0x02, 0x00, 0x00};
*(int16_t *)&tdata[3] = t_ms;
CAN_Send_Msg(0x8000 | id, tdata, sizeof(tdata));
}
2. Funciones de Ejemplo
2.1 Modo Normal
2.1.1 Control de Posición
/**
* @brief Position control
* @param id Motor ID
* @param pos Position: Unit 0.0001 circle, e.g., pos = 5000 means rotating to the position of 0.5 circle.
* @param torque
*/
void motor_control_Pos(uint8_t id,int32_t pos,int16_t tqe)
{
uint8_t tdata[8] = {0x07, 0x07, 0x0A, 0x05, 0x00, 0x00, 0x80, 0x00};
*(int16_t *)&tdata[2] = pos;
*(int16_t *)&tdata[6] = tqe;
uint32_t ext_id = (0x8000 | id);
CAN_Send_Msg(ext_id, tdata, 8);
}
2.1.2 Control de Velocidad
/**
* @brief Speed control
* @param id Motor ID
* @param vel Speed: Unit 0.00025 rotations/second, e.g., val = 1000 means 0.25 rotations/second
* @param tqe Torque
*/
uint8_t tdata[8] = {0x07, 0x07, 0x00, 0x80, 0x20, 0x00, 0x80, 0x00};
*(int16_t *)&tdata[4] = vel;
*(int16_t *)&tdata[6] = tqe;
uint32_t ext_id = (0x8000 | id);
CAN_Send_Msg(ext_id, tdata, 8);
}
2.3 Modo de Par
/**
* @brief Torque mode
* @param id Motor ID
* @param tqe Torque
*/
void motor_control_tqe(uint8_t id,int32_t tqe)
{
uint8_t tdata[8] = {0x05, 0x13, 0x00, 0x80, 0x20, 0x00, 0x80, 0x00};
*(int16_t *)&tdata[2] = tqe;
CAN_Send_Msg(0x8000 | id, tdata, 4);
}
2.4 Modo de Control Cooperativo
/**
* @brief Motor position-speed-feedforward torque (maximum torque) control, int16 type
* @param id Motor ID
* @param pos Position: Unit 0.0001 circle, e.g., pos = 5000 means rotating to the position of 0.5 circle.
* @param val Speed: Unit 0.00025 rotations/second, e.g., val = 1000 means 0.25 rotations/second
* @param tqe Maximum torque
*/
void motor_control_pos_val_tqe(uint8_t id, int16_t pos, int16_t val, int16_t tqe)
{
static uint8_t tdata[8] = {0x07, 0x35, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
*(int16_t *)&tdata[2] = val;
*(int16_t *)&tdata[4] = tqe;
*(int16_t *)&tdata[6] = pos;
CAN_Send_Msg(0x8000 | id, tdata, 8);
}
2.5 Modo de Voltaje DQ
Instrucciones:
- Puede controlar el voltaje de la fase Q, unidad: 0.1v, p. ej., vol = 10 significa que el voltaje de la fase Q es 1V.
void motor_control_volt(FDCAN_HandleTypeDef *hfdcanx, uint8_t id, int16_t vol)
static uint8_t tdata[7] = {0x01, 0x00, 0x08, 0x05, 0x1b, 0x00, 0x00};
*(int16_t *)&tdata[5] = vol;
can_send(hfdcanx, 0x8000 | id, tdata, sizeof(tdata));
}
2.6 Modo de Corriente DQ
Instrucciones:
- Puede controlar la corriente de fase Q, unidad: 0.1A, p. ej., cur = 10 significa que la corriente de fase Q es 1A.
void motor_control_cur(FDCAN_HandleTypeDef *hfdcanx, uint8_t id, int16_t cur)
{
static uint8_t tdata[7] = {0x01, 0x00, 0x09, 0x05, 0x1c, 0x00, 0x00};
*(int16_t *)&tdata[5] = cur;
can_send(hfdcanx, 0x8000 | id, tdata, sizeof(tdata));
}
2.7 Freno
Instrucciones:
- Frenado del motor, rotar el motor tendrá amortiguación.
/**
* @brief Motor brake
* @param fdcanHandle &hfdcanx
* @param motor id Motor ID
*/
void set_motor_brake(FDCAN_HandleTypeDef *fdcanHandle, uint8_t id)
static uint8_t cmd[] = {0x01, 0x00, 0x0f};
can_send(fdcanHandle, 0x8000 | id, cmd, sizeof(cmd));
}
2.8 Parar
Instrucciones:
- El motor se detiene y pierde la fuerza para mantener la posición.
/**
* @brief Stop the motor. Note: The motor must be stopped before resetting the zero position, otherwise it will be invalid.
* @param fdcanHandle &hfdcanx
* @param motor id Motor ID
*/
void set_motor_stop(FDCAN_HandleTypeDef *fdcanHandle, uint8_t id)
{
static uint8_t cmd[] = {0x01, 0x00, 0x00};
can_send(fdcanHandle, 0x8000 | id, cmd, sizeof(cmd));
}
3. Instrucciones para Tipos Comunes (Unidades)
3.1 Corriente (A)
Tipo de Datos | LSB | Real (A) |
---|---|---|
int8 | 1 | 1 |
int16 | 1 | 0.1 |
int32 | 1 | 0.001 |
float | 1 | 1 |
3.2 Voltaje (V)
Tipo de Datos | LSB | Real (V) |
---|---|---|
int8 | 1 | 0.5 |
int16 | 1 | 0.1 |
int32 | 1 | 0.001 |
float | 1 | 1 |
3.3 Par (Nm)
Par verdadero = k * tqe + d
3.3.1 5046 Par (Nm)
Tipo de Datos | Pendiente (k) | Desplazamiento (d) |
---|---|---|
int16 | 0.005397 | -0.455107 |
int32 | 0.000528 | -0.414526 |
float | 0.533654 | -0.519366 |
3.3.2 4538 Par (Nm)
Tipo de Datos | Pendiente (k) | Desplazamiento (d) |
---|---|---|
int16 | 0.004587 | -0.290788 |
int32 | 0.000445 | -0.234668 |
float | 0.493835 | -0.473398 |
3.3.2 5047/6056 (Bipolar, Relación de Engranajes 36) Par (Nm)
Tipo de Datos | Pendiente (k) | Desplazamiento (d) |
---|---|---|
int16 | 0.004563 | -0.493257 |
int32 | 0.000462 | -0.512253 |
float | 0.465293 | -0.554848 |
3.3.3 5047 (Unipolar, Relación de Engranajes 9) Par (Nm)
Tipo de Datos | Pendiente (k) | Desplazamiento (d) |
---|---|---|
int16 | 0.005332 | -0.072956 |
int32 | 0.000533 | -0.034809 |
float | 0.547474 | -0.150232 |
3.4 Temperatura (℃)
Tipo de Datos | LSB | Real (℃) |
---|---|---|
int8 | 1 | 1 |
int16 | 1 | 0.1 |
int32 | 1 | 0.001 |
float | 1 | 1 |
3.5 Tiempo (s)
Tipo de Datos | LSB | Real (s) |
---|---|---|
int8 | 1 | 0.01 |
int16 | 1 | 0.001 |
int32 | 1 | 0.000001 |
float | 1 | 1 |
3.6 Posición (rotaciones)
Tipo de Datos | LSB | Real (rotaciones) | Real (°) |
---|---|---|---|
int8 | 1 | 0.01 | 3.6 |
int16 | 1 | 0.0001 | 0.036 |
int32 | 1 | 0.00001 | 0.0036 |
float | 1 | 1 | 360 |
3.7 Velocidad (rotaciones/segundo)
Tipo de Datos | LSB | Real (rotaciones/segundo) |
---|---|---|
int8 | 1 | 0.01 |
int16 | 1 | 0.00025 |
int32 | 1 | 0.00001 |
float | 1 | 1 |
3.8 Aceleración (rotaciones/segundo²)
Tipo de Datos | LSB | Real (rotaciones/segundo²) |
---|---|---|
int8 | 1 | 0.05 |
int16 | 1 | 0.001 |
int32 | 1 | 0.00001 |
float | 1 | 1 |
3.9 Escala PWM (sin unidades)
Tipo de Datos | LSB | Real |
---|---|---|
int8 | 1 | 1/127 - 0.007874 |
int16 | 1 | 1/32767 - 0.000030519 |
int32 | 1 | (1/2147483647) - 4.657^10 |
float | 1 | 1 |
3.10 Escala Kp, Kd (sin unidades)
Tipo de Datos | LSB | Real |
---|---|---|
int8 | 1 | 1/127 - 0.007874 |
int16 | 1 | 1/32767 - 0.000030519 |
int32 | 1 | (1/2147483647) - 4.657^10 |
float | 1 | 1 |
Ejemplo en C++
El control en C++ requiere una placa controladora CAN-USB adicional. Por favor consulte livelybot_hardware_sdk

Controlando Motores con reComputer Mini Jetson Orin
Actualmente, las interfaces de comunicación CAN más comúnmente utilizadas para motores en el mercado son los conectores XT30(2+2) y JST. Nuestros dispositivos reComputer Mini Jetson Orin y reComputer Robotics están equipados con puertos XT30(2+2) duales e interfaces CAN basadas en JST, proporcionando compatibilidad perfecta.
reComputer Mini:

reComputer Robotics

Para más detalles sobre el uso de CAN, por favor consulte esta wiki.
Habilitando la Interfaz CAN
Paso 1: Antes de usar CAN0 y CAN1, retire la cubierta inferior y configure ambas resistencias de terminación de 120Ω en la posición ON.

Paso 2: Conecte el motor directamente al CAN0 del reComputer Mini a través de la interfaz XT30(2+2).
Los pines H/L de la interfaz CAN del reComputer Mini son opuestos a los del motor, por lo que las conexiones H/L en el arnés XT30 2+2 necesitan ser invertidas.


Esta solución de alimentación solo es adecuada para aprendizaje y pruebas con un solo motor. Para aplicaciones con múltiples motores, por favor diseñe una placa de alimentación independiente para aislar la fuente de alimentación del Jetson de la fuente de alimentación del motor para evitar que grandes corrientes pasen directamente a través del Jetson.
Habilitando la Comunicación CAN del Jetson
Abra una terminal e ingrese el siguiente comando para poner el pin GPIO en alto para activar CAN0:
gpioset --mode=wait 0 43=0
Si usas el CAN1 de la interfaz JST, pon el pin 106 en alto:
gpioset --mode=wait 0 106=0
Mantén esta terminal abierta y crea una nueva terminal para configurar CAN0:
sudo modprobe mttcan
sudo ip link set can0 type can bitrate 1000000
sudo ip link set can0 up
Control de Python
- Instalar Entorno de Python
pip install python-can numpy
- Crear Directorio de Scripts
mkdir -p ~/hightorque/scripts
- Create hightorque_motor.py File
cd ~/hightorque/scripts
touch hightorque_motor.py
Copia el siguiente código en hightorque_motor.py.
hightorque_motor.py
import can
import numpy as np
from time import sleep
from enum import IntEnum
class MotorType(IntEnum):
"""Motor Type Enum"""
HT5046 = 0 # 5046 Motor
HT4538 = 1 # 4538 Motor
HT5047_36 = 2 # 5047/6056 Dual-pole 36 Reduction Ratio
HT5047_9 = 3 # 5047 Single-pole 9 Reduction Ratio
class ControlMode(IntEnum):
"""Control Mode Enum"""
NORMAL = 0 # Normal Mode
TORQUE = 1 # Torque Mode
COOPERATIVE = 2 # Cooperative Control Mode
class Motor:
def __init__(self, motor_type: MotorType, slave_id: int, master_id: int):
"""
Initialize Motor Object
:param motor_type: Motor Type
:param slave_id: Slave ID
:param master_id: Master ID
"""
self.motor_type = motor_type
self.slave_id = slave_id
self.master_id = master_id
self.position = 0
self.velocity = 0
self.torque = 0
self.temperature = 0
# Set Torque Conversion Parameters Based on Motor Type
if motor_type == MotorType.HT5046:
self.torque_k = 0.005397
self.torque_d = -0.455107
elif motor_type == MotorType.HT4538:
self.torque_k = 0.004587
self.torque_d = -0.290788
elif motor_type == MotorType.HT5047_36:
self.torque_k = 0.004563
self.torque_d = -0.493257
elif motor_type == MotorType.HT5047_9:
self.torque_k = 0.005332
self.torque_d = -0.072956
def update_status(self, position: float, velocity: float, torque: float, temperature: float):
"""Update Motor Status"""
self.position = position
self.velocity = velocity
self.torque = torque
self.temperature = temperature
class MotorControl:
def __init__(self, channel: str, bitrate: int = 1000000):
"""
Initialize Motor Controller
:param channel: CAN Channel
:param bitrate: CAN Baud Rate
"""
self.bus = can.interface.Bus(channel=channel, bustype='socketcan', bitrate=bitrate)
self.motors = {}
def add_motor(self, motor: Motor):
"""Add Motor to Controller"""
self.motors[motor.slave_id] = motor
def __send_data(self, motor_id: int, data: bytes):
"""
Send CAN Data
:param motor_id: Motor ID
:param data: Data to Send
"""
msg = can.Message(
arbitration_id=0x8000 | motor_id,
data=data,
is_extended_id=True
)
self.bus.send(msg)
def enable(self, motor: Motor):
"""Enable Motor"""
data = bytes([0x01, 0x00, 0x01])
self.__send_data(motor.slave_id, data)
sleep(0.1)
def disable(self, motor: Motor):
"""Disable Motor"""
data = bytes([0x01, 0x00, 0x00])
self.__send_data(motor.slave_id, data)
sleep(0.1)
def set_zero_position(self, motor: Motor):
"""Set Motor Zero Position"""
data = bytes([0x40, 0x01, 0x04, 0x64, 0x20, 0x63, 0x0a])
self.__send_data(motor.slave_id, data)
sleep(1.0) # Wait 1 second
self.save_settings(motor)
def save_settings(self, motor: Motor):
"""Save Motor Settings to Flash"""
data = bytes([0x05, 0xb3, 0x02, 0x00, 0x00])
self.__send_data(motor.slave_id, data)
def control_position(self, motor: Motor, position: float, torque: float):
"""
Position Control
:param motor: Motor Object
:param position: Target Position (Unit: 0.0001 turns)
:param torque: Torque Limit
"""
pos_bytes = int(position).to_bytes(2, 'little')
tqe_bytes = int(torque).to_bytes(2, 'little')
data = bytes([0x07, 0x07]) + pos_bytes + bytes([0x80, 0x00]) + tqe_bytes
self.__send_data(motor.slave_id, data)
def control_velocity(self, motor: Motor, velocity: float, torque: float):
"""
Velocity Control
:param motor: Motor Object
:param velocity: Target Velocity (Unit: 0.00025 turns/second)
:param torque: Torque Limit
"""
vel_bytes = int(velocity).to_bytes(2, 'little')
tqe_bytes = int(torque).to_bytes(2, 'little')
data = bytes([0x07, 0x07, 0x00, 0x80]) + vel_bytes + tqe_bytes
self.__send_data(motor.slave_id, data)
def control_torque(self, motor: Motor, torque: float):
"""
Torque Control
:param motor: Motor Object
:param torque: Target Torque
"""
tqe_bytes = int(torque).to_bytes(2, 'little')
data = bytes([0x05, 0x13]) + tqe_bytes
self.__send_data(motor.slave_id, data)
def control_cooperative(self, motor: Motor, position: float, velocity: float, torque: float):
"""
Cooperative Control (Position, Velocity, Torque Simultaneous Control)
:param motor: Motor Object
:param position: Target Position (Unit: 0.0001 turns)
:param velocity: Target Velocity (Unit: 0.00025 turns/second)
:param torque: Torque Limit
"""
vel_bytes = int(velocity).to_bytes(2, 'little')
tqe_bytes = int(torque).to_bytes(2, 'little')
pos_bytes = int(position).to_bytes(2, 'little')
data = bytes([0x07, 0x35]) + vel_bytes + tqe_bytes + pos_bytes
self.__send_data(motor.slave_id, data)
def read_motor_status(self, motor: Motor):
"""Read Motor Status"""
data = bytes([0x17, 0x01])
self.__send_data(motor.slave_id, data)
sleep(0.01) # Wait for Data Reception
# Receive and Parse Data
msg = self.bus.recv(timeout=0.1)
if msg and msg.arbitration_id == (0x8000 | motor.slave_id):
data = msg.data
if len(data) >= 8 and data[0] == 0x27:
position = int.from_bytes(data[2:4], 'little')
velocity = int.from_bytes(data[4:6], 'little')
torque = int.from_bytes(data[6:8], 'little')
motor.update_status(position, velocity, torque, 0)
def periodic_read_status(self, motor: Motor, period_ms: int):
"""
Set Periodic Motor Status Reading
:param motor: Motor Object
:param period_ms: Period (milliseconds)
"""
period_bytes = int(period_ms).to_bytes(2, 'little')
data = bytes([0x05, 0xb4, 0x02, 0x00]) + period_bytes
self.__send_data(motor.slave_id, data)
def close(self):
"""Close CAN Bus"""
self.bus.shutdown()
- Crear archivo hightorque_test.py
Copia el siguiente código en hightorque_test.py.
hightorque_test.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
import math
import numpy as np
from hightorque_motor import Motor, MotorControl, MotorType
# Configuration Parameters
NUM_MOTORS = 2 # Number of Motors to Control
CAN_INTERFACE = "can0" # CAN Interface Name
CAN_BITRATE = 1000000 # CAN Baud Rate
MOTOR_TYPE = MotorType.HT5047_36 # Motor Type
# Sine Wave Parameters
FREQUENCY = 0.1 # Frequency (Hz)
AMPLITUDE = 2500 # Amplitude (0.0001 turns)
OFFSET = 2500 # Offset to Ensure Positive Position
DURATION = 60.0 # Run Duration (s)
def main():
# Create Motor Control Object
controller = MotorControl(channel=CAN_INTERFACE, bitrate=CAN_BITRATE)
try:
# Create and Add Motors
motors = []
for i in range(NUM_MOTORS):
motor = Motor(MOTOR_TYPE, slave_id=i+1, master_id=0)
controller.add_motor(motor)
motors.append(motor)
# Enable Motor
print(f"Enabling Motor {i+1}...")
controller.enable(motor)
time.sleep(1) # Wait for Motor Enable
# Set Zero Position
print(f"Setting Motor {i+1} Zero Position...")
controller.set_zero_position(motor)
time.sleep(1)
# Save Settings to Flash
print(f"Saving Motor {i+1} Settings...")
controller.save_settings(motor)
time.sleep(1)
# Read Initial Status
controller.read_motor_status(motor)
print(f"Motor {i+1} Initial Status:")
print(f"Position: {motor.position * 0.0001:.4f} turns")
print(f"Velocity: {motor.velocity * 0.00025:.4f} turns/second")
print(f"Torque: {motor.torque * motor.torque_k + motor.torque_d:.4f} Nm")
# Start Sine Wave Position Control
print("\nStarting Sine Wave Position Control...")
start_time = time.time()
while time.time() - start_time < DURATION:
current_time = time.time() - start_time
# Calculate Sine Wave Position with Offset to Ensure Positive
position = AMPLITUDE * math.sin(2 * math.pi * FREQUENCY * current_time) + OFFSET
# Control All Motors
for motor in motors:
# Use Position Control Mode with Max Torque of 1000
controller.control_position(motor, position=int(position), torque=1000)
# Control Frequency
time.sleep(0.001) # 1kHz Control Frequency
except KeyboardInterrupt:
print("\nProgram Interrupted by User")
finally:
# Disable All Motors
for motor in motors:
print(f"Disabling Motor {motor.slave_id}...")
controller.disable(motor)
# Close CAN Bus
controller.close()
print("CAN Bus Closed")
if __name__ == "__main__":
main()
- Ejecutar hightorque_test.py
python hightorque_test.py
Soporte Técnico y Discusión de Productos
¡Gracias por elegir nuestros productos! Proporcionamos varios canales de soporte para asegurar que tengas la mejor experiencia.