socket传输数据:
局域网连接
连接---通信(命令行直接;+)--- 传输数据(socket)--传输内容:launch文件;
qgc连接;
1.局域网下的通信
1.1 局域网
厂家提供的方式是通过Homer图数传工具(硬件)构建的amov局域网实现通信连接.
好处是通信距离足够长,支持150m;坏处是"局部",无法访问互联网.
[IMAGE:homer连接]
根据这个原理,我尝试了通过个人局域网(即热点),建立通信连接.
[ 因为无人机本身带有机载电脑,而主机正常也就能连接热点和wifi ]
1.2个人热点[互联网下的局域网]
优点:便捷,且可访问互联网:
个人热点通常使用的确实是 WLAN(无线局域网)技术,它利用了无线技术(如Wi-Fi)来创建一个局域网络;
关键在于个人热点设备本身已经通过移动运营商的网络(如4G、5G)连接了互联网。
个人热点在此过程中扮演了中介的角色:
它将其他设备发出的请求转发给移动运营商的网络,并将响应返回给这些设备
[这意味着对于任何的报错输出你都可以去线上寻找答案(尤其是大模型AI)];
缺点是通信距离短,无人机飞远了数据传输有大延迟 ;
2.远程控制主机
2.1 GUi图形化界面--Nomachine
基于X11协议的远程桌面工具;
2.2 SSH 连接--命令行操控
连接:ssh建立连接需要账号和密码+IP;
[输入密码];
连接成功(如红框所示):
3.实操 --个人热点下实现ros无人机与PC传输gps经纬度
3.1实现局域网下的通信
开启手机热点,连接设备至少2个(个人PC和amov无人机机载电脑主机)
点击查看其配置(即IP):
知道ip,即可ping 查看是否能够通信;
比如我发现amov的IP地址为192.168.63.a;
1) ping尝试
ping 192.168.163.a
应有输出[代表ping通]:
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
Reply from 127.0.0.1: bytes=32 time<1ms TTL=128
3.2连接无人机机载电脑(通过ssh)
见[2.2 SSH 连接--命令行操控]
命令行下输入:
ssh amov@ 192.168.x.a
#amov 为账户名 后面为其ip地址
输入密码;
登录成功;
3.3 启动节点[同时顺便连接qgc]
连接qgc流程:进入对应路径-更改脚本-启动脚本;
cd home/amov/p600_experiment/src/p600_experiment/launch_basic
vim p600_gps_onboard.launch
3.3.1将上图红框的ip改为要使用QGC的个人PC主机IP[如此才能实现与qgc的连接]
3.3.2随后执行该.launch脚本以启动节点:
roslaunch p600_gps_onboard.launch
脚本如下:
<!-- 本launch为使用px4_sender进行机载控制时的机载端启动脚本 -->
<launch>
<!-- 启动MAVROS -->
<!-- 不同机载电脑,注意修改fcu_url至正确的端口号及波特率 -->
<node pkg="mavros" type="mavros_node" name="mavros" output="screen">
<param name="fcu_url" value="/dev/ttyTHS0:921600" />
<!--param name="gcs_url" value="udp://@192.168.31.46" / -->
<param name="gcs_url" value="" />
<param name="target_system_id" value="1" />
<param name="target_component_id" value="1" />
<rosparam command="load" file="$(find p600_experiment)/config/mavros_config/px4_pluginlists_gps.yaml" />
<rosparam command="load" file="$(find p600_experiment)/config/mavros_config/px4_config_gps.yaml" />
</node>
<!-- 启动Prometheus代码 -->
<!-- run the px4_pos_estimator.cpp -->
<arg name="input_source" default="9"/>
<arg name="rate_hz" default="30"/>
<node pkg="prometheus_control" type="px4_pos_estimator" name="px4_pos_estimator" output="screen">
<!-- 定位数据输入源 0 for vicon, 1 for 激光SLAM, 2 for gazebo ground truth, 3 for T265 -->
<param name="input_source" value="$(arg input_source)" />
<param name="rate_hz" value="$(arg rate_hz)" />
</node>
<!-- run the px4_sender.cpp -->
<node pkg="prometheus_control" type="px4_sender" name="px4_sender" output="screen">
<rosparam command="load" file="$(find p600_experiment)/config/prometheus_control_config/px4_sender_outdoor.yaml"/>
</node>
<!-- run the ground_station.cpp -->
<node pkg="prometheus_station" type="ground_station" name="ground_station" output="screen" launch-prefix="gnome-terminal --tab --">
</node>
<!-- run the ground_station_msg.cpp -->
<node pkg="prometheus_station" type="ground_station_msg" name="ground_station_msg" output="screen" launch-prefix="gnome-terminal --tab --">
</node>
</launch>
3.3.3预期输出:
该cmd窗口顶端应该如下:
3.3.4 rostopic list 查看已启动节点:
白框即为涉及到gps的节点:
3.3.5 qgc成功连接:
(红框处应显示为连接成功)
3.3.6关于节点:
在ROS(Robot Operating System)中,节点(Nodes)是实现机器人功能的基本组成单元。
每个节点通常执行一个特定的任务,并且可以通过ROS的通信机制与其他节点进行数据交换。
以下是关于ROS节点的详细介绍以及一个简单的实例:
节点的基本概念:
节点定义:
- ROS节点是一个执行特定任务的进程,可以理解为ROS应用程序中的一个模块或者组件。
- 每个节点都是一个独立的进程,可以通过ROS的通信机制与其他节点进行数据交换。
节点之间的通信:
- ROS节点通过话题(Topics)、服务(Services)、参数服务器(Parameter Server)以及动态重配置(Dynamic Reconfigure)进行通信。
- 话题:是一种发布者-订阅者模型,节点可以发布(publish)消息到话题或者订阅(subscribe)话题接收消息。
- 服务:允许节点请求某种特定的计算或操作,其他节点可以提供服务以响应这些请求。
- 参数服务器:用于存储和获取ROS参数,节点可以动态地获取和修改这些参数。
- 动态重配置:允许节点在运行时调整其参数,而不需要重启节点。
节点的编写:
- ROS节点可以使用多种编程语言编写,包括C++和Python。
- 通常使用ROS提供的官方库(如roscpp和rospy)来编写节点,这些库提供了与ROS通信机制的高级接口。
示例:移动机器人中的ROS节点
假设有一个简单的移动机器人系统,包括以下几个ROS节点:
传感器数据获取节点:
- 功能:从机器人的传感器(例如激光雷达、相机)获取数据。
- 通信方式:通过发布者(Publisher)发布激光数据到名为
/scan
的话题。- 实现:可以使用C++编写,订阅激光雷达数据并发布到
/scan
话题。路径规划节点:
- 功能:根据机器人的当前位置和目标位置计算最优路径。
- 通信方式:订阅机器人当前位置和目标位置的话题,并将路径信息发布到名为
/path
的话题。- 实现:可以使用Python编写,订阅
/initial_pose
和/goal_pose
话题,使用路径规划算法(如A*或Dijkstra算法)计算路径,并发布到/path
话题。运动控制节点:
- 功能:接收路径信息,并控制机器人实现运动。
- 通信方式:订阅
/path
话题,控制机器人的底盘或运动执行器。- 实现:可以使用C++编写,订阅
/path
话题,调用运动控制库(如ROS MoveBase等)实现机器人的运动控制。用户界面节点:
- 功能:提供交互界面,允许用户设定目标位置或查看机器人状态。
- 通信方式:通过ROS服务接收用户设定的目标位置,并可以通过话题发布机器人的状态信息。
- 实现:可以使用Python编写,提供简单的图形用户界面(GUI),通过ROS服务与其他节点进行通信。
3.3.7节点实例(p600_gps_onboard.launch):
<!-- 本launch为使用px4_sender进行机载控制时的机载端启动脚本 -->
<launch>
<!-- 启动MAVROS -->
<!-- 不同机载电脑,注意修改fcu_url至正确的端口号及波特率 -->
<node pkg="mavros" type="mavros_node" name="mavros" output="screen">
<param name="fcu_url" value="/dev/ttyTHS0:921600" />
<!--param name="gcs_url" value="udp://@192.168.31.46" / -->
<param name="gcs_url" value="" />
<param name="target_system_id" value="1" />
<param name="target_component_id" value="1" />
<rosparam command="load" file="$(find p600_experiment)/config/mavros_config/px4_pluginlists_gps.yaml" />
<rosparam command="load" file="$(find p600_experiment)/config/mavros_config/px4_config_gps.yaml" />
</node>
<!-- 启动Prometheus代码 -->
<!-- run the px4_pos_estimator.cpp -->
<arg name="input_source" default="9"/>
<arg name="rate_hz" default="30"/>
<node pkg="prometheus_control" type="px4_pos_estimator" name="px4_pos_estimator" output="screen">
<!-- 定位数据输入源 0 for vicon, 1 for 激光SLAM, 2 for gazebo ground truth, 3 for T265 -->
<param name="input_source" value="$(arg input_source)" />
<param name="rate_hz" value="$(arg rate_hz)" />
</node>
<!-- run the px4_sender.cpp -->
<node pkg="prometheus_control" type="px4_sender" name="px4_sender" output="screen">
<rosparam command="load" file="$(find p600_experiment)/config/prometheus_control_config/px4_sender_outdoor.yaml"/>
</node>
<!-- run the ground_station.cpp -->
<node pkg="prometheus_station" type="ground_station" name="ground_station" output="screen" launch-prefix="gnome-terminal --tab --">
</node>
<!-- run the ground_station_msg.cpp -->
<node pkg="prometheus_station" type="ground_station_msg" name="ground_station_msg" output="screen" launch-prefix="gnome-terminal --tab --">
</node>
</launch>
这是一个ROS launch文件,用于启动与机载控制相关的节点和程序。让我们逐个节点和参数来详细解释:
1. 启动 MAVROS
<node pkg="mavros" type="mavros_node" name="mavros" output="screen">
<param name="fcu_url" value="/dev/ttyTHS0:921600" />
<param name="gcs_url" value="" />
<param name="target_system_id" value="1" />
<param name="target_component_id" value="1" />
<rosparam command="load" file="$(find p600_experiment)/config/mavros_config/px4_pluginlists_gps.yaml" />
<rosparam command="load" file="$(find p600_experiment)/config/mavros_config/px4_config_gps.yaml" />
</node>
- mavros_node: 这个节点来自
mavros
包,它与 PX4 Autopilot 系统通信,充当 ROS 和飞控单元之间的接口。 - fcu_url: 指定飞控单元的串口设备及波特率,这里设置为
/dev/ttyTHS0:921600
。 - gcs_url: 地面站 URL,如果有需要可以填入对应的值,但在这里是空白的。
- target_system_id 和 target_component_id: 分别指定飞控单元的系统 ID 和组件 ID。
- px4_pluginlists_gps.yaml 和 px4_config_gps.yaml: 加载了用于 MAVROS 的配置文件,配置 PX4 插件和参数。
2. 启动 Promethues 代码
<node pkg="prometheus_control" type="px4_pos_estimator" name="px4_pos_estimator" output="screen">
<param name="input_source" value="9" />
<param name="rate_hz" value="30" />
</node>
- px4_pos_estimator: 这个节点估计无人机的位置,根据参数设置从不同的数据源获取位置数据,这里使用参数
input_source
来指定输入源为 9,可能代表特定的传感器或系统。 - rate_hz: 设置节点运行的频率为 30Hz。
<node pkg="prometheus_control" type="px4_sender" name="px4_sender" output="screen">
<rosparam command="load" file="$(find p600_experiment)/config/prometheus_control_config/px4_sender_outdoor.yaml"/>
</node>
- px4_sender: 这个节点负责向 PX4 发送控制命令或数据。通过加载
px4_sender_outdoor.yaml
文件来配置节点所需的参数。
3. 启动地面站相关节点
<node pkg="prometheus_station" type="ground_station" name="ground_station" output="screen" launch-prefix="gnome-terminal --tab --">
</node> <node pkg="prometheus_station" type="ground_station_msg" name="ground_station_msg" output="screen" launch-prefix="gnome-terminal --tab --">
</node>
- ground_station: 这个节点可能是一个地面站程序的一部分,用于与无人机或系统进行通信和控制。
launch-prefix
设置了在新标签页中启动该节点。 - ground_station_msg: 这个节点可能是用来处理地面站的消息传递和交互的程序。
3.2 订阅话题
GimbalBasic::GimbalBasic(ros::NodeHandle &nh)
{
nh.param<std::string>("multicast_udp_ip", multicast_udp_ip, "224.0.0.88");
this->communication_ = new Communication(nh);
//【订阅】吊舱状态数据
this->gimbal_state_sub_ = nh.subscribe("/gimbal/state", 10, &GimbalBasic::stateCb, this);
//【订阅】跟踪误差
this->vision_diff_sub_ = nh.subscribe("/gimbal/track", 10, &GimbalBasic::trackCb, this);
//【发布】框选 点击 目标
this->window_position_pub_ = nh.advertise<ground_station_bridge::WindowPosition>("/detection/bbox_draw", 1000);
//【发布】吊舱控制
this->gimbal_control_pub_ = nh.advertise<ground_station_bridge::GimbalControl>("/gimbal/control", 1000);
}
3.2.1 订阅(sub)话题实例 :
this->gimbal_state_sub_ = nh.subscribe("/gimbal/state", 10, &GimbalBasic::stateCb, this);
this->vision_diff_sub_ = nh.subscribe("/gimbal/track", 10, &GimbalBasic::trackCb, this);
- 这两行代码分别用来订阅两个不同的ROS话题。
gimbal_state_sub_
订阅/gimbal/state
话题,每次缓存10个消息,当有新消息时调用GimbalBasic::stateCb
成员函数处理。vision_diff_sub_
订阅/gimbal/track
话题,同样每次缓存10个消息,当有新消息时调用GimbalBasic::trackCb
成员函数处理。&GimbalBasic::stateCb
和&GimbalBasic::trackCb
是成员函数指针,指向处理收到消息的回调函数。
3.2.2 查看所有话题:
rostopic list
是一个命令行工具命令,用于列出当前ROS系统中所有可用的话题(topics);
3.2.3 命令行终端获得gps话题的输出:
e.g.
rostopic echo /mavros/gpsstatus/gps1/raw
预期输出:
关于话题:
话题(topics)是一种基础的通信机制,用于在ROS节点之间传递消息。话题是一种发布者-订阅者(publisher-subscriber)模型的实现,允许节点(ROS程序)以异步的方式进行通信。以下是关于ROS话题的一些重要信息和特性:
1. 定义和命名
- 话题名称: 每个话题都有一个唯一的名称,用于在整个ROS系统中标识该话题。话题名称以斜杠
/
开头,例如/odom
、/scan
等。- 消息类型: 每个话题传递的消息具有特定的数据类型,如传感器数据、控制命令等。消息类型由 ROS 消息定义文件(
.msg
文件)定义,并且在编译时生成。2. 通信模式
- 发布者(Publishers): 发布者节点向话题发布消息。多个节点可以同时发布到同一个话题。
- 订阅者(Subscribers): 订阅者节点从话题订阅消息。多个节点可以同时订阅同一个话题。
3. 异步通信
- ROS话题的通信是异步的,即发布者和订阅者之间不需要直接建立连接。发布者发布消息后,所有订阅该话题的节点都能接收到这些消息,而不需要发布者和订阅者同时在线。
3.3 通过socket传回[+内容筛选]
socket代码如下:
server:
# -*- coding: utf-8 -*-
#!/usr/bin/env python
import socket
# 设置服务器的 IP 地址和端口号
SERVER_IP ='192.168.79.60' #'10.128.72.152'#'192.168.1.134'#'192.168.231.77'
SERVER_PORT = 8082
# 创建一个 TCP socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 连接服务器
client_socket.connect((SERVER_IP, SERVER_PORT))
# 设置超时时间为 5 秒
client_socket.settimeout(10)
while True:
# # 发送 "rostopic echo" 命令给服务器
# message = "rostopic echo"
# client_socket.sendall(message.encode())
# 手动输入消息
message = input("请输入要发送的消息 ('q' to quit): ")
if message == 'q':
break
# 发送消息给服务器
client_socket.sendall(message.encode())
# 接收服务器的响应
try:
response = client_socket.recv(4096) # 增加缓冲区大小以确保完整接收响应
if response:
response_str = response.decode('gbk')
print("从服务器收到的响应:", response_str)
# 截取以“lat:”开头的行
lat_lines = [line for line in response_str.split('\n') if line.startswith('lat:')]
print("截取的 lat 行:")
if lat_lines:
for line in lat_lines:
print(line)
else:
print("没有找到以 'lat:' 开头的行")
# 截取以“lon:”开头的行
lon_lines = [line for line in response_str.split('\n') if line.startswith('lon:')]
print("截取的 lon 行:")
if lon_lines:
for line in lon_lines:
print(line)
else:
print("没有找到以 'lon:' 开头的行")
else:
print("服务器没有响应")
except socket.timeout:
print("操作超时,请重试")
# 关闭连接
client_socket.close()
client[实现基本的实时输入通信]:
import socket
# 设置服务器的 IP 地址和端口号
SERVER_IP ='10.128.74.238' #'192.168.1.123'
SERVER_PORT = 8080 # 端口号与服务器端口号一致
# 创建一个 UDP socket
client_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
while True:
# 输入要发送的数据
message = input("请输入要发送到服务器的消息(输入 'exit' 退出): \n GPS:")
if message == 'exit':
break
# 发送数据
client_socket.sendto(message.encode(), (SERVER_IP, SERVER_PORT))
# 接收服务器的响应
data, server_address = client_socket.recvfrom(1024)
print(f"收到来自服务器 {server_address} 的响应:", data.decode())
# 关闭连接
client_socket.close()
3.4 传给本地数据库
[待补充]..