Primeiros Passos com Motores Stackforce Série X
Este artigo apresentará como começar a usar os motores da série Stackforce e como utilizá-los com C++ e Python no reComputer Jetson Super.

Especificações
Aqui está a tabela completa com todos os parâmetros preenchidos para todos os modelos de motor:
| Parâmetro | 6010 | 8108 |
|---|---|---|
| Tensão Nominal | 24V | 24V |
| Corrente Nominal | 10.5A | 7.5A |
| Potência Nominal | 240W | 180W |
| Torque Nominal | 5 Nm | 7.5 Nm |
| Torque de Pico | 11 Nm | 22 Nm |
| Velocidade Nominal | 120 RPM | 110 RPM |
| Velocidade Máxima | 270 RPM | 320 RPM |
| Taxa de Engrenagem | 8:1 | 8:1 |
| Protocolo de Comunicação | MIT Protocol | MIT Protocol |
| Modos de Controle | Controle de Posição, Velocidade, Torque | Controle de Posição, Velocidade, Torque |
| Diâmetro Externo | 80 mm | 97 mm |
| Espessura | 47 mm | 46 mm |
| Peso | 392 g ±10% | 395 g ±5% |
| Resistência de Fase | 0.48 Ω ±10% | 0.439 Ω ±10% |
| Indutância de Fase | 368 μH ±10% | 403 μH ±10% |
Principais Recursos
- Alto Torque de Saída
- Controle em Modo MIT
- Realimentação por Encoder Magnético
- Design Compacto e Leve
- Suporte para Comunicação CAN Bus de Alta Velocidade
- Aplicações Versáteis
Guia de Introdução
Preparações Antes do Uso
Em um PC com Sistema Windows
- Manual do Produto.
- Baixe o VOFA.
O CANID e o CANMode do motor são ambos modificados via porta serial. O motor é enviado com um CANID padrão de 0x01 e CANMode de CAN2.0 a 1Mbps.
Fiação da Porta Serial
Conecte V, G, T, R respectivamente ao VCC (3.3V), GND, RX, TX do módulo de comunicação serial (RX e TX devem ser conectados cruzados). Como mostrado na figura abaixo:

Modificando o CANID
Defina a taxa de baud da porta serial para 1Mbps.

O CANID a ser enviado é 0x**, e o ID definido é 0x**, com um limite máximo de 0x7F. Após definir o CANID com sucesso, o seguinte log será impresso:

Você pode definir o CANID:0x01 para facilitar o teste no código subsequente.
Modificando o Modo CAN
Envie CANMODE:0 ou CANMODE:1 via porta serial.
CANMODE:0 representa o modo CAN2.0 (1Mbps), enquanto CANMODE:1 representa o modo CANFD (5Mbps).
A modificação bem-sucedida do modo CAN é mostrada nas figuras abaixo:


Você pode definir o CANMODE:0 para facilitar o teste no código subsequente.
Usando o reComputer Mini Jetson Orin para Controlar Motores
As interfaces de comunicação CAN mais comuns para motores no mercado são XT30 (2+2) e conectores JST. Nossos dispositivos reComputer Mini Jetson Orin e reComputer Robotics são equipados com interfaces XT30 (2+2) duplas e interfaces CAN baseadas em JST, proporcionando compatibilidade perfeita.
reComputer Mini:

reComputer Robotics

Para informações mais detalhadas sobre o uso do CAN, consulte este wiki.
Habilitando a Interface CAN
Etapa 1: Antes de usar CAN0 e CAN1, remova a tampa inferior e defina os dois resistores terminais de 120Ω para a posição ON.

Desligue a chave seletora do resistor terminal de comunicação CAN de 120Ω integrado no motor.

Se o Recomputer Mini não tiver definido o resistor terminal de 120Ω para ON, você pode optar por ligar a chave seletora do resistor terminal de comunicação CAN do motor.
Etapa 2: Conecte o motor diretamente ao CAN0 do reComputer Mini por meio da interface XT30 (2+2).


Como o design da interface CAN do reComputer Mini é oposto ao da interface CAN do motor, é necessária soldagem manual para inverter as linhas de dados.



Considerando a alta tensão e corrente exigidas pelo motor, recomenda-se comprar um adaptador de energia de 24V 300W para alimentar o reComputer Mini para acionar um único motor. Se for necessário conectar mais motores, pode-se adquirir um adaptador de energia de maior potência de acordo com a necessidade.

Esta fonte de alimentação é apenas para aprendizagem e teste com um único motor. Para múltiplos motores, projete uma placa de alimentação separada e isole a alimentação do Jetson da alimentação do motor para evitar que uma corrente alta passe diretamente pelo Jetson.
Habilitando a Comunicação CAN do Jetson
Abra um terminal e insira o seguinte comando para puxar o pino GPIO para nível alto e ativar o CAN0:
gpioset --mode=wait 0 43=0
Se estiver usando o CAN1 com a interface JST, puxe o pino 106 para nível alto.
gpioset --mode=wait 0 106=0
Mantenha este terminal aberto, inicie um novo terminal e configure o CAN0.
sudo modprobe mttcan
sudo ip link set can0 type can bitrate 1000000
sudo ip link set can0 up
Configurando o Ambiente C++ e Python
Etapa 1: Clone o SDK.
git clone https://github.com/Seeed-Projects/Stackforce-Motor-SDK.git
Etapa 2: O SDK do driver requer as seguintes dependências. Para Debian Linux, elas podem ser instaladas com os seguintes comandos:
sudo apt-get install -y build-essential cmake
sudo apt install linux-modules-extra-5.15.0-1025-nvidia-tegra # For Jetson Jetpack 6.0
Se forem necessárias ligações Python, instale adicionalmente Python 3, pip e pybind11:
sudo apt-get install -y python3 python3-pip python3-pybind11 python3-setuptools
Após instalar as dependências, siga as etapas abaixo para instalar o SDK do driver como uma biblioteca C++ ou um pacote Python. Ambos usarão CMake para compilar o código C++.
Controle de Motor e Recebimento de Dados
C++
main.cpp
#include <chrono>
#include <cstdint>
#include <cmath>
#include <cstdio>
#include <thread>
#include "CAN_comm.h"
#include "config.h"
MIT devicesState[4];
uint32_t sendNum; // for testing send speed
uint32_t recNum;
MIT MITCtrlParam;
uint16_t sendCounter = 0;
bool motorEnable = true;
int receivedNumber = 0;
uint64_t prev_ts = 0;
float t = 0.0f;
float targetJointAngle = 0.0f; // Target joint angle (can be modified at runtime via input)
namespace {
uint64_t micros_steady(){
using namespace std::chrono;
return duration_cast<microseconds>(steady_clock::now().time_since_epoch()).count();
}
}
void setup() {
std::printf("SF Motor Control (Jetson) start\n");
CANInit();
enable(0x01); // Enable motor with ID 0x01 <- Change ID to control different motors
prev_ts = micros_steady();
t = 0.0f;
}
uint16_t printCount = 0;
uint16_t recCount = 0;
void loop() {
recCANMessage();
// Check for new joint angle input
// (Check once every 1000 loops to avoid frequent blocking input calls)
static uint16_t inputCheckCount = 0;
if(++inputCheckCount >= 1000){
inputCheckCount = 0;
float newAngle;
if(std::scanf("%f", &newAngle) == 1){
targetJointAngle = newAngle;
std::printf("Target joint angle updated: %.3f rad\n", newAngle);
}
}
static int IDswitch = 0x01; // <- Change ID to control different motors
uint64_t current_ts = micros_steady();
/*
* Function:
* Update control parameters based on time difference and send MIT command.
*
* Parameters:
* - current_ts: current timestamp
* - prev_ts : previous timestamp
* - t : time variable used for sine/cosine calculations
* - MITCtrlParam:
* Control parameter structure including position, velocity,
* position gain (Kp), velocity gain (Kd), and torque
* - IDswitch : motor ID selector
*
* Return:
* None
*/
if(current_ts - prev_ts >= 1000){ // 1 ms control period
// Update time variable (increase by 1 ms)
t += 0.001;
// Set control parameters:
// target position, target velocity, position gain, velocity gain, and torque
MITCtrlParam.pos = targetJointAngle;
MITCtrlParam.vel = 0;
MITCtrlParam.kp = 0.5;
MITCtrlParam.kd = 0.3;
MITCtrlParam.tor = 0;
// Update previous timestamp
prev_ts = current_ts;
// IDswitch++;
// If IDswitch exceeds 0x04, reset it to 0x01
// if(IDswitch > 0x04){
// IDswitch = 0x01;
// }
sendMITCommand(IDswitch, MITCtrlParam); // Send MIT command
printCount++;
if(printCount >= 100){
printCount = 0;
// Only print when IDswitch is 0x01
// Print commanded position/velocity and actual motor position/velocity
if(IDswitch == 0x01){
std::printf( "[CMD] pos: %6.3f rad vel: %6.3f rad/s | " "[FB] pos: %6.3f rad vel: %6.3f rad/s\n", MITCtrlParam.pos, MITCtrlParam.vel, devicesState[IDswitch - 1].pos, devicesState[IDswitch - 1].vel );
}
}
}
std::this_thread::sleep_for(std::chrono::milliseconds(1));
}
int main(){
setup();
while(true){
loop();
}
disable(0x01); // Disable motor with ID 0x01
return 0;
}
cd build
cmake ..
make
O executável compilado estará localizado em build/sfmotor_control. Execute o programa:
./sfmotor_control
O programa, por padrão, controla o motor com ID 0x01. Durante a operação, você pode inserir o valor do ângulo alvo (em radianos) pelo teclado. Ele também recebe dados de retorno sobre o ângulo e a velocidade angular do motor.
Python
main.py
import sys
import time
import select
# Import core control module (assumes sf_can_controller.py is in the same directory)
from sf_can_controller import MotorController
# --- Core Configuration ---
IFACE = "can0"
MOTOR_ID = 1 # <- Change ID to control different motors
UPDATE_RATE_HZ = 100.0
PRINT_EVERY = 2
INITIAL_TARGET_DEG = 0.0
# --- Main Control Loop ---
def run_simple_test() -> None:
"""Run a simplified position control loop."""
# 1. Initialization
update_period = 1.0 / UPDATE_RATE_HZ
target_rad = INITIAL_TARGET_DEG
KP, KD = 0.5, 0.3 # Default MIT parameters
controller = MotorController(interface=IFACE, motor_id=MOTOR_ID)
print(f"--- SF Motor Test Start ---")
print(f"Interface: {IFACE}, ID: {MOTOR_ID}, Rate: {UPDATE_RATE_HZ} Hz")
# 2. Enable motor
controller.enable()
last_send_time = time.perf_counter()
print_counter = 0
inputCheckCount = 0
# 3. Main loop
while True:
controller.poll_rx()
current_state = controller.get_motor_state()
now = time.perf_counter()
# --- Periodic input check (every 500 loops) ---
inputCheckCount += 1
if inputCheckCount >= 500:
inputCheckCount = 0
# Blocking I/O waiting for user input (this will pause the control loop)
# Note: If the input is not a number, a ValueError will be raised.
line = input("Please enter target joint angle: ").strip()
if line:
angle_deg = float(line)
target_rad = angle_deg
print(f"Target joint angle updated: {angle_deg:.3f} deg")
# Periodically send MIT command
if now - last_send_time >= update_period:
last_send_time = now
# Send target position command
controller.send_mit_command(
pos=target_rad,
vel=0.0,
kp=KP,
kd=KD,
tor=0.0
)
# Print motor state
print_counter += 1
if print_counter >= PRINT_EVERY:
print_counter = 0
print(
f"Cmd={target_rad:.2f} | "
f"Pos={current_state.pos:.2f} (Vel={current_state.vel:.2f})"
)
time.sleep(0.001)
if __name__ == "__main__":
# Run test
run_simple_test()
O script Python está localizado no diretório script/ e pode ser executado diretamente, sem compilação.
python main.py
O programa, por padrão, controla o motor com ID 0x01. Durante a operação, você pode inserir o valor do ângulo alvo (em radianos) pelo teclado. Ele também recebe dados de retorno sobre o ângulo e a velocidade angular do motor.
Citação
Suporte Técnico e Discussão de Produto
Obrigado por escolher nossos produtos! Estamos aqui para oferecer diferentes formas de suporte para garantir que sua experiência com nossos produtos seja a mais tranquila possível. Oferecemos vários canais de comunicação para atender a diferentes preferências e necessidades.