初步完成ROS服务程序工作
This commit is contained in:
parent
4d34c200dc
commit
b645464b0b
24
src/Service/CMakeLists.txt
Normal file
24
src/Service/CMakeLists.txt
Normal file
@ -0,0 +1,24 @@
|
||||
cmake_minimum_required(VERSION 3.0.2)
|
||||
project(Service)
|
||||
|
||||
find_package(catkin REQUIRED COMPONENTS
|
||||
rospy
|
||||
std_msgs
|
||||
geometry_msgs
|
||||
visualization_msgs
|
||||
message_generation
|
||||
)
|
||||
|
||||
add_service_files(
|
||||
FILES
|
||||
FFT.srv
|
||||
)
|
||||
|
||||
generate_messages(
|
||||
DEPENDENCIES
|
||||
std_msgs
|
||||
)
|
||||
|
||||
catkin_package(
|
||||
CATKIN_DEPENDS message_runtime std_msgs geometry_msgs visualization_msgs
|
||||
)
|
79
src/Service/package.xml
Normal file
79
src/Service/package.xml
Normal file
@ -0,0 +1,79 @@
|
||||
<?xml version="1.0"?>
|
||||
<package format="2">
|
||||
<name>Service</name>
|
||||
<version>0.0.0</version>
|
||||
<description>The Service package</description>
|
||||
|
||||
<!-- One maintainer tag required, multiple allowed, one person per tag -->
|
||||
<!-- Example: -->
|
||||
<!-- <maintainer email="jane.doe@example.com">Jane Doe</maintainer> -->
|
||||
<maintainer email="root@todo.todo">root</maintainer>
|
||||
|
||||
|
||||
<!-- One license tag required, multiple allowed, one license per tag -->
|
||||
<!-- Commonly used license strings: -->
|
||||
<!-- BSD, MIT, Boost Software License, GPLv2, GPLv3, LGPLv2.1, LGPLv3 -->
|
||||
<license>TODO</license>
|
||||
|
||||
|
||||
<!-- Url tags are optional, but multiple are allowed, one per tag -->
|
||||
<!-- Optional attribute type can be: website, bugtracker, or repository -->
|
||||
<!-- Example: -->
|
||||
<!-- <url type="website">http://wiki.ros.org/Service</url> -->
|
||||
|
||||
|
||||
<!-- Author tags are optional, multiple are allowed, one per tag -->
|
||||
<!-- Authors do not have to be maintainers, but could be -->
|
||||
<!-- Example: -->
|
||||
<!-- <author email="jane.doe@example.com">Jane Doe</author> -->
|
||||
|
||||
|
||||
<!-- The *depend tags are used to specify dependencies -->
|
||||
<!-- Dependencies can be catkin packages or system dependencies -->
|
||||
<!-- Examples: -->
|
||||
<!-- Use depend as a shortcut for packages that are both build and exec dependencies -->
|
||||
<!-- <depend>roscpp</depend> -->
|
||||
<!-- Note that this is equivalent to the following: -->
|
||||
<!-- <build_depend>roscpp</build_depend> -->
|
||||
<!-- <exec_depend>roscpp</exec_depend> -->
|
||||
<!-- Use build_depend for packages you need at compile time: -->
|
||||
<!-- <build_depend>message_generation</build_depend> -->
|
||||
<!-- Use build_export_depend for packages you need in order to build against this package: -->
|
||||
<!-- <build_export_depend>message_generation</build_export_depend> -->
|
||||
<!-- Use buildtool_depend for build tool packages: -->
|
||||
<!-- <buildtool_depend>catkin</buildtool_depend> -->
|
||||
<!-- Use exec_depend for packages you need at runtime: -->
|
||||
<!-- <exec_depend>message_runtime</exec_depend> -->
|
||||
<!-- Use test_depend for packages you need only for testing: -->
|
||||
<!-- <test_depend>gtest</test_depend> -->
|
||||
<!-- Use doc_depend for packages you need only for building documentation: -->
|
||||
<!-- <doc_depend>doxygen</doc_depend> -->
|
||||
<buildtool_depend>catkin</buildtool_depend>
|
||||
<build_depend>geometry_msgs</build_depend>
|
||||
<build_depend>message_generation</build_depend>
|
||||
<build_depend>rospy</build_depend>
|
||||
<build_depend>std_msgs</build_depend>
|
||||
<build_depend>visualization_msgs</build_depend>
|
||||
<build_depend>message_generation</build_depend>
|
||||
|
||||
<build_export_depend>geometry_msgs</build_export_depend>
|
||||
<build_export_depend>rospy</build_export_depend>
|
||||
<build_export_depend>std_msgs</build_export_depend>
|
||||
<build_export_depend>visualization_msgs</build_export_depend>
|
||||
<build_export_depend>message_runtime</build_export_depend>
|
||||
|
||||
<exec_depend>geometry_msgs</exec_depend>
|
||||
<exec_depend>rospy</exec_depend>
|
||||
<exec_depend>std_msgs</exec_depend>
|
||||
<exec_depend>visualization_msgs</exec_depend>
|
||||
<exec_depend>message_runtime</exec_depend>
|
||||
<exec_depend>geometry_msgs</exec_depend>
|
||||
<exec_depend>visualization_msgs</exec_depend>
|
||||
|
||||
|
||||
<!-- The export tag contains other, unspecified, tags -->
|
||||
<export>
|
||||
<!-- Other tools can request additional information be placed here -->
|
||||
|
||||
</export>
|
||||
</package>
|
27
src/Service/scripts/Publisher_S.py
Normal file
27
src/Service/scripts/Publisher_S.py
Normal file
@ -0,0 +1,27 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import rospy
|
||||
import math
|
||||
from geometry_msgs.msg import PointStamped
|
||||
|
||||
def main():
|
||||
rospy.init_node('Publisher_S')
|
||||
pub = rospy.Publisher('position', PointStamped, queue_size=10) # 向 position 话题发布 PointStamped 类型的消息
|
||||
rate = rospy.Rate(10) # 每 0.1s 一条信息
|
||||
|
||||
k = 0
|
||||
|
||||
while not rospy.is_shutdown():
|
||||
msg = PointStamped()
|
||||
msg.header.stamp = rospy.Time.now()
|
||||
msg.header.frame_id = "map" # 基于 map 的坐标系
|
||||
msg.point.x = math.sin(0.05 * math.pi * k) # x 值
|
||||
msg.point.y = math.cos(0.05 * math.pi * k) # y 值
|
||||
msg.point.z = 0.0
|
||||
pub.publish(msg) # 发布话题
|
||||
rospy.loginfo("发布端发送坐标信息: x=%.3f, y=%.3f" % (msg.point.x, msg.point.y)) # 打印坐标信息
|
||||
k += 1
|
||||
rate.sleep()
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
48
src/Service/scripts/Service_S.py
Normal file
48
src/Service/scripts/Service_S.py
Normal file
@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import rospy
|
||||
import math, cmath
|
||||
from Service.srv import FFT, FFTResponse
|
||||
|
||||
def computeFFT(input_data):
|
||||
N = len(input_data)
|
||||
magnitude = [0.0] * (N//2 + 1) # 存储幅值
|
||||
phase = [0.0] * (N//2 + 1) # 存储相位
|
||||
|
||||
for k in range(N//2 + 1):
|
||||
s = 0+0j
|
||||
|
||||
for n in range(N):
|
||||
angle = -2 * math.pi * k * n / N # 角度计算
|
||||
s += input_data[n] * complex(math.cos(angle), math.sin(angle)) # 快速傅里叶变换公式
|
||||
|
||||
magnitude[k] = abs(s) # 幅值
|
||||
phase[k] = cmath.phase(s) # 相位
|
||||
|
||||
return magnitude, phase
|
||||
|
||||
def fft_callback(req):
|
||||
if len(req.data_x) != req.window_size or len(req.data_y) != req.window_size:
|
||||
rospy.logerr("数据量不符合128点FFT要求")
|
||||
return FFTResponse()
|
||||
|
||||
mag_x, phase_x = computeFFT(req.data_x) # 对坐标 x 和 y 分别进行快速傅里叶变换FFT
|
||||
mag_y, phase_y = computeFFT(req.data_y)
|
||||
|
||||
res = FFTResponse()
|
||||
res.magnitude_x = mag_x # 坐标 x 的幅度
|
||||
res.magnitude_y = mag_y # 坐标 y 的幅度
|
||||
res.phase_x = phase_x # 坐标 x 的相位
|
||||
res.phase_y = phase_y # 坐标 y 的相位
|
||||
|
||||
rospy.loginfo("FFT 服务完成 %d 个点" % req.window_size)
|
||||
return res
|
||||
|
||||
if __name__ == '__main__':
|
||||
rospy.init_node('Service_S')
|
||||
|
||||
service = rospy.Service('fft_service', FFT, fft_callback) # ROS 服务
|
||||
|
||||
rospy.loginfo("服务端快速傅里叶变换程序执行成功")
|
||||
|
||||
rospy.spin()
|
147
src/Service/scripts/Subscriber_Client_S.py
Normal file
147
src/Service/scripts/Subscriber_Client_S.py
Normal file
@ -0,0 +1,147 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
import rospy
|
||||
import random
|
||||
from geometry_msgs.msg import PointStamped, Point
|
||||
from visualization_msgs.msg import Marker, MarkerArray
|
||||
from Service.srv import FFT
|
||||
|
||||
MAX_POINTS = 100
|
||||
FFT_WINDOW_SIZE = 128
|
||||
|
||||
original_trajectory = []
|
||||
noisy_trajectory = []
|
||||
noisy_x_history = []
|
||||
noisy_y_history = []
|
||||
current_x_magnitudes = []
|
||||
current_y_magnitudes = []
|
||||
noisy_pub = None
|
||||
marker_pub = None
|
||||
fft_client = None
|
||||
|
||||
def position_callback(msg):
|
||||
global original_trajectory, noisy_trajectory
|
||||
global noisy_x_history, noisy_y_history
|
||||
global current_x_magnitudes, current_y_magnitudes
|
||||
global noisy_pub, marker_pub, fft_client
|
||||
|
||||
noise_x = random.uniform(-0.1, 0.1) # 产生 -0.1 ~0.1 的随机噪声
|
||||
noise_y = random.uniform(-0.1, 0.1)
|
||||
|
||||
noisy_msg = PointStamped()
|
||||
noisy_msg.header = msg.header
|
||||
noisy_msg.point.x = msg.point.x + noise_x # 在原信号上叠加噪声
|
||||
noisy_msg.point.y = msg.point.y + noise_y
|
||||
noisy_msg.point.z = 0.0
|
||||
|
||||
original_trajectory.append(msg.point) # 原点轨迹
|
||||
if len(original_trajectory) > MAX_POINTS:
|
||||
original_trajectory.pop(0)
|
||||
noisy_trajectory.append(noisy_msg.point) #加噪轨迹
|
||||
if len(noisy_trajectory) > MAX_POINTS:
|
||||
noisy_trajectory.pop(0)
|
||||
|
||||
noisy_x_history.append(noisy_msg.point.x) #保存历史坐标信息
|
||||
noisy_y_history.append(noisy_msg.point.y)
|
||||
|
||||
marker_array = MarkerArray()
|
||||
|
||||
# 原始信号轨迹绘制
|
||||
original_line = Marker()
|
||||
original_line.header = msg.header
|
||||
original_line.ns = "trajectory"
|
||||
original_line.id = 0
|
||||
original_line.type = Marker.LINE_STRIP
|
||||
original_line.action = Marker.ADD
|
||||
original_line.scale.x = 0.02
|
||||
original_line.color.g = 1.0 # 绿色线
|
||||
original_line.color.a = 1.0
|
||||
original_line.points = list(original_trajectory)
|
||||
marker_array.markers.append(original_line)
|
||||
|
||||
# 加噪信号轨迹绘制
|
||||
noisy_line = Marker()
|
||||
noisy_line.header = msg.header
|
||||
noisy_line.ns = "trajectory"
|
||||
noisy_line.id = 1
|
||||
noisy_line.type = Marker.LINE_STRIP
|
||||
noisy_line.action = Marker.ADD
|
||||
noisy_line.scale.x = 0.02
|
||||
noisy_line.color.r = 1.0 # 红色线
|
||||
noisy_line.color.a = 1.0
|
||||
noisy_line.points = list(noisy_trajectory)
|
||||
marker_array.markers.append(noisy_line)
|
||||
|
||||
# 原始信号位置点
|
||||
original_point = Marker()
|
||||
original_point.header = msg.header
|
||||
original_point.ns = "current_point"
|
||||
original_point.id = 0
|
||||
original_point.type = Marker.SPHERE
|
||||
original_point.action = Marker.ADD
|
||||
original_point.pose.position = msg.point
|
||||
original_point.pose.orientation.w = 1.0
|
||||
original_point.scale.x = 0.1
|
||||
original_point.scale.y = 0.1
|
||||
original_point.scale.z = 0.1
|
||||
original_point.color.g = 1.0 # 绿色球
|
||||
original_point.color.a = 1.0
|
||||
marker_array.markers.append(original_point)
|
||||
|
||||
# 加噪信号位置点
|
||||
noisy_point = Marker()
|
||||
noisy_point.header = msg.header
|
||||
noisy_point.ns = "current_point"
|
||||
noisy_point.id = 1
|
||||
noisy_point.type = Marker.SPHERE
|
||||
noisy_point.action = Marker.ADD
|
||||
noisy_point.pose.position = noisy_msg.point
|
||||
noisy_point.pose.orientation.w = 1.0
|
||||
noisy_point.scale.x = 0.1
|
||||
noisy_point.scale.y = 0.1
|
||||
noisy_point.scale.z = 0.1
|
||||
noisy_point.color.r = 1.0 # 红色球
|
||||
noisy_point.color.a = 1.0
|
||||
marker_array.markers.append(noisy_point)
|
||||
|
||||
# 当点数 >=128 时利用快速傅里叶变换FFT计算加噪信号频谱
|
||||
if len(noisy_x_history) >= FFT_WINDOW_SIZE:
|
||||
try:
|
||||
res = fft_client(data_x=noisy_x_history[-FFT_WINDOW_SIZE:],
|
||||
data_y=noisy_y_history[-FFT_WINDOW_SIZE:],
|
||||
window_size=FFT_WINDOW_SIZE)
|
||||
rospy.loginfo("FFT computed successfully")
|
||||
current_x_magnitudes[:] = res.magnitude_x
|
||||
current_y_magnitudes[:] = res.magnitude_y
|
||||
except rospy.ServiceException as e:
|
||||
rospy.logerr("Failed to call FFT service: %s" % e)
|
||||
|
||||
# 判断频谱,生成频谱图
|
||||
if current_x_magnitudes and current_y_magnitudes:
|
||||
x_spectrum = Marker()
|
||||
x_spectrum.header = msg.header
|
||||
x_spectrum.ns = "坐标x频谱"
|
||||
x_spectrum.id = 2
|
||||
x_spectrum.type = Marker.CUBE_LIST
|
||||
x_spectrum.action = Marker.ADD
|
||||
x_spectrum.scale.x = 0.08
|
||||
x_spectrum.scale.y = 0.01
|
||||
x_spectrum.scale.z = 1.0
|
||||
x_spectrum.color.b = 1.0
|
||||
x_spectrum.color.a = 0.8
|
||||
|
||||
y_spectrum = Marker()
|
||||
y_spectrum.header = msg.header
|
||||
y_spectrum.ns = "坐标y频谱"
|
||||
y_spectrum.id = 3
|
||||
y_spectrum.type = Marker.CUBE_LIST
|
||||
y_spectrum.action = Marker.ADD
|
||||
y_spectrum.scale.x = 0.08
|
||||
y_spectrum.scale.y = 0.01
|
||||
y_spectrum.scale.z = 1.0
|
||||
y_spectrum.color.r = 1.0
|
||||
y_spectrum.color.a = 0.8
|
||||
|
||||
for i in range(len(current_x_magnitudes)):
|
||||
px = Point()
|
||||
px.x = i * 0.1
|
8
src/Service/srv/FFT.srv
Normal file
8
src/Service/srv/FFT.srv
Normal file
@ -0,0 +1,8 @@
|
||||
float64[] data_x
|
||||
float64[] data_y
|
||||
int32 window_size
|
||||
---
|
||||
float64[] magnitude_x
|
||||
float64[] magnitude_y
|
||||
float64[] phase_x
|
||||
float64[] phase_y
|
Loading…
x
Reference in New Issue
Block a user