#!/usr/bin/env python import rospy import time, datetime from geometry_msgs.msg import Twist from sensor_msgs.msg import Imu, JointState, BatteryState from trajectory_msgs.msg import JointTrajectoryPoint from pyrr import Quaternion from scipy.spatial.transform import Rotation class LogWriter(): def __init__(self) -> None: rospy.init_node("log_writer") self.rate = rospy.Rate(0.1) # подпишемся на интересующие нас топики rospy.Subscriber("cmd_vel", Twist, self.cmd_vel_callback, queue_size=10) rospy.Subscriber("cmd_pose", Twist, self.cmd_pose_callback, queue_size=10) rospy.Subscriber("joint_states", JointState, self.cur_joint_pos_callback, queue_size=1) rospy.Subscriber("lcm/servo_cmd", JointTrajectoryPoint, self.ref_joint_pos_callback, queue_size=1) rospy.Subscriber("imu/data", Imu, self.imu_callback, queue_size=1) rospy.Subscriber("bat", BatteryState, self.battery_callback, queue_size=1) # создадим сообщения для подписанных топиков self.cmd_vel_msg = Twist() self.cmd_pose_msg = Twist() self.cur_joints_msg = JointState() self.ref_joints_msg = JointTrajectoryPoint() self.imu_msg = Imu() self.bat_msg = BatteryState() # создадим файл для записи логов filename = f"log_{datetime.datetime.now().strftime('%Y%m%d-%H%M%S')}.csv" self.file = open(f"/home/user/mors_ws/src/mors_base/log_writer/logs/{filename}", 'w') # добавим в таблицу заголовки нужных колонок line = "datetime, t, \ voltage, cmd_vel[X], cmd_vel[Y], cmd_vel[Z], \ cmd_pose_linear[X], cmd_pose_linear[Y], cmd_pose_linear[Z], cmd_pose_angular[X], cmd_pose_angular[Y], cmd_pose_angular[Z],\ cur_joint[0], cur_joint[1], cur_joint[2], cur_joint[3], cur_joint[4], cur_joint[5], \ cur_joint[6], cur_joint[7], cur_joint[8], cur_joint[9], cur_joint[10], cur_joint[11], \ ref_joint[0], ref_joint[1], ref_joint[2], ref_joint[3], ref_joint[4], ref_joint[5], \ ref_joint[6], ref_joint[7], ref_joint[8], ref_joint[9], ref_joint[10], ref_joint[11], \ roll, pitch, yaw" self.file.write(line + '\n') rospy.loginfo("log_writer started") def loop(self): start_t = time.time() while not rospy.is_shutdown(): # определим текущее время now = time.time() t = int(now - start_t)+1 cur_joint_str = "" ref_joint_str = "" # обработаем данные о сервоприводах for i in range(12): if len(self.cur_joints_msg.position) >= 12: cur_joint_str += f"{self.cur_joints_msg.position[i]}, " #f"1, "# else: cur_joint_str += f"0, " if len(self.ref_joints_msg.positions) >= 12: ref_joint_str += f"{self.ref_joints_msg.positions[i]}, " #f"2, "# else: ref_joint_str += "0, " # обработаем данные с IMU quat_df = [self.imu_msg.orientation.x, self.imu_msg.orientation.y, self.imu_msg.orientation.z, self.imu_msg.orientation.w] if quat_df[3] != 0: quat = Quaternion(quat_df).inverse rot = Rotation.from_quat(quat) rot_euler = rot.as_euler('xyz', degrees=False) else: rot_euler = [0, 0, 0] voltage = self.bat_msg.voltage # запишем в одну строку все данные полученные с колбэков line = f"{now}, {t}, \ {voltage}\ {self.cmd_vel_msg.linear.x}, {self.cmd_vel_msg.linear.y}, {self.cmd_vel_msg.angular.z}, \ {self.cmd_pose_msg.linear.x}, {self.cmd_pose_msg.linear.y}, {self.cmd_pose_msg.linear.z}, \ {self.cmd_pose_msg.angular.x}, {self.cmd_pose_msg.angular.y}, {self.cmd_pose_msg.angular.z}, \ {cur_joint_str}{ref_joint_str}\ {rot_euler[0]}, {rot_euler[0]}, {rot_euler[0]}\ \n" # запишем строку в файл self.file.write(line) self.rate.sleep() # колбэки на топики, на которые мы подписались def battery_callback(self, msg : BatteryState): self.bat_msg = msg def cmd_vel_callback(self, msg : Twist): self.cmd_vel_msg = msg def cmd_pose_callback(self, msg : Twist): self.cmd_pose_msg = msg def cur_joint_pos_callback(self, msg : JointState): self.cur_joints_msg = msg def ref_joint_pos_callback(self, msg : JointTrajectoryPoint): self.ref_joints_msg = msg def imu_callback(self, msg : Imu): self.imu_msg = msg def main(): lw = LogWriter() lw.loop() if __name__ == '__main__': main()