PCL库学习及ROS使用

PCL库学习

c_cpp_properties.json

{"configurations": [{"name": "Linux","includePath": ["${workspaceFolder}/**","/usr/include","/usr/local/include"],"defines": [],"compilerPath": "/usr/bin/gcc","cStandard": "c11","cppStandard": "c++17","intelliSenseMode": "clang-x64"// "compileCommands": "${workspaceFolder}/build/compile_commands.json"}],"version": 4
}

CMakeLists.txt

cmake_minimum_required(VERSION 2.6)
project(pcl_demo)find_package(PCL 1.14 REQUIRED)include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})add_executable(pcl_read pcl_read.cpp)target_link_libraries (pcl_read ${PCL_LIBRARIES})
# install(TARGETS pcl_read RUNTIME DESTINATION bin)

点云数据类型

  • pcl::PointXYZ:最简单也可能是最常用到的点类型;它只储存了3Dxyz的信息。
  • pcl::PointXYZI:除上面XYZ内容外还包含了一个描述点亮度(intensity)的字段。当想要获取传感器返回的亮度高于一定级别的点时非常有用。还有与此相似的其他两种标准的点数据类型:一是pcl::nterestPoint,它有一个字段储存强度(strength);二是pcl::PointWithRange;它有一个字段储存距离(视点到采样点)。 pcl::PointXYZRGBA:这种点类型储存3D信息,也储存颜色(RGB=Red,Green, Blue)和透明度(A=Alpha)。
  • pcl::PointXYZRGB:这种点类型与前面的点类型相似,但是它没有透明度字段。
  • pcl::Normal:这是最常用的点类型,表示曲面上给定点处的法线以及测量的曲率。
  • pcl::PointNormal:这种点类型跟前一个点类型一样;它包含了给定点所在曲面法线以及曲率信息,但是它也包含了点的3Dxyz坐标。这种点类型的变异类型是PointXYZRGBNormal和 PointXYZINormal,正如名字所提示,它们包含了颜色(前者)和亮度(后者)。

公共字段

  • header:这个字段是pcl::PCLHeader类型,指定了点云的获取时间。
  • points:这个字段是std::vector<PointT,…>类型,它是储存所有点的容器。vector定 义中的PointT对应于类的模板参数,即点的类型。
  • width:这个字段指定了点云组织成一种图像时的宽度,否则它包含的是云中点的数量。
  • height:这个字段指定了点云组织成一种图像时的高度,否则它总是1。
  • is_dense:这个字段指定了点云中是否有无效值(无穷大或NaN值)。
  • sensor_origin_:这个字段是Eigen::Vector4f类型,并且定义了传感器根据相对于原点 的平移所得到的位姿。
  • sensor_orientation_:这个字段是Eigen::Quaternionf类型,并且定义了传感器旋转所 得到的位姿。

创建并保存点云

方式1

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>int main()
{pcl::PointCloud<pcl::PointXYZ> cloud;// Fill in the cloud datacloud.width = 5;cloud.height = 1;cloud.is_dense = false;cloud.resize(cloud.width * cloud.height);for (auto &point : cloud){point.x = 1024 * rand() / (RAND_MAX + 1.0f);point.y = 1024 * rand() / (RAND_MAX + 1.0f);point.z = 1024 * rand() / (RAND_MAX + 1.0f);}pcl::io::savePCDFileASCII("test_pcd.pcd", cloud);std::cerr << "Saved " << cloud.size() << " data points to test_pcd.pcd." << std::endl;for (const auto &point : cloud)std::cerr << "    " << point.x << " " << point.y << " " << point.z << std::endl;return 0;
}
/*************
Saved 5 data points to test_pcd.pcd.0.352222 -0.151883 -0.106395-0.397406 -0.473106 0.292602-0.731898 0.667105 0.441304-0.734766 0.854581 -0.0361733-0.4607 -0.277468 -0.916762
***************/    

方式2

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/common/common_headers.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/console/parse.h>int main(int argc, char **argv)
{pcl::PointCloud<pcl::PointXYZ>::Ptr basic_cloud_ptr(new pcl::PointCloud<pcl::PointXYZ>);pcl::PointCloud<pcl::PointXYZRGB>::Ptr point_cloud_ptr(new pcl::PointCloud<pcl::PointXYZRGB>);uint8_t r(255), g(15), b(15);for(float z(-1.0); z < 1.0; z += 0.05){for(float angle(0.0); angle <= 360.0; angle += 5.0){pcl::PointXYZ  basic_point;basic_point.x = 0.5 * cosf(pcl::deg2rad(angle));basic_point.y = sinf(pcl::deg2rad(angle));basic_point.z = z;basic_cloud_ptr->points.push_back(basic_point);pcl::PointXYZRGB point;point.x = basic_point.x;point.y = basic_point.y;point.z = basic_point.z;uint32_t rgb = (static_cast<uint32_t>(r) << 16 | static_cast<uint32_t>(g) << 8 |static_cast<uint32_t>(b));point.rgb = *reinterpret_cast<float *> (&rgb);point_cloud_ptr->points.push_back(point); }if(z<0.0){r -= 12;g += 12;}else{g -= 12;b += 12;}}basic_cloud_ptr->width = (int)basic_cloud_ptr->points.size();basic_cloud_ptr->height = 1;basic_cloud_ptr->is_dense = false;pcl::io::savePCDFileASCII("test_pcd_basic_2.pcd", *basic_cloud_ptr);for(const auto &point:basic_cloud_ptr->points)std::cerr<<" "<<point.x<<" "<<point.y<<" "<<point.z<<std::endl;point_cloud_ptr->width = (int)point_cloud_ptr->points.size();point_cloud_ptr->height = 1;point_cloud_ptr->is_dense = false;pcl::io::savePCDFileASCII("test_pcd_point_2.pcd", *point_cloud_ptr);for(const auto &point:point_cloud_ptr->points)std::cerr<<" "<<point.x<<" "<<point.y<<" "<<point.z<<std::endl;return 0;    
}

test_pcd.pcd

# .PCD v.7 - Point Cloud Data file format
VERSION .7								# 版本号
FIELDS x y z 				    		#  指定一个点可以有的每一个维度和字段的名字
SIZE 4 4 4 								# 用字节数指定每一个维度的大小。例如:
TYPE F F F								# 用一个字符指定每一个维度的类型 int uint folat
COUNT 1 1 1 1							# 指定每一个维度包含的元素数目
WIDTH 5   						  	    # 像图像一样的有序结构,有5行和1列,
HEIGHT 1    					  		# 这样该数据集中共有5*1=5个点
VIEWPOINT 0 0 0 1 0 0 0					# 指定数据集中点云的获取视点 视点信息被指定为平移(txtytz)+四元数(qwqxqyqz)
POINTS 5								# 指定点云中点的总数。从0.7版本开始,该字段就有点多余了
DATA ascii								# 指定存储点云数据的数据类型。支持两种数据类型:ascii和二进制
0.35222197 -0.15188313 -0.10639524
-0.3974061 -0.47310591 0.29260206
-0.73189831 0.66710472 0.44130373
-0.73476553 0.85458088 -0.036173344
-0.46070004 -0.2774682 -0.91676188

读取点云

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>int main(int argc, char ** argv)
{pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);if(pcl::io::loadPCDFile<pcl::PointXYZ>("/home/ghigher/CPuls_Project/test01/build/test_pcd.pcd", *cloud) == -1){PCL_ERROR("Couldn`t read file test_pcd.pcd \n");return -1;}std::cout<<"Load " << cloud->width * cloud->height << "data points from test_pcd.pcd width the following fields:" <<std::endl;for(size_t i = 0; i<cloud->points.size(); ++i){std::cout << " "<< cloud->points[i].x << " "<< cloud->points[i].y <<" "<< cloud->points[i].z << std::endl;}return 0;
}
/*********************************
Load 5data points from test_pcd.pcd width the following fields:0.352222 -0.151883 -0.106395-0.397406 -0.473106 0.292602-0.731898 0.667105 0.441304-0.734766 0.854581 -0.0361733-0.4607 -0.277468 -0.916762
*********************************/

显示点云

#include <pcl/visualization/cloud_viewer.h>
#include <iostream>
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>int main()
{pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);pcl::io::loadPCDFile("/home/ghigher/CPuls_Project/test01/build/test_pcd_point_2.pcd", *cloud);//创建CloudViewer点云显示对象pcl::visualization::CloudViewer viewer("Cloud Viewer");viewer.showCloud(cloud);while(!viewer.wasStopped()){}return 0;
}
image-20240217155304489

KDTree

#include <pcl/point_cloud.h>        //点类型定义头文件
#include <pcl/kdtree/kdtree_flann.h> //kdtree类定义头文件#include <iostream>
#include <vector>
#include <ctime>int
main (int argc, char** argv)
{srand (time (NULL));   //用系统时间初始化随机种子//创建一个PointCloud<pcl::PointXYZ>pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);// 随机点云生成cloud->width = 1000;             //此处点云数量cloud->height = 1;                //表示点云为无序点云cloud->points.resize (cloud->width * cloud->height);for (size_t i = 0; i < cloud->points.size (); ++i)   //循环填充点云数据{cloud->points[i].x = 1024.0f * rand() / (RAND_MAX + 1.0f); // // 产生数值为0-1024的浮点数cloud->points[i].y = 1024.0f * rand () / (RAND_MAX + 1.0f);cloud->points[i].z = 1024.0f * rand () / (RAND_MAX + 1.0f);}//创建KdTreeFLANN对象,并把创建的点云设置为输入,创建一个searchPoint变量作为查询点pcl::KdTreeFLANN<pcl::PointXYZ> kdtree; // pcl::KdTreeFLANN<PointT, Dist>::setInputCloud (const PointCloudConstPtr &cloud, const IndicesConstPtr &indices)//设置搜索空间kdtree.setInputCloud (cloud);//设置查询点并赋随机值pcl::PointXYZ searchPoint;searchPoint.x = 1024.0f * rand () / (RAND_MAX + 1.0f);searchPoint.y = 1024.0f * rand () / (RAND_MAX + 1.0f);searchPoint.z = 1024.0f * rand () / (RAND_MAX + 1.0f);// K 临近搜索//创建一个整数(设置为10)和两个向量来存储搜索到的K近邻,两个向量中,一个存储搜索到查询点近邻的索引,另一个存储对应近邻的距离平方int K = 10;std::vector<int> pointIdxNKNSearch(K);      //存储查询点近邻索引std::vector<float> pointNKNSquaredDistance(K); //存储近邻点对应距离平方//打印相关信息std::cout << "K nearest neighbor search at (" << searchPoint.x << " " << searchPoint.y << " " << searchPoint.z<< ") with K=" << K << std::endl;if ( kdtree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0 )  //执行K近邻搜索{//打印所有近邻坐标for (size_t i = 0; i < pointIdxNKNSearch.size (); ++i)std::cout << "    "  <<   cloud->points[ pointIdxNKNSearch[i] ].x << " " << cloud->points[ pointIdxNKNSearch[i] ].y << " " << cloud->points[ pointIdxNKNSearch[i] ].z << " (squared distance: " << pointNKNSquaredDistance[i] << ")" << std::endl;}// 半径 R内近邻搜索方法std::vector<int> pointIdxRadiusSearch;           //存储近邻索引std::vector<float> pointRadiusSquaredDistance;   //存储近邻对应距离的平方float radius = 256.0f * rand () / (RAND_MAX + 1.0f);   //随机的生成某一半径//打印输出std::cout << "Neighbors within radius search at (" << searchPoint.x << " " << searchPoint.y << " " << searchPoint.z<< ") with radius=" << radius << std::endl;// 假设我们的kdtree返回了大于0个近邻。那么它将打印出在我们"searchPoint"附近的10个最近的邻居并把它们存到先前创立的向量中。if ( kdtree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0 )  //执行半径R内近邻搜索方法{for (size_t i = 0; i < pointIdxRadiusSearch.size (); ++i)std::cout << "    "  <<   cloud->points[ pointIdxRadiusSearch[i] ].x << " " << cloud->points[ pointIdxRadiusSearch[i] ].y << " " << cloud->points[ pointIdxRadiusSearch[i] ].z << " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;}return 0;
}
/**************************
K nearest neighbor search at (763.71 771.792 499.333) with K=10743.497 707.763 466.9 (squared distance: 5560.2)743.305 814.092 581.355 (squared distance: 8933.23)831.035 753.543 578.683 (squared distance: 11162.2)706.388 734.124 580.101 (squared distance: 11228.1)811.653 670.148 524.748 (squared distance: 13276)819.709 753.288 599.12 (squared distance: 13435.7)852.38 697.685 530.509 (squared distance: 14326.1)817.204 665.183 481.782 (squared distance: 14535)694 796.036 396.447 (squared distance: 16032.8)788.24 794.644 621.827 (squared distance: 16128.8)
Neighbors within radius search at (763.71 771.792 499.333) with radius=118.164743.497 707.763 466.9 (squared distance: 5560.2)743.305 814.092 581.355 (squared distance: 8933.23)831.035 753.543 578.683 (squared distance: 11162.2)706.388 734.124 580.101 (squared distance: 11228.1)811.653 670.148 524.748 (squared distance: 13276)819.709 753.288 599.12 (squared distance: 13435.7)
**************************/

ROS中使用

PCL接口

  • std_msgs::Header:通常是每一个ROS消息的一部分。它包含消息发送时间、序列号和坐标系名称等信息。等价于pcl::Headertype。
  • sensor_msgs::PointCloud2:用来转换pcl::PointCloud类型
  • pcl_msgs::PointIndices:这个消息类型储存了一个点云中点的索引,等价PCL类型是pcl::PointIndices。
  • pcl_msgs::PolygonMesh:这个消息类型保存了描绘网格、顶点和多边形的信息,等价PCL类型是pcl::PolygonMesh。
  • pcl_msgs::Vertices:这个消息类型将一组顶点的索引保存在一个数组中,例如描述一个多边形。等价PCL类型是pcl::Vertices。
  • pcl_msgs::ModelCoefficients:这个消息类型储存了一个模型的不同系数,例如描述一 个平面需要的四个参数。等价的PCL类型是pcl:ModelCoefficients。
void toROSMsg(const pcl::PointCloud<T> &, sensor_msgs::PointCloud2 &); 
void fromROSMsg(const sensor_msgs::PointCloud2 &, pcl::PointCloud<T> &);
void moveFromROSMsg(sensor_msgs::PointCloud2 &, pcl::PointCloud<T> &); 

创建并发布

依赖

  message_filters roscpp rosbag rospy sensor_msgs std_msgs pcl_ros pcl_conversions message_generation
#include <iostream>
#include <pcl/point_types.h>
#include <pcl_conversions/pcl_conversions.h>
#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>int main(int argc, char **argv)
{ros::init(argc, argv, "point_cloud_node");ros::NodeHandle nh;ros::Publisher pub = nh.advertise<sensor_msgs::PointCloud2>("pointcloud_pub_topic", 1000);ros::Rate rate(3);unsigned int num_points = 4;pcl::PointCloud<pcl::PointXYZRGB> cloud;cloud.points.resize(num_points);sensor_msgs::PointCloud2 output_msg;while(ros::ok()){output_msg.header.stamp = ros::Time::now();for(int i=0; i<num_points; i++){cloud.points[i].x = i;cloud.points[i].y = i;cloud.points[i].z = i;cloud.points[i].r = 0;cloud.points[i].g = 255;cloud.points[i].b = 0;}pcl::toROSMsg(cloud, output_msg);output_msg.header.frame_id = "point_cloud_frame_id";pub.publish(output_msg);rate.sleep();}ros::spin();return 0;} 
image-20240217155602698

接收并进行位姿转换

#include <ros/ros.h>
#include <sensor_msgs/PointCloud2.h>
#include <pcl/point_types.h>
#include <pcl_conversions/pcl_conversions.h>
#include <pcl/common/transforms.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/filters/voxel_grid.h>class pcl_sub
{private:ros::NodeHandle nh;ros::Subscriber subCloud;ros::Publisher pubCloud;sensor_msgs::PointCloud2 msg;sensor_msgs::PointCloud2 adjust_msg;pcl::PointCloud<pcl::PointXYZRGB> adjust_pcl;public:pcl_sub():nh("~"){subCloud = nh.subscribe<sensor_msgs::PointCloud2>("/point_cloud_topic", 1, &pcl_sub::getcloud, this);pubCloud = nh.advertise<sensor_msgs::PointCloud2>("/adjust_msgs", 1);}void getcloud(const sensor_msgs::PointCloud2ConstPtr &laserCloudMsg){pcl::PointCloud<pcl::PointXYZRGB>::Ptr adjust_pcl_ptr(new pcl::PointCloud<pcl::PointXYZRGB>);//将ROS消息转换为PCL点云pcl::fromROSMsg(*laserCloudMsg, *adjust_pcl_ptr);//定义一个旋转矩阵 虽然为3D 实质上是4x4矩阵(旋转+平移)Eigen::Isometry3d T = Eigen::Isometry3d::Identity();Eigen::AngleAxisd rotationVector(M_PI/4, Eigen::Vector3d(0, 0, 1));Eigen::Matrix3d rotationMatrix = Eigen::Matrix3d::Identity();rotationMatrix = rotationVector.toRotationMatrix();//旋转部分赋值T.linear() = rotationMatrix;//平移部分赋值T.translation() = Eigen::Vector3d(0, 0, 0);//执行变换 保存结果pcl::PointCloud<pcl::PointXYZRGB>::Ptr transform_cloud(new pcl::PointCloud<pcl::PointXYZRGB>);pcl::transformPointCloud (*adjust_pcl_ptr, *transform_cloud, T.matrix());adjust_pcl = *transform_cloud;for(int i = 0; i<adjust_pcl.points.size();i++){adjust_pcl.points[i].r = 255;adjust_pcl.points[i].g = 0;adjust_pcl.points[i].b = 0;}//将PCL点云转换为ROS消息pcl::toROSMsg(adjust_pcl, adjust_msg);pubCloud.publish(adjust_msg);}~pcl_sub(){}
};int main(int argc, char **argv)
{ros::init(argc, argv, "point_cloud_transform");pcl_sub ps;ros::spin();return 0;
}
image-20240217173448241

参考视频:https://space.bilibili.com/222855903

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

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

相关文章

2.14日学习打卡----初学Zookeeper(一)

2.14日学习打卡 目录: 2.14日学习打卡Zookeeper概念一. 集中式到分布式单机架构集群架构什么是分布式三者区别 二. CAP定理分区容错性一致性可用性一致性和可用性的矛盾一致性和可用性如何选择 三. 什么是Zookeeper分布式架构Zookeeper从何而来Zookeeper介绍 四. 应用场景数据发…

第六节笔记:OpenCompass 大模型评测

视频链接&#xff1a;https://www.bilibili.com/video/BV1Gg4y1U7uc/?spm_id_from333.788&vd_source3bbd0d74033e31cbca9ee35e111ed3d1

上位机图像处理和嵌入式模块部署(Halcon借鉴与客户学习)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 对于很多学院派的同学来说&#xff0c;他们对市场的感觉一般是比较弱的。如果写一个软件的话&#xff0c;或者说开发一个项目的话&#xff0c;他们…

2024 CKS 题库 | 9、网络策略 NetworkPolicy

不等更新题库 CKS 题库 9、网络策略 NetworkPolicy Task 创建一个名为 pod-restriction 的 NetworkPolicy 来限制对在 namespace dev-team 中运行的 Pod products-service 的访问。 只允许以下 Pod 连接到 Pod products-service namespace qaqa 中的 Pod位于任何 namespace&…

vue-自定义创建项目(六)

为什么要自定义创建项目&#xff1f; 因为VueCli默认创建的项目不能够满足我们的要求&#xff0c;比如默认的项目中没有帮我们集成路由&#xff0c;vuex&#xff0c;eslink等功能。 默认项目 自定义创建项目 流程&#xff1a; 创建项目命令&#xff1a;vue create custom_dem…

亚马逊测评:揭秘做号的“花招”与“猫腻”,如何避免被割韭菜?

亚马逊测评行业如今如火如荼&#xff0c;吸引了众多朋友投身其中。然而&#xff0c;这个行业也是五花八门&#xff0c;什么样的人和公司都有&#xff0c;让人眼花缭乱。作为卖家&#xff0c;如何选择靠谱的测评服务商是一门必修课&#xff1b;而对于初学者&#xff0c;如何入门…

SHERlocked93 的 2021 年终总结

我还是和往年一样&#xff0c;总结发的又晚了一点&#xff0c;为什么又发这么晚呢&#xff0c;因为懒 年终总结 疫情之后时间时间过的太快了&#xff0c;不知道是不是只有我这样感觉。 四五月份去兰州玩了下&#xff08;其实是出差&#xff09;&#xff0c;终于看到了黄土高原&…

2024年蓝牙耳机推荐,值得入手的蓝牙耳机排行榜

​随着生活水平的提高&#xff0c;蓝牙耳机已经成为了许多人日常生活中不可或缺的数码产品。无论是听音乐、看视频还是打电话&#xff0c;蓝牙耳机都为我们提供了极大的便利。然而&#xff0c;面对市场上众多的蓝牙耳机品牌和型号&#xff0c;许多人感到无所适从。所以&#xf…

Linux第58步_备份busybox生成rootfs根文件系统

备份busybox生成rootfs根文件系统 打开终端 输入“ls回车” 输入“cd linux/回车” 输入“ls回车”&#xff0c;产看“linux”目录下的文件和文件夹 输入“cd nfs/回车”&#xff0c;切换到“nfs”目录 输入“ls回车”&#xff0c;产看“nfs”目录下的文件和文件夹 输入…

力扣OJ题——旋转数组

题目&#xff1a;189.旋转数组 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数 思路一&#xff1a; 1.每次挪动旋转1位&#xff08;用tmp将最后一位存起来&#xff0c;其余所有数据向后移&#xff0c;然后将tmp放在第一个位…

RabbitMQ配置消息转换器

1. 默认转换器 Test public void testSendMap() throws InterruptedException {// 准备消息Map<String, Object> msg new HashMap<>();msg.put("name", "harry");msg.put("age", 21);// 发送消息rabbitTemplate.convertAndSend(&q…

无电池设备物联网的未来

在物联网(IoT)世界中&#xff0c;一种改变游戏规则的趋势正在出现&#xff0c;它就是无电池物联网。想象一下不需要普通电池的智能设备。这些被称为环境物联网(A-IoT)的独特小工具正在改变游戏规则。它们不再使用老式电池&#xff0c;而是通过无线电信号、光、振动和热量获取能…

Python一级考试笔记

Python一级考试笔记【源源老师】 前置知识&#xff1a;&#xff08;了解即可&#xff09; Python常见的几种编程环境&#xff1a;IDLE&#xff08;自带&#xff09;、Visual Studio Code、Jupyter、pyCharm&#xff1b; python版本&#xff1a;python3 和 python2&#xff08;…

STM32学习笔记(七) —— DMA传输(MTM)

DMA&#xff0c;全称是Direct Memory Access&#xff08;直接内存访问&#xff09;。可以在存储器和存储器之间或者外设和存储器之间传输数据&#xff0c;而不需要CPU的干预&#xff0c;这样可以节省CPU的资源&#xff0c;提高工作效率。 1.功能框图 STM32F103RCT6有两个DMA控…

东方博宜 1057. 能被5整除且至少有一位数字是5的所有整数的个数

东方博宜 1057. 能被5整除且至少有一位数字是5的所有整数的个数。 思路&#xff1a; 1 首先输入n 2 用for循环遍历1-n中间的数 3 每一个数进行对5取余的运算&#xff0c;看是否能被5整除 4 在整除的基础上&#xff0c;看这个数的各个数位上是否有5&#xff0c;这一步将数对10取…

OpenGL学习——15.投光物_聚光

前情提要&#xff1a;本文代码源自Github上的学习文档“LearnOpenGL”&#xff0c;我仅在源码的基础上加上中文注释。本文章不以该学习文档做任何商业盈利活动&#xff0c;一切著作权归原作者所有&#xff0c;本文仅供学习交流&#xff0c;如有侵权&#xff0c;请联系我删除。L…

简单工厂模式-Simple Factory Pattern

原文地址:https://jaune162.blog/design-pattern/simple-factory-pattern/ 简介 简单工厂模式是一种非常常用的设计模式,但是并不属于GoF中的23种设计模式。简单设计模式有很多种实现方式。 本文我们就来讨论简单工厂模式的实现方式,以及如何借助Spring实现一个扩展性很好…

数字孪生与智慧城市:共筑未来城市的科技基石

一、引言 随着科技的飞速发展&#xff0c;数字孪生与智慧城市已成为未来城市建设的两大关键技术。数字孪生为城市提供了一个虚拟的数字镜像&#xff0c;使我们能全面、深入地了解城市的运行状态。而智慧城市则借助先进的信息通信技术&#xff0c;提升城市的智能化水平&#xf…

手写myscrapy(二)

我们看一下scrapy的系统架构设计方法和思路&#xff1a; 模块化设计&#xff1a; Scrapy采用模块化设计&#xff0c;将整个系统划分为多个独立的模块&#xff0c;包括引擎&#xff08;Engine&#xff09;、调度器&#xff08;Scheduler&#xff09;、下载器&#xff08;Downl…

PMP 考试的含金量怎么样?

PMP考试的含金量怎么样&#xff1f;培训机构又该如何选择&#xff1f; PMP认证只有在部分城市才能参与职称评定、没有挂靠这一说&#xff0c;毕竟认证体系不一样&#xff0c;但如果是从项目管理行业开始说起的话&#xff0c;其他证书都黯然失色&#xff0c;也只有PMP或同类证书…