ROS2机器人编程简述humble-第四章-BASIC DETECTOR .3

news2024/11/13 14:44:40

书中程序适用于turtlebot、husky等多种机器人,配置相似都可以用的。

支持ROS2版本foxy、humble。

基础检测效果如下:

由于缺¥,所有设备都非常老旧,都是其他实验室淘汰或者拼凑出来的设备。机器人控制笔记本是2010年版本。

但是依然可以跑ROS1、ROS2。

book_ros2/br2_tf2_detector目录:

.
├── CMakeLists.txt
├── include
│   └── br2_tf2_detector
│       ├── ObstacleDetectorImprovedNode.hpp
│       ├── ObstacleDetectorNode.hpp
│       └── ObstacleMonitorNode.hpp
├── launch
│   ├── detector_basic.launch.py
│   ├── detector_improved.launch.py
│   ├── turtlebot_detector_basic.launch.py
│   └── turtlebot_detector_improved.launch.py
├── package.xml
└── src
    ├── br2_tf2_detector
    │   ├── ObstacleDetectorImprovedNode.cpp
    │   ├── ObstacleDetectorNode.cpp
    │   ├── ObstacleMonitorNode (copy).cpp
    │   └── ObstacleMonitorNode.cpp
    ├── detector_improved_main.cpp
    └── detector_main.cpp

5 directories, 15 files

里面有两个部分basic和improved。

CMakelist(lib):

cmake_minimum_required(VERSION 3.5)
project(br2_tf2_detector)

set(CMAKE_CXX_STANDARD 17)

# find dependencies
find_package(ament_cmake REQUIRED)
find_package(rclcpp REQUIRED)
find_package(tf2_ros REQUIRED)
find_package(geometry_msgs REQUIRED)
find_package(sensor_msgs REQUIRED)
find_package(visualization_msgs REQUIRED)

set(dependencies
    rclcpp
    tf2_ros
    geometry_msgs
    sensor_msgs
    visualization_msgs
)

include_directories(include)

add_library(${PROJECT_NAME} SHARED
  src/br2_tf2_detector/ObstacleDetectorNode.cpp
  src/br2_tf2_detector/ObstacleMonitorNode.cpp
  src/br2_tf2_detector/ObstacleDetectorImprovedNode.cpp
)
ament_target_dependencies(${PROJECT_NAME} ${dependencies})

add_executable(detector src/detector_main.cpp)
ament_target_dependencies(detector ${dependencies})
target_link_libraries(detector ${PROJECT_NAME})

add_executable(detector_improved src/detector_improved_main.cpp)
ament_target_dependencies(detector_improved ${dependencies})
target_link_libraries(detector_improved ${PROJECT_NAME})

install(TARGETS
  ${PROJECT_NAME}
  detector
  detector_improved
  ARCHIVE DESTINATION lib
  LIBRARY DESTINATION lib
  RUNTIME DESTINATION lib/${PROJECT_NAME}
)

install(DIRECTORY launch DESTINATION share/${PROJECT_NAME})

if(BUILD_TESTING)
  find_package(ament_lint_auto REQUIRED)
  ament_lint_auto_find_test_dependencies()
endif()

ament_package()

障碍物识别节点

// Copyright 2021 Intelligent Robotics Lab
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <memory>

#include "br2_tf2_detector/ObstacleDetectorNode.hpp"

#include "sensor_msgs/msg/laser_scan.hpp"
#include "geometry_msgs/msg/transform_stamped.hpp"

#include "rclcpp/rclcpp.hpp"

namespace br2_tf2_detector
{

using std::placeholders::_1;

ObstacleDetectorNode::ObstacleDetectorNode()
: Node("obstacle_detector")
{
  scan_sub_ = create_subscription<sensor_msgs::msg::LaserScan>(
    "input_scan", rclcpp::SensorDataQoS(),
    std::bind(&ObstacleDetectorNode::scan_callback, this, _1));

  tf_broadcaster_ = std::make_shared<tf2_ros::StaticTransformBroadcaster>(*this);
}

void
ObstacleDetectorNode::scan_callback(sensor_msgs::msg::LaserScan::UniquePtr msg)
{
  double dist = msg->ranges[msg->ranges.size() / 2];

  if (!std::isinf(dist)) {
    geometry_msgs::msg::TransformStamped detection_tf;

    detection_tf.header = msg->header;
    detection_tf.child_frame_id = "detected_obstacle";
    detection_tf.transform.translation.x = msg->ranges[msg->ranges.size() / 2];

    tf_broadcaster_->sendTransform(detection_tf);
  }
}

}  // namespace br2_tf2_detector

主要就是回调函数完成大部分功能。具体参考源代码即可。

障碍物监控节点:

// Copyright 2021 Intelligent Robotics Lab
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <tf2/transform_datatypes.h>
#include <tf2/LinearMath/Quaternion.h>
#include <tf2_geometry_msgs/tf2_geometry_msgs.h>

#include <memory>

#include "br2_tf2_detector/ObstacleMonitorNode.hpp"

#include "geometry_msgs/msg/transform_stamped.hpp"

#include "rclcpp/rclcpp.hpp"

namespace br2_tf2_detector
{

using namespace std::chrono_literals;

ObstacleMonitorNode::ObstacleMonitorNode()
: Node("obstacle_monitor"),
  tf_buffer_(),
  tf_listener_(tf_buffer_)
{
  marker_pub_ = create_publisher<visualization_msgs::msg::Marker>("obstacle_marker", 1);

  timer_ = create_wall_timer(
    500ms, std::bind(&ObstacleMonitorNode::control_cycle, this));
}

void
ObstacleMonitorNode::control_cycle()
{
  geometry_msgs::msg::TransformStamped robot2obstacle;

  try {
    robot2obstacle = tf_buffer_.lookupTransform(
      "odom", "detected_obstacle", tf2::TimePointZero);
  } catch (tf2::TransformException & ex) {
    RCLCPP_WARN(get_logger(), "Obstacle transform not found: %s", ex.what());
    return;
  }

  double x = robot2obstacle.transform.translation.x;
  double y = robot2obstacle.transform.translation.y;
  double z = robot2obstacle.transform.translation.z;
  double theta = atan2(y, x);

  RCLCPP_INFO(
    get_logger(), "Obstacle detected at (%lf m, %lf m, , %lf m) = %lf rads",
    x, y, z, theta);

  visualization_msgs::msg::Marker obstacle_arrow;
  obstacle_arrow.header.frame_id = "odom";
  obstacle_arrow.header.stamp = now();
  obstacle_arrow.type = visualization_msgs::msg::Marker::ARROW;
  obstacle_arrow.action = visualization_msgs::msg::Marker::ADD;
  obstacle_arrow.lifetime = rclcpp::Duration(1s);

  geometry_msgs::msg::Point start;
  start.x = 0.0;
  start.y = 0.0;
  start.z = 0.0;
  geometry_msgs::msg::Point end;
  end.x = x;
  end.y = y;
  end.z = z;
  obstacle_arrow.points = {start, end};

  obstacle_arrow.color.r = 1.0;
  obstacle_arrow.color.g = 0.0;
  obstacle_arrow.color.b = 0.0;
  obstacle_arrow.color.a = 1.0;

  obstacle_arrow.scale.x = 0.02;
  obstacle_arrow.scale.y = 0.1;
  obstacle_arrow.scale.z = 0.1;


  marker_pub_->publish(obstacle_arrow);
}

}  // namespace br2_tf2_detector

代码和原始版本稍微有些不同。

重要部分:

  try {
    robot2obstacle = tf_buffer_.lookupTransform(
      "odom", "detected_obstacle", tf2::TimePointZero);
  } catch (tf2::TransformException & ex) {
    RCLCPP_WARN(get_logger(), "Obstacle transform not found: %s", ex.what());
    return;
  }

  double x = robot2obstacle.transform.translation.x;
  double y = robot2obstacle.transform.translation.y;
  double z = robot2obstacle.transform.translation.z;
  double theta = atan2(y, x);

  RCLCPP_INFO(
    get_logger(), "Obstacle detected at (%lf m, %lf m, , %lf m) = %lf rads",
    x, y, z, theta);

如果tf不能正常工作,会报错Obstacle transform not found:

例如odom没有

[detector-1] [WARN] [1676266943.177279939] [obstacle_monitor]: Obstacle transform not found: "odom" passed to lookupTransform argument target_frame does not exist.

例如detected_obstacle没有

[detector-1] [WARN] [1676267019.166991316] [obstacle_monitor]: Obstacle transform not found: "detected_obstacle" passed to lookupTransform argument source_frame does not exist. 

需要思考并解决问题哦^_^

如果都ok!那么"Obstacle detected at (%lf m, %lf m, , %lf m) = %lf rads":

机器人在运动中所以角度和距离会不断变化。

此时如果查看:

rqt

其中检测tf是由激光传感器测距给出的。

节点主题图:

这个代码主程序!

// Copyright 2021 Intelligent Robotics Lab
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <memory>

#include "br2_tf2_detector/ObstacleDetectorNode.hpp"
#include "br2_tf2_detector/ObstacleMonitorNode.hpp"

#include "rclcpp/rclcpp.hpp"

int main(int argc, char * argv[])
{
  rclcpp::init(argc, argv);

  auto obstacle_detector = std::make_shared<br2_tf2_detector::ObstacleDetectorNode>();
  auto obstacle_monitor = std::make_shared<br2_tf2_detector::ObstacleMonitorNode>();

  rclcpp::executors::SingleThreadedExecutor executor;
  executor.add_node(obstacle_detector->get_node_base_interface());
  executor.add_node(obstacle_monitor->get_node_base_interface());

  executor.spin();

  rclcpp::shutdown();
  return 0;
}

这里需要注意!

  rclcpp::executors::SingleThreadedExecutor executor;
  executor.add_node(obstacle_detector->get_node_base_interface());
  executor.add_node(obstacle_monitor->get_node_base_interface());

如果C++掌握一般推荐看一看:

蓝桥ROS机器人之现代C++学习笔记7.1 并行基础

多线程是如何实现的。

整个程序要跑起来:

终端1-gazebo仿真:ros2 launch turtlebot3_gazebo empty_world.launch.py

ros2 launch turtlebot3_gazebo empty_world.launch.py 
[INFO] [launch]: All log files can be found below /home/zhangrelay/.ros/log/2023-02-13-13-43-10-244500-Aspire4741-10860
[INFO] [launch]: Default logging verbosity is set to INFO
urdf_file_name : turtlebot3_burger.urdf
[INFO] [gzserver-1]: process started with pid [10862]
[INFO] [gzclient   -2]: process started with pid [10864]
[INFO] [ros2-3]: process started with pid [10868]
[INFO] [robot_state_publisher-4]: process started with pid [10870]
[robot_state_publisher-4] [WARN] [1676266991.467830827] [robot_state_publisher]: No robot_description parameter, but command-line argument available.  Assuming argument is name of URDF file.  This backwards compatibility fallback will be removed in the future.
[robot_state_publisher-4] Parsing robot urdf xml string.
[robot_state_publisher-4] Link base_link had 5 children
[robot_state_publisher-4] Link caster_back_link had 0 children
[robot_state_publisher-4] Link imu_link had 0 children
[robot_state_publisher-4] Link base_scan had 0 children
[robot_state_publisher-4] Link wheel_left_link had 0 children
[robot_state_publisher-4] Link wheel_right_link had 0 children
[robot_state_publisher-4] [INFO] [1676266991.472337172] [robot_state_publisher]: got segment base_footprint
[robot_state_publisher-4] [INFO] [1676266991.472419811] [robot_state_publisher]: got segment base_link
[robot_state_publisher-4] [INFO] [1676266991.472444636] [robot_state_publisher]: got segment base_scan
[robot_state_publisher-4] [INFO] [1676266991.472465018] [robot_state_publisher]: got segment caster_back_link
[robot_state_publisher-4] [INFO] [1676266991.472485972] [robot_state_publisher]: got segment imu_link
[robot_state_publisher-4] [INFO] [1676266991.472505808] [robot_state_publisher]: got segment wheel_left_link
[robot_state_publisher-4] [INFO] [1676266991.472525491] [robot_state_publisher]: got segment wheel_right_link
[ros2-3] Set parameter successful
[INFO] [ros2-3]: process has finished cleanly [pid 10868]
[gzserver-1] [INFO] [1676266994.292818234] [turtlebot3_imu]: <initial_orientation_as_reference> is unset, using default value of false to comply with REP 145 (world as orientation reference)
[gzserver-1] [INFO] [1676266994.417396256] [turtlebot3_diff_drive]: Wheel pair 1 separation set to [0.160000m]
[gzserver-1] [INFO] [1676266994.417528534] [turtlebot3_diff_drive]: Wheel pair 1 diameter set to [0.066000m]
[gzserver-1] [INFO] [1676266994.420616206] [turtlebot3_diff_drive]: Subscribed to [/cmd_vel]
[gzserver-1] [INFO] [1676266994.425994254] [turtlebot3_diff_drive]: Advertise odometry on [/odom]
[gzserver-1] [INFO] [1676266994.428920116] [turtlebot3_diff_drive]: Publishing odom transforms between [odom] and [base_footprint]
[gzserver-1] [INFO] [1676266994.460852885] [turtlebot3_joint_state]: Going to publish joint [wheel_left_joint]
[gzserver-1] [INFO] [1676266994.461009035] [turtlebot3_joint_state]: Going to publish joint [wheel_right_joint]

终端2-障碍物检测:

ros2 launch br2_tf2_detector turtlebot_detector_basic.launch.py

终端3-rqt:rqt

终端4-rviz2:rviz2

windows端也可以获取信息。

补充:

四元数是方向的4元组表示,它比旋转矩阵更简洁。四元数对于分析涉及三维旋转的情况非常有效。四元数广泛应用于机器人、量子力学、计算机视觉和3D动画。

可以在维基百科上了解更多关于基础数学概念的信息。还可以观看一个可探索的视频系列,将3blue1brown制作的四元数可视化。

官方教程将指导完成调试典型tf2问题的步骤。它还将使用许多tf2调试工具,如tf2_echo、tf2_monitor和view_frames。

TF2完整教程提纲:

tf2

许多tf2教程都适用于C++和Python。这些教程经过简化,可以完成C++曲目或Python曲目。如果想同时学习C++和Python,应该学习一次C++教程和一次Python教程。

目录

工作区设置

学习tf2

调试tf2

将传感器消息与tf2一起使用

工作区设置

如果尚未创建完成教程的工作空间,请遵循本教程。

学习tf2

tf2简介。

本教程将让了解tf2可以为您做什么。它在一个多机器人的例子中展示了一些tf2的力量,该例子使用了turtlesim。这还介绍了使用tf2_echo、view_frames和rviz。

编写静态广播(Python)(C++)。

本教程教如何向tf2广播静态坐标帧。

编写广播(Python)(C++)。

本教程教如何向tf2广播机器人的状态。

编写监听器(Python)(C++)。

本教程教如何使用tf2访问帧变换。

添加框架(Python)(C++)。

本教程教如何向tf2添加额外的固定帧。

使用时间(Python)(C++)。

本教程教使用lookup_transform函数中的超时来等待tf2树上的转换可用。

时间旅行(Python)(C++)。

本教程向介绍tf2的高级时间旅行功能。

调试tf2

四元数基本原理。

本教程介绍ROS 2中四元数的基本用法。

调试tf2问题。

本教程向介绍调试tf2相关问题的系统方法。

将传感器消息与tf2一起使用

对tf2_ros::MessageFilter使用标记数据类型。

本教程教您如何使用tf2_ros::MessageFilter处理标记的数据类型。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/342030.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

九龙证券|本周5只新股申购,特斯拉、蔚来、理想的供应商来A股了!

据现在组织&#xff0c;2月13日到17日共有5只新股申购&#xff0c;其间上证主板2只&#xff0c;深证主板1只&#xff0c;北交所2只。 2月14日发动打新的深证主板新股多利科技成立于2010年&#xff0c;是一家专心于轿车冲压零部件及相关模具的开发、出产与出售的企业。从2020年…

nodejs版本管理器nvm下载,安装详情

文章目录前言一、NVM下载二、NVM安装三.使用NVM安装nodejs1.NVM常用命令2.安装node3.使用node前言 安装nodejs方式有两种。 第一种&#xff1a;官网下载  通过nodejs官网https://nodejs.org/zh-cn/下载安装 &#xff0c;但有个缺陷&#xff0c;不同版本的nodejs无法顺利的切…

软件测试面试理论(超详细)

【面试理论知识】1、你的测试职业发展是什么? 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自己…

Dubbo中应用级,与接口级配置中心的使用,包括单配置中心与多配置中心

接口级或应用级服务发现 Dubbo3 默认采用 “应用级服务发现 接口级服务发现” 的双注册模式 可以通过配置 dubbo.registry.register-modeinstance/interface/all 来改变注册行为。 instance &#xff1a; 应用级interface &#xff1a; 接口级all &#xff1a;两者都注册&a…

一文详解jvm之-Xms -Xmx -Xmn -Xss -XX:PermSize -XX:MaxPermSize等参数的设置和优化以及如何选择垃圾回收器

文章目录1. 文章引言2. 常见配置汇总2.1 Xmn Xms Xmx Xss的区别2.2 其他常见配置2.3 典型设置举例3. 回收器选择3.1 吞吐量优先的并行收集器3.2 响应时间优先的并发收集器3.3 辅助信息4. 参考文档1. 文章引言 我们经常在tomcat的catalina.bat或者catalina.sh中配置如下参数&am…

亚马逊、速卖通、temu、Cdiscount通过自养号给自己店铺测评补单需要哪些技巧?

亚马逊卖家通过测评平台&#xff0c;获取亚马逊买家的真实服务点评&#xff0c;即亚马逊测评。它既可以让买家更加快速、有效地了解产品&#xff0c;也可以让卖家有机会通过买家的评论去优化产品&#xff0c;以获得更多买家的喜爱。因此&#xff0c;亚马逊测评之于卖家&#xf…

Linux下内存buff/cache占用过多问题解决

在Linux下经常会遇到buff/cache内存占用过多问题&#xff0c; 尤其是使用云主机的时候最严重&#xff0c;由于很多是虚拟内存&#xff0c;因此如果buff/cache占用过大的&#xff0c; free空闲内存就很少&#xff0c;影响使用&#xff1b; 通常内存关系是&#xff1a; 普通机器…

Python 获得摄像头捕捉的图像

Python 获得摄像头捕捉的图像 很多时候&#xff0c;我们都需要通过摄像头捕获图像&#xff0c;以便进行处理&#xff0c;在这里分享的是通过OPEN CV这个库来实现。 OPEN CV的安装和使用 安装很简单&#xff0c;相关文章也很多&#xff0c;注意一点&#xff0c;不要安装最新版…

【Android视频号信息获取①】

*在2019年深圳上班的时候 那时候还是个Java 码农 接触了一下 Xposed.时隔多年 忘记差不多了 用frida先来练练手 新公司又让我研究微信视频号获取个人的视频主页标题列表 * 确定微信版本 不同版本微信hook点不一样。 预想实现方式 用Xposed去请求注册一个中转服务 然后脚本请…

Java——编辑距离

题目链接 leetcode在线oj题——编辑距离 题目描述 给你两个单词 word1 和 word2&#xff0c; 请返回将 word1 转换成 word2 所使用的最少操作数 。 你可以对一个单词进行如下三种操作&#xff1a; 插入一个字符删除一个字符替换一个字符 题目示例 输入&#xff1a;word…

搭建DJI 无人机Onboard SDK ROS开发环境及测试

搭建DJI 无人机Onboard SDK ROS开发环境及测试功能包简介开发环境搭建测试功能包连接设备启动SDK功能包简介 ROS功能包名称&#xff1a;dji_sdk 功能包功能&#xff1a;用于DJI 板载SDK的ROS版本 OSDK 是一个用于开发无人机应用程序的开发工具包&#xff0c;基于OSDK 开发的…

CUDA线程层次一文搞懂|参加CUDA线上训练营

设备术语 Host&#xff1a;CPU 和 内存 (host memory)Device&#xff1a;GPU 和显存 (device memory) CUDA 线程层次 CUDA 线程层次分为&#xff1a; Thread 所有线程执行相同的核函数并行执行 Thread Block 执行在一个 Streaming Multiprocessor &#xff08;SM&#xff09…

Python快速上手系列--异常处理--详解篇

本章所说的就是我们经常遇到的一个问题&#xff0c;报错、异常。我们应该如何处理&#xff0c;让它不影响后面的程序运行。异常首先我们看看一个简单的示例。print(2/0)其结果可想而知&#xff0c;当然是报错了&#xff01;程序被终止了&#xff01;这里会提示用户&#xff0c;…

索引-性能分析-慢查询日志

索引语法 1、创建索引时候 [UNIQUE | FULLTEXT] 关键字是可选的&#xff1b; 1&#xff09;加上 UNIUQE 就是创建唯一索引&#xff08;唯一索引&#xff0c;说明改字段不能出现重复数据&#xff09;&#xff1b; 2&#xff09;加上FULLTEXT 创建的是一个全文索引&#xff1b;…

Webpack5 环境下 Openlayers 标注(Icon) require 引入图片问题

Webpack5 环境下 Openlayers 标注&#xff08;Icon&#xff09; require 引入图片问题环境版本Openlayers 使用 require 问题Webpack5 正确配置构建新环境的时候&#xff0c;偶然发现 Openlayers 使用 require 的方式加载图片&#xff08;Icon&#xff09;报错&#xff0c;开始…

电子技术——DC偏移

电子技术——DC偏移 因为差分放大器是直接耦合的并且对于DC有着有限的增益&#xff0c;因此本节我们讨论差分放大器在DC相关方面的问题。 MOS差分放大器的输入偏移电压 考虑下面的电路&#xff0c;我们将MOS差分放大器的输入端都置地&#xff1a; 此时假如电路完全对称&#…

IP地址:揭晓安欣警官自证清白的黑科技

《狂飙》这部电视剧&#xff0c;此从播出以来可谓是火爆了&#xff0c;想必大家都是看过的。剧中&#xff0c;主人公“安欣”是一名警察。一直在与犯罪分子做斗争。 莽村的李顺案中&#xff0c;有匿名者这个案件在网上发帖恶意造谣&#xff0c;说安欣是黑恶势力的保护伞&#…

将视频作为桌面动态壁纸,只需要两步,让你保存的视频在桌面动起来,动态壁纸工具,视频动态壁纸,小风车,桌面美化工具

这款软件可以让你宝贵的视频资源变成动态壁纸显示在你的电脑上&#xff0c;体积小巧&#xff0c;不需要安装&#xff0c;即点即用。 一、软件简介 这是一款可以将视频文件作为动态壁纸展示在电脑桌面的软件&#xff0c;它体积小巧&#xff0c;占用资源也不多&#xff0c;相比…

SpringMVC基础入门(一)之理论基础概念

文章目录SpringMVC1.概念2.常用注解请求与响应1.请求参数2.JSON传输3.常用注解响应1.响应页面2.响应JSON数据Rest风格1.介绍2.常用注解SpringMVC 1.概念 &#xff08;1&#xff09;定义 SpringMVC是一种基于Java实现MVC模型的轻量级Web框架。 &#xff08;2&#xff09;为什…

test2

物理层故障分析 一、传输介质故障 a.主要用途简述 传输介质主要分为 导向传输介质和非导向传输介质。前者包括双绞线&#xff08;两根铜线并排绞合&#xff0c;距离过远会失真&#xff09;、同轴电缆&#xff08;铜质芯线屏蔽层&#xff0c;抗干扰性强&#xff0c;传输距离更…