You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
481 lines
14 KiB
481 lines
14 KiB
6 months ago
|
# RMD-X8 Python Library
|
||
|
# Copyright 2022 Sanjay Sunil
|
||
|
|
||
|
import can
|
||
|
import os
|
||
|
import time
|
||
|
|
||
|
|
||
|
class RMD_X8:
|
||
|
"""
|
||
|
A class to read and write on the RMD-X8 motor.
|
||
|
|
||
|
...
|
||
|
|
||
|
Attributes
|
||
|
----------
|
||
|
bus : type
|
||
|
the can bus channel used to communicate with the motor
|
||
|
identifier : type
|
||
|
the motor's identifier on the can bus
|
||
|
|
||
|
Methods
|
||
|
-------
|
||
|
setup():
|
||
|
Setup the can bus connection.
|
||
|
send_cmd(data, delay):
|
||
|
Send a frame data to the motor.
|
||
|
read_pid():
|
||
|
Read the motor's current PID parameters.
|
||
|
write_pid_ram(data):
|
||
|
Write PID parameters to the RAM.
|
||
|
write_pid_rom(data):
|
||
|
Write PID parameters to the ROM.
|
||
|
read_acceleration():
|
||
|
Read the motor's acceleration data.
|
||
|
write_acceleration_ram(data):
|
||
|
Write the acceleration to the RAM of the motor.
|
||
|
read_encoder():
|
||
|
Read the current position of the encoder.
|
||
|
write_encoder_offset(data):
|
||
|
Set the motor's encoder offset.
|
||
|
write_motor_zero_rom():
|
||
|
Write the current position of the motor to the ROM
|
||
|
as the motor zero position.
|
||
|
read_multi_turns_angle():
|
||
|
Read the multi-turn angle of the motor.
|
||
|
read_single_turn_angle():
|
||
|
Read the single circle angle of the motor.
|
||
|
motor_off():
|
||
|
Turn off the motor, while clearing the motor operating
|
||
|
status and previously received control commands.
|
||
|
motor_stop():
|
||
|
Stop the motor, but do not clear the operating state and
|
||
|
previously received control commands.
|
||
|
motor_running():
|
||
|
Resume motor operation from the motor stop command.
|
||
|
read_motor_status_1():
|
||
|
Reads the motor's error status, voltage, temperature and
|
||
|
other information.
|
||
|
read_motor_status_2():
|
||
|
Reads the motor temperature, voltage, speed and encoder
|
||
|
position.
|
||
|
read_motor_status_3():
|
||
|
Reads the phase current status data of the motor.
|
||
|
clear_motor_error_flag():
|
||
|
Clears the error status of the currrent motor.
|
||
|
torque_closed_loop(data):
|
||
|
Control torque current output of the motor.
|
||
|
speed_closed_loop(data):
|
||
|
Control the speed of the motor.
|
||
|
position_closed_loop_1(data):
|
||
|
Control the position of the motor (multi-turn angle).
|
||
|
position_closed_loop_2(data):
|
||
|
Control the position of the motor (multi-turn angle).
|
||
|
position_closed_loop_3(data):
|
||
|
Control the position of the motor (single-turn angle).
|
||
|
position_closed_loop_4(data):
|
||
|
Control the position of the motor (single-turn angle).
|
||
|
"""
|
||
|
|
||
|
def __init__(self, identifier):
|
||
|
"""
|
||
|
Constructs all the necessary attributes for the RMDX8 object.
|
||
|
"""
|
||
|
self.bus = None
|
||
|
self.identifier = identifier
|
||
|
|
||
|
def setup(self):
|
||
|
"""
|
||
|
Setup the can bus connection.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
self.bus : type
|
||
|
The bus used to communicate with the motor.
|
||
|
"""
|
||
|
try:
|
||
|
os.system("sudo /sbin/ip link set can0 up type can bitrate 1000000")
|
||
|
time.sleep(0.1)
|
||
|
except Exception as e:
|
||
|
print(e)
|
||
|
|
||
|
try:
|
||
|
bus = can.interface.Bus(bustype='socketcan_native', channel='can0')
|
||
|
except OSError:
|
||
|
print('err: PiCAN board was not found.')
|
||
|
exit()
|
||
|
except Exception as e:
|
||
|
print(e)
|
||
|
|
||
|
self.bus = bus
|
||
|
return self.bus
|
||
|
|
||
|
def send_cmd(self, data, delay):
|
||
|
"""
|
||
|
Send frame data to the motor.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
data : list
|
||
|
The frame data to be sent to the motor.
|
||
|
delay : int/float
|
||
|
The time to wait after sending data to the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = can.Message(arbitration_id=self.identifier,
|
||
|
data=data, extended_id=False)
|
||
|
self.bus.send(message)
|
||
|
time.sleep(delay)
|
||
|
received_message = self.bus.recv()
|
||
|
return received_message
|
||
|
|
||
|
def read_pid(self):
|
||
|
"""
|
||
|
Read the motor's current PID parameters.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def write_pid_ram(self, data):
|
||
|
"""
|
||
|
Write PID parameters to the RAM.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
data : list
|
||
|
The frame data to be sent to the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x31, 0x00, data[0], data[1],
|
||
|
data[2], data[3], data[4], data[5]]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def write_pid_rom(self, data):
|
||
|
"""
|
||
|
Write PID parameters to the ROM.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
data : list
|
||
|
The frame data to be sent to the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x32, 0x00, data[0], data[1],
|
||
|
data[2], data[3], data[4], data[5]]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def read_acceleration(self):
|
||
|
"""
|
||
|
Read the motor's acceleration data.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def write_acceleration_ram(self, data):
|
||
|
"""
|
||
|
Write the acceleration to the RAM of the motor.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
data : list
|
||
|
The frame data to be sent to the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x34, 0x00, 0x00, 0x00,
|
||
|
data[0], data[1], data[2], data[3]]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def read_encoder(self):
|
||
|
"""
|
||
|
Read the current position of the encoder.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def write_encoder_offset(self, data):
|
||
|
"""
|
||
|
Set the motor's encoder offset.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
data : list
|
||
|
The frame data to be sent to the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x91, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, data[0], data[1]]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def write_motor_zero_rom(self):
|
||
|
"""
|
||
|
Write the current position of the motor to the ROM as the motor zero position.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x19, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def read_multi_turns_angle(self):
|
||
|
"""
|
||
|
Read the multi-turn angle of the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x92, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def read_single_turn_angle(self):
|
||
|
"""
|
||
|
Read the single circle angle of the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x94, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def motor_off(self):
|
||
|
"""
|
||
|
Turn off the motor, while clearing the motor operating status and previously received control commands.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x80, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def motor_stop(self):
|
||
|
"""
|
||
|
Stop the motor, but do not clear the operating state and previously received control commands.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x81, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def motor_run(self):
|
||
|
"""
|
||
|
Resume motor operation from the motor stop command.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x88, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def read_motor_status_1(self):
|
||
|
"""
|
||
|
Reads the motor's error status, voltage, temperature and other information.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x9A, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def read_motor_status_2(self):
|
||
|
"""
|
||
|
Reads the motor temperature, voltage, speed and encoder position.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x9C, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def read_motor_status_3(self):
|
||
|
"""
|
||
|
Reads the phase current status data of the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x9D, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def clear_motor_error_flag(self):
|
||
|
"""
|
||
|
Clears the error status of the currrent motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0x9B, 0x00, 0x00, 0x00,
|
||
|
0x00, 0x00, 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def torque_closed_loop(self, data):
|
||
|
"""
|
||
|
Control torque current output of the motor.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
data : list
|
||
|
The frame data to be sent to the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0xA1, 0x00, 0x00, 0x00,
|
||
|
data[0], data[1], 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def speed_closed_loop(self, data):
|
||
|
"""
|
||
|
Control the speed of the motor.
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
data : list
|
||
|
The frame data to be sent to the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0xA2, 0x00, 0x00, 0x00,
|
||
|
data[0], data[1], data[2], data[3]]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def position_closed_loop_1(self, data):
|
||
|
"""
|
||
|
Control the position of the motor (multi-turn angle).
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
data : list
|
||
|
The frame data to be sent to the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0xA3, 0x00, 0x00, 0x00,
|
||
|
data[0], data[1], data[2], data[3]]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def position_closed_loop_2(self, data):
|
||
|
"""
|
||
|
Control the position of the motor (multi-turn angle).
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
data : list
|
||
|
The frame data to be sent to the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0xA4, 0x00, data[0], data[1],
|
||
|
data[2], data[3], data[4], data[5]]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def position_closed_loop_3(self, data):
|
||
|
"""
|
||
|
Control the position of the motor (single-turn angle).
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
data : list
|
||
|
The frame data to be sent to the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0xA5, data[0], 0x00, 0x00,
|
||
|
data[1], data[2], 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|
||
|
|
||
|
def position_closed_loop_4(self, data):
|
||
|
"""
|
||
|
Control the position of the motor (single-turn angle).
|
||
|
|
||
|
Parameters
|
||
|
----------
|
||
|
data : list
|
||
|
The frame data to be sent to the motor.
|
||
|
|
||
|
Returns
|
||
|
-------
|
||
|
received_message : list
|
||
|
Frame data received from the motor after receiving the command.
|
||
|
"""
|
||
|
message = [0xA6, data[0], data[1], data[2],
|
||
|
data[3], data[4], 0x00, 0x00]
|
||
|
return self.send_cmd(message, 0.01)
|