MassageRobot_Dobot/UI_next/force_sensor_aubo.py

367 lines
14 KiB
Python
Executable File

import struct
import serial
import numpy as np
import atexit
import time
import subprocess
import psutil
import sys
# sys.path.append("/home/jsfb/jsfb_ws/MassageRobot_Dobot/Massage/MassageControl")
from tools.ssh_tools import execute_command_on_remote
from tools.serial_tools import start_virtual_serial,stop_virtual_serial
class XjcSensor:
def __init__(self, port="/tmp/ttyRobotTool", baudrate=115200, arm_ip='192.168.100.20', rate=250):
self.port = port
self.baudrate = baudrate
self.rate = rate
# 远程服务器信息
self.arm_ip = arm_ip
self.crc16_table = self.generate_crc16_table()
self.slave_adress = 0x01
self.ser = None
try:
self.connect()
atexit.register(self.disconnect)
except KeyboardInterrupt:
print("Process interrupted by user")
self.disconnect()
def __new__(cls, *args, **kwargs):
"""
Making this class singleton
"""
if not hasattr(cls, 'instance'):
cls.instance = super(XjcSensor, cls).__new__(cls)
return cls.instance
def connect(self):
username = 'root'
password = 'bestcobot'
ssh_port = 8822
# 启动ser2net服务
# stop_command = 'systemctl stop ser2net'
# output, error = execute_command_on_remote(self.arm_ip, username, password, stop_command, ssh_port)
start_command = 'systemctl restart ser2net'
output, error = execute_command_on_remote(self.arm_ip, username, password, start_command, ssh_port)
print('start ser2net')
# 在本地后台启动socat命令
# subprocess.call(['pkill', '-f', 'socat'])
# socat_command = f'socat PTY,raw,echo=0,link=/tmp/ttyRobotTool TCP:{self.arm_ip}:5000'
# self.socat_process = subprocess.Popen(socat_command, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
# print('socat process started')
stop_virtual_serial(self.port)
start_virtual_serial(self.arm_ip,5000,self.port)
time.sleep(0.1)
self.ser = serial.Serial(self.port, self.baudrate,timeout=0.1)
@staticmethod
def generate_crc16_table():
table = []
polynomial = 0xA001
for i in range(256):
crc = i
for _ in range(8):
if crc & 0x0001:
crc = (crc >> 1) ^ polynomial
else:
crc >>= 1
table.append(crc)
return table
def crc16(self,data: bytes):
crc = 0xFFFF
for byte in data:
crc = (crc >> 8) ^ self.crc16_table[(crc ^ byte) & 0xFF]
return (crc >> 8) & 0xFF, crc & 0xFF
def set_zero(self):
"""
传感器置零,重新上电之后需要置零
"""
try:
# 重置输入输出缓冲区
self.ser.reset_input_buffer()
self.ser.reset_output_buffer()
# 清除串口缓冲区中的数据
if self.ser.in_waiting > 0:
self.ser.read(self.ser.in_waiting)
# 根据地址设置置零命令
if self.slave_adress == 0x01:
zero_cmd = bytes.fromhex('01 10 46 1C 00 02 04 00 00 00 00 E8 95') # 传感器内置通信协议--清零传感器数据
elif self.slave_adress == 0x09:
zero_cmd = bytes.fromhex('09 10 46 1C 00 02 04 00 00 00 00 C2 F5')
# 发送置零命令
self.ser.write(zero_cmd)
response = bytearray(self.ser.read(8))
print(f"set zero response: {response}")
# CRC 校验
Hi_check, Lo_check = self.crc16(response[:-2])
if response[0] != self.slave_adress or response[1] != 0x10 or \
response[-1] != Hi_check or response[-2] != Lo_check:
print("set zero failed!")
return -1
print("set zero success!")
return 0
except serial.SerialException as e:
print(f"Serial communication error: {e}")
print(f"Details - Address: {self.slave_adress}, Port: {self.ser.port}")
return -1
except Exception as e:
print(f"Unexpected error: {e}")
return -1
# 可能比较慢
def read_data_f32(self):
self.ser.reset_input_buffer() # 清除输入缓冲区
self.ser.reset_output_buffer() # 清除输出缓冲区
if self.ser.in_waiting > 0:
self.ser.read(self.ser.in_waiting)
if self.slave_adress == 0x01:
# command = bytes.fromhex('01 04 00 54 00 0C B1 DF') # (旧版)传感器内置通信协议--读取一次六维力数据
command = bytes.fromhex('01 04 00 00 00 0C F0 0F') # (新版)传感器内置通信协议--读取一次六维力数据
elif self.slave_adress == 0x09:
command = bytes.fromhex('09 04 00 54 00 0C B0 97') # 传感器内置通信协议--读取一次六维力数据
try:
self.ser.write(command)
response = bytearray(self.ser.read(29))
print(response)
Hi_check, Lo_check = self.crc16(response[:-2])
if response[0] != self.slave_adress or response[1] != 0x04 or \
response[-1] != Hi_check or response[-2] != Lo_check or response[2] != 24:
print("read data failed!")
return -1
sensor_data = struct.unpack('>ffffff', response[3:27])
except serial.SerialException as e:
print(f"Serial communication error: {e}")
return -1
except Exception as e:
print(f"Unexpected error: {e}")
return -1
return np.array(sensor_data)
# def read_data_once(self):
# if self.ser.in_waiting > 0:
# self.ser.read(self.ser.in_waiting)
# if self.slave_adress == 0x01:
# command = bytes.fromhex('01 04 00 54 00 0C B1 DF') # 传感器内置通信协议--读取一次六维力数据
# elif self.slave_adress == 0x09:
# command = bytes.fromhex('09 04 00 54 00 0C B0 97') # 传感器内置通信协议--读取一次六维力数据
# try:
# self.ser.write(command)
# total_bytes = 29 # 单个数据包大小
# allowed_time_error = 0.02 # 允许的误差时间
# cache = self.ser.inWaiting() # 获f取缓存区数据
# # print(f"cache:{cache}")
# if cache > self.rate * total_bytes * allowed_time_error:
# self.ser.read(cache)
# while True:
# if int.from_bytes(self.ser.read(1), byteorder='big') == 0x01:
# if int.from_bytes(self.ser.read(1), byteorder='big') == 0x04:
# if int.from_bytes(self.ser.read(1), byteorder='big') == 0x18:
# # print("This is Header")
# break
# response = bytearray([0x01, 0x04, 0x18]) # 使用bytearray创建16进制数据的列表
# out = self.ser.read(24)
# response.extend(out) # 读取24个字节的数据并添加到列表中
# # print(f"response:{out}")
# sensor_data = self.parse_data_active(response)
# except serial.SerialException as e:
# print(f"Serial communication error: {e}")
# return None
# return sensor_data
def enable_active_transmission(self):
"""
Activate the sensor's active transmission mode
"""
try:
# 根据不同的速率设置命令
if self.rate == 100:
if self.slave_adress == 0x01:
rate_cmd = bytes.fromhex('01 10 01 9A 00 01 02 00 00 AB 6A') # 传感器内置通信协议--100Hz
elif self.slave_adress == 0x09:
rate_cmd = bytes.fromhex('09 10 01 9A 00 01 02 00 00 CC AA')
print("Set mode in 100Hz")
elif self.rate == 250:
if self.slave_adress == 0x01:
rate_cmd = bytes.fromhex('01 10 01 9A 00 01 02 00 01 6A AA')
elif self.slave_adress == 0x09:
rate_cmd = bytes.fromhex('09 10 01 9A 00 01 02 00 01 0D 6A')
print("Set mode in 250Hz")
elif self.rate == 500:
if self.slave_adress == 0x01:
rate_cmd = bytes.fromhex('01 10 01 9A 00 01 02 00 02 2A AB') # 传感器内置通信协议--500Hz
elif self.slave_adress == 0x09:
rate_cmd = bytes.fromhex('09 10 01 9A 00 01 02 00 02 4D 6B')
print("Set mode in 500Hz")
else:
print("Rate not supported")
return
# 检查串口是否打开
if not self.ser.is_open:
raise serial.SerialException("Serial port is not open")
# 重置输入缓冲区
self.ser.reset_input_buffer()
# 写入指令
self.ser.write(rate_cmd)
print("Transmission command sent successfully")
return 0
except serial.SerialException as e:
print(f"Serial communication error: {e}")
print(f"Details - Rate: {self.rate}, Address: {self.slave_adress}, Port: {self.ser.port}")
return -1
except Exception as e:
print(f"Unexpected error: {e}")
return -1
def disable_active_transmission(self):
"""
Disable the sensor's active transmission mode
"""
try:
# 禁用传感器活动传输模式的命令
rate_cmd = bytes.fromhex('FF FF FF FF FF FF FF FF FF FF FF')
print("Disable the sensor's active transmission mode")
# 重置输入缓冲区
if not self.ser.is_open:
raise serial.SerialException("Serial port is not open")
self.ser.reset_input_buffer()
# 发送禁用传输模式的命令
self.ser.write(rate_cmd)
print("Transmission disabled successfully")
return 0
except serial.SerialException as e:
print(f"Serial communication error: {e}")
print(f"Details - Port: {self.ser.port}")
return -1
except Exception as e:
print(f"Unexpected error: {e}")
return -1
def read(self):
"""
Read the sensor's data.
"""
try:
if self.ser.in_waiting > 0:
self.ser.read(self.ser.in_waiting)
while True:
if int.from_bytes(self.ser.read(1), byteorder='big') == 0x20:
if int.from_bytes(self.ser.read(1), byteorder='big') == 0x4E:
break
response = bytearray([0x20, 0x4E]) # 使用bytearray创建16进制数据的列表
response.extend(self.ser.read(14)) # 读取12个字节的数据并添加到列表中
Hi_check, Lo_check = self.crc16(response[:-2])
if response[-1] != Hi_check or response[-2] != Lo_check:
print("check failed!")
return None
sensor_data = self.parse_data_passive(response)
return sensor_data
except serial.SerialException as e:
print(f"Serial communication error: {e}")
return None
def parse_data_passive(self, buffer):
values = [
int.from_bytes(buffer[i:i+2], byteorder='little', signed=True)
for i in range(2, 14, 2)
]
Fx, Fy, Fz = np.array(values[:3]) / 10.0
Mx, My, Mz = np.array(values[3:]) / 1000.0
return np.array([Fx, Fy, Fz, Mx, My, Mz])
def disconnect(self):
"""
Deactivate the sensor's active transmission mode and stop related services.
"""
try:
# 关闭串口通信
if hasattr(self, 'ser') and self.ser.is_open:
send_str = "FF " * 50
send_str = send_str[:-1]
rate_cmd = bytes.fromhex(send_str)
self.ser.write(rate_cmd)
self.ser.close()
except serial.SerialException as e:
print(f"Serial communication error: {e}")
# 停止本地的socat进程
stop_virtual_serial(self.port)
# if self.socat_process:
# # 通过 pkill 杀死所有 socat 进程
# subprocess.call(['pkill', '-f', 'socat'])
# print('socat processes terminated')
# 停止远程的ser2net服务
if hasattr(self, 'arm_ip'):
stop_command = 'systemctl stop ser2net'
output, error = execute_command_on_remote(self.arm_ip, 'root', 'bestcobot', stop_command, 8822)
print('stop ser2net')
def __del__(self):
self.disconnect()
if __name__ == "__main__":
import sys
import pathlib
sys.path.append(str(pathlib.Path(__file__).parent.parent))
# from tools.Rate import Rate
import signal
import sys
# rate = Rate(20)
xjc_sensor = XjcSensor()
def signal_handler(sig, frame):
print('Received Ctrl+C, exiting gracefully...')
sys.exit(0)
signal.signal(signal.SIGINT, lambda signum, frame: sys.exit(0))
# atexit.register(xjc_sensor.disconnect)
time.sleep(1)
xjc_sensor.disable_active_transmission()
xjc_sensor.disable_active_transmission()
xjc_sensor.disable_active_transmission()
print(xjc_sensor.read_data_f32())
print(xjc_sensor.read_data_f32())
print(xjc_sensor.read_data_f32())
# print(xjc_sensor.read())
time.sleep(1)
xjc_sensor.set_zero()
xjc_sensor.set_zero()
xjc_sensor.set_zero()
time.sleep(1)
# xjc_sensor.enable_active_transmission()
# while True:
# sensor_data = xjc_sensor.read()
# #sensor_data = xjc_sensor.read_data_f32()
# if sensor_data is None:
# print('failed to get force sensor data!')
# print(sensor_data)
# rate.sleep(False)
# # break