2020-12-03----------------------------------------------------------------------------------------------------------------------------------------------------------

ROS中,发布多个odo和laser frame之间的变换,并在odo frame下发布位姿和路径,在laser frame下发布点云

    void publish(){geometry_msgs::Quaternion q = tf::createQuaternionMsgFromYaw(current_pose_(2));// 发布tf变换,rviz也依赖这里的变换去表示坐标系之间的相对位姿geometry_msgs::TransformStamped odo_transform;odo_transform.header.stamp = ros::Time::now();odo_transform.header.frame_id = "odo";// 当前transform所表示的父坐标系odo_transform.child_frame_id = "scan";// 当前transform的子坐标系odo_transform.transform.translation.x = current_pose_(0);odo_transform.transform.translation.y = current_pose_(1);odo_transform.transform.rotation = q;tf_.sendTransform(odo_transform);// tf::TransformBroadcaster tf_;// 发布里程计消息,在里程计坐标系下表示,rviz中的效果为三维坐标系/箭头的移动nav_msgs::Odometry odo;odo.header.stamp = ros::Time::now();odo.header.frame_id = "odo";odo.child_frame_id = "scan";// 这里的意义是什么?只有这个不发布tf不可以odo.pose.pose.position.x = current_pose_(0);odo.pose.pose.position.y = current_pose_(1);odo.pose.pose.orientation = q;laser_odo_pub_.publish(odo);// 发布path,即带时间戳的位姿的集合,在rviz中的效果就是路径
//            geometry_msgs::PoseStamped pose;
//            pose.header.frame_id = "scan";
//            pose.pose.orientation.w = std::cos(current_pose_(2) * 0.5);
//            pose.pose.orientation.z = std::sin(current_pose_(2) * 0.5);
//            pose.pose.position.x = current_pose_(0);
//            pose.pose.position.y = current_pose_(1);
//            path_.poses.push_back(pose);// nav_msgs::Path path_;
//            nav_pub.publish(path_);static int count = 0;
//    每隔一定时间在scan坐标系下发布当前的点云数据,调整decay time使之长时间在odo坐标系中保留
//    因此,如果想要在scan坐标系下发布,而没有往odo中认为做变换,就需要知道scan和odo frame之间的关系,即tf所发布的消息if(count % 10 == 0){// 发布的实际上是预处理后的点cloud_.points.clear();for(const auto& point : ref_->points){geometry_msgs::Point32 p;if(point.position.norm() < 0.3)// 预处理后的无效点为0,需要过滤掉continue;p.x = point.position(0);p.y = point.position(1);p.z = 0.0;cloud_.points.emplace_back(p);}cloud_pub_.publish(cloud_);}count++;}

2020-10-29----------------------------------------------------------------------------------------------------------------------------------------------------------

C++强制类型转换运算符(static_cast、reinterpret_cast、const_cast和dynamic_cast)

C++强制类型转换运算符(static_cast、reinterpret_cast、const_cast和dynamic_cast)

2020-10-28----------------------------------------------------------------------------------------------------------------------------------------------------------

层级关系: 

workspace下有以下几个文件夹:

  • src
  • build
  • devel

src文件夹下:

  • package1
  • package2
  • CmakeLists.txt

package下:

  • src
  • include
  • CmakeLists.txt
  • package.xml

创建新package

创建一个package的方法为在src文件夹下执行

catkin_create_pkg [package_name] [dependes1] [dependes2] ...

这时会自动在src下生成该package,并带有以上四个文件夹.(一个类似的指令为roscreate-pkg,作用不一样,在这里不可以使用)

编译方法:

在workspace下执行:

catkin_make

等同于在workspace/src下执行:

cmake ..
make

release模式编译workspace下所有packages:

catkin_make -DCMAKE_BUILD_TYPE=RELEASE

其中relase可不全大写.注意这里是-DCMAKE_...(因为是给cmake指定的)

只编译指定package:

catkin_make -DCATKIN_WHITELIST_PACKAGES="package_name"

注意这里是-DCATKIN_.... (因为是给catkin_make指定的)

还有指定安装目录:

catkin_make -DCMAKE_INSTALL_PREFIX=...

2020-09-24----------------------------------------------------------------------------------------------------------------------------------------------------------

Eigen中使用auto可能存在的风险

void test(obj1, obj2){const auto value = ob1.method1() - ob2.method2();std::cout << value << std::endl;Eigen::Vector2d v = Eigen::Vector2d::Zeros();// 如果这句与Eigen无关,则不会有问题std::cout << value << std::endl;
}

上述method1和method的返回的都是Eigen::Vector2d形式的变量,但是obj1.method()的低层是:

    const Eigen::Vector2d getPose()const{Eigen::Vector2d pose = state_post_.head(2);return pose;}

其中,state_post_是动态大小的即Xd,只不过在类的构造函数中初始化了.

令人震惊的是,上面两次std::cout输出的结果是不一样的,而且如果连续循环多次调用test并给定多个不同参数,不同循环间的第二次输出,结果是一样的,但是单次循环内的两次输出结果不同!!!

原因肯定跟obj1中的state_post_是动态大小有关,但具体细节想不明白,什么原因呢???

解决方法是不要使用auto而是显式定义:

    const Eigen::Vector2d value = ob1.method1() - ob2.method2();

原因希望以后有机会弄清楚!!!!

2020-09-22-----------------------------------------------------------------------------------------------------------------------------------------------------------

ROS中的回调函数

1/可以定义成全局的callback函数

参考这里的文章https://www.cnblogs.com/tiderfang/p/8968124.html

需要注意的是回调函数的第一个参数的类型const sensor_msgs::XXXX::ConstPtr&或者const sensor_msgs::XXXXConstPtr&,这个是由ros的回调机制所决定的,如果这个参数要作为参数传递给别的函数,注意类型;

如果回调函数只需要这一个参数,可以缺省;

如果需要多个参数需要使用boost::bind,绑定成一个.

2/也可以使用类的成员函数作为回调函数

参考这里的文章https://blog.csdn.net/m0_38089090/article/details/81195776

需要注意的是,需要指定类的实例,即:

ros::Subscriber sub = n.subscribe<nav_msgs::Odometry>("chatter", 1000, &Listener::callback, &listener);

当然,类内可以使用this,可能需要使用bind

odom_sub = private_nh.subscribe<nav_msgs::Odometry>("odom", 1, boost::bind(&PatrolRobot::odomCB, this, _1));

需要注意的是,这里需要指定subscribe的话题类型,这与全局callback函数不同,

如果成员函数的输入参数不止一个,也需要bind.同样注意,这些成员函数的输入参数类型需要与ros回调机制所决定的一致.

笔者曾将尝试,将类或者类的成员函数作为参数bind后作为全局callback的回调函数,笔者之所以想调用callback再调用成员函数,而不是直接调用成员函数,原因在于想让成员函数执行后的结果返回到全局的callback函数中,从而进行可视化.

但是!!!其实类的内部也可以定义ros::NodeHandle和Publisher等,不需要再传递回到main函数,只要保证main函数里ros::init正常执行了就可以了.虽然没有解决把成员变量作为参数传递给全局callback的需求(可能还是跟我的类是模板类有关),但发现了这么做是完全没有必要的,在类内部发布就可以了,更加方便.

2020-09-20-----------------------------------------------------------------------------------------------------------------------------------------------------------

int**以及如何new二维数组

a) int a;表示一个内存空间,这个空间用来存放一个整数(int);
b) int* a;表示一个内存空间,这个空间用来存放一个指针,这个指针指向一个存放整数的空间,即a)中提到的空间;
c) int** a;表示一个内存空间,这个空间用来存放一个指针,这个指针指向一个存放指针的空间,并且指向的这个空间中的指针,指向一个整数。也简单的说,指向了一个b)中提到的空间;
d) int (*a)[4];表示一个内存空间,这个空间用来存放一个指针,这个指针指向一个长度为4、类型为int的数组;和int** a的区别在于,++、+=1之后的结果不一样,其他用法基本相同。
e) int (*a)(int);表示一个内存空间,这个空间用来存放一个指针,这个指针指向一个函数,这个函数有一个类型为int的参数,并且函数的返回类型也是int。

int* p[]:int*的数组,p的类型应该是int**

new多维数组的方法:

1/  int (* array2D)[5] = new int[n][5];也就是上面的d),需要知道第二个维度的大小,这样,array2D才知道要移动5个位置;

2/  int **array2D = new int *[height]; 然后再挨个new array2D[i],需要注意的是,这个在内容上是不连续的,访问防止越界;

3/  std::vector

举例:

    int** q = new int*[10];// new出来了10个int*的空间,但是int*只是指针,其所指向的空间还没有new呢喔,需要逐个newint (*p)[5] = new int[10][5];// p实际上还是指向指针的指针,只不过这里的对一个指针指得是固定指向5个int大小的int*for(int row = 0; row < 10; ++row){for(int col = 0; col < 5; ++col){p[row][col] = row * 5 + col;}}std::cout << *(*p++) << std::endl;std::cout << *(*p++) << std::endl;std::cout << *(*p++) << std::endl;

参考:

https://blog.csdn.net/wang13342322203/article/details/85228415

https://blog.csdn.net/yuqinjh/article/details/79095787

2020-09-18----------------------------------------------------------------------------------------------------------------------------------------------------------

ROS中LaserScan转换成PointCloud以及PointCloud2:

首先是LaserScan->PointCloud:

有两种方法,一种是自己一开始的笨方法:

    sensor_msgs::PointCloud cloud;int len = scan->ranges.size();cloud.header = scan->header;cloud.header.frame_id = "map";cloud.points.resize(len);cloud.channels.resize(1);cloud.channels[0].name = "intensity";cloud.channels[0].values.resize(len);for(int index = 0; index < len; ++index){geometry_msgs::Point32 p;double angle = scan->angle_min + scan->angle_increment * index;p.x = std::cos(angle) * scan->ranges[index];p.y = std::sin(angle) * scan->ranges[index];cloud.points[index] = p;cloud.channels[0].values[index] = scan->intensities[index];}

这里要注意channel的处理,当然不是必要的,但是如果需要intensity信息,就必须要设置.scan中默认存在intensity这个成员变量,转换成PointCloud的话,则需要自己定义这么个东西,具体方法上先resize这个channel数组成1,代表我只有一个channel(如果不resize可能会有问题,没法确定共有几个channel有意义).对于这个channel,名字是intensity, values数组连续填充即可.相对于scan,这样更省空间.当然这样操作比较繁琐.

另一种方法,调用库内置的函数方法:

    // cmake中添加laser_gemotry这个catkin的模块// #include <laser_geometry/laser_geometry.h>sensor_msgs::PointCloud cloud;laser_geometry::LaserProjection project;project.projectLaser(*scan, cloud);cloud.header.frame_id = "map";

当然还有方法直接调用tf进行点云的畸变校正和坐标变换,参考http://wiki.ros.org/laser_pipeline/Tutorials/IntroductionToWorkingWithLaserScannerData

接下来,是PointCloud<->PointCloud2,直接调用sensor_msg空间下的方法:

    sensor_msgs::PointCloud2 cloud_pub;sensor_msgs::PointCloud cloud;sensor_msgs::convertPointCloudToPointCloud2(cloud, cloud_pub);// 当然,sensor_msgs::convertPointCloud2ToPointCloud也是存在的

除此之外还有ROS和PCL中多种PointCloud之间的转换:

pcl::PointCloud<pcl::PointXYZ> pcl的点云pcl::PCLPointCloud2 pcl的第二种点云sensor_msgs::PointCloud2 ROS中的点云sensor_msgs::PointCloud ROS中的点云

参考:https://zhuanlan.zhihu.com/p/55958811

2020-09-01-----------------------------------------------------------------------------------------------------------------------------------------------------------

这里犯了一个很严重的错误,混淆了reserve和resize的概念.

reserve只是保留了足够的空间,并不影响size,因此reserv后没有经过push_back, emplace_back或者resize过,那么size==0, 不可直接使用[]进行索引;而resize改变了大小.同时默认赋值为0(不同编译器可能有差别).

    std::vector<int> test;test.reserve(3);// 只是保留了空间,千万不可用[]索引,在知道大小的情况下resize后可以,因为resize后size变了test.resize(3);// size变为3,且前三位默认是0LOG(INFO) << "After resize: " << test.size();LOG(INFO) << test[0] << " " << test[1] << " " << test[2];test.emplace_back(1);// 此时size变成了4LOG(INFO) << test.size();test[1] = 2;LOG(INFO) << test.size();return 0;

2020-08-20----------------------------------------------------------------------------------------------------------------------------------------------------------

取余数,周期性的角度限制范围

#include <cmath>
#include <glog/logging.h>
int main(int argc, char** argv){LOG(INFO) << std::remainder(5.0, 3.0);LOG(INFO) << std::remainder(-5.0, 3.0);LOG(INFO) << std::fmod(5.0, 3.0);LOG(INFO) << std::fmod(-5.0, 3.0);return 0;
}
// 输出结果:
//I0820 15:51:18.592721   655 remainder.cpp:7] -1
//I0820 15:51:18.592793   655 remainder.cpp:8] 1
//I0820 15:51:18.592806   655 remainder.cpp:9] 2
//I0820 15:51:18.592810   655 remainder.cpp:10] -2
// 也就是说fmod的输出的符号与arg1相同
// remainder则有可能变号,输出范围为(-arg2/2, arg2/2)

2020-07-23----------------------------------------------------------------------------------------------------------------------------------------------------------ROS中workspace下,cmake文件,.xml文件,以及launch文件的关系:

cmake文件中包含project name,以及若干个executable name;

package.xml中只有一个package name标志了目前的这个文件夹属于这个package;

launch文件格式如下:

<launch><node pkg="rslidar_sdk" name="rslidar_sdk_node" type="rslidar_sdk_node" output="screen"></node><!-- rviz --><node pkg="rviz" name="rviz" type="rviz" args="-d $(find rslidar_sdk)/rviz/rviz.rviz" />
</launch>

第2行指定了package name,指的是带有该名字的.xml文件所在package(cmake文件中的project name要与此一致,一一对应),这里就是指的本package;

type指的是该package下的node,对应的是cmake文件中add的同名executable文件,所以两者的名字也必须一一对应(源文件中的ros::init(arc, argv, "node_name")最好与也与此一致);

而name则是将该可执行文件的名字remap成一个新的node名字。

2020-07-22----------------------------------------------------------------------------------------------------------------------------------------------------------

lower_bound(val):返回容器中第一个值【大于或等于】val的元素的iterator位置。

upper_bound(val): 返回容器中第一个值【大于】

真正的物理意义在于,lower_bound在于找到第一个可以插入的位置,即如果有等于val的返回第一个等于val位置,如果没有返回第一个大于val的;upper_bound可以找到最后一个可以插入的地方,也就是第一个大于val的位置.

2020-07-01----------------------------------------------------------------------------------------------------------------------------------------------------------sudo apt-get update不成功:

1. 设置源;

2. 报错内容与自己设置的某些第三方网站相关,在/etc/apt下是否有个apt.conf文件,内容应该与之相关,尝试注释或者删除

2020-06-03----------------------------------------------------------------------------------------------------------------------------------------------------------

左值引用vs右值引用https://blog.csdn.net/xuyuqingfeng953/article/details/51058236

左值引用和直接传递了实参有区别么?

tuple, forward_as_tuplehttps://www.cnblogs.com/LuckCoder/p/8632209.html

2020-04-03------------------------------------------------------------------------------------------------------------------------------------------------------------------

指针作为类的成员变量,我想要改变指针的内容,指针的指针和指针的引用还是有区别的,

2020-3-23-----------------------------------------------------------------------------------------------------------------------------------------------------------如果new了一片内存赋值给指针p,通过delete的方式回收了内存,这时内存回收了,但是指针p依然指向这片未分配的内存区域,成为野指针,结果是不确定的,因而在delete释放内存的同时,需要手动通过p=nullptr将p置空 。同样,定义的时候也需要初始化。

C/C++野指针

空指针与野指针

野指针(概念,产生原因,危害,避免方法)

2020-3-20-----------------------------------------------------------------------------------------------------------------------------------------------------------

class A{
A(input){temp = input;
}
private:
int temp;
}
A a(5);std::shared_ptr<A> p(new A);
std::shared_ptr<A> p = std::make_shared<A>(a);
std::shared_ptr<A> p = std::make_shared<A>(5);

make_shared后面跟A类的一个对象或者构造函数里的参数,都是可以的。

2020-3-17-----------------------------------------------------------------------------------------------------------------------------------------------------------vector可以assign(n, digit);可以resize(大小),改变size,过大capacity会自动扩容; 也可以 reserve主动扩容,改变capacity.

resize更大之后,好像默认赋值0;resize更小之后,size变小了,但是原来的位置可以访问,而且还是原来的值,物理内存上的内容并没有改变.

thread及时回收,防止资源泄露https://www.cnblogs.com/liangjf/p/9801496.html

多线程cmake设置:

find_package (Threads)
add_executable (myapp main.cpp ...)
target_link_libraries (myapp ${CMAKE_THREAD_LIBS_INIT})

互斥锁std::mutex和条件变量std::condition_variable

——> > > std::mutex: std::mutex是C++中最基本的互斥量,提供了独占所有权的特性,std::mutex提供了以下成员函数:

构造函数:std::mutex不允许拷贝构造,也不允许move拷贝,最初产生的mutex对象是处于unlocked状态的。
lock():调用线程将锁住该互斥量,线程调用该函数会发生以下3种情况: 
(1)如果该互斥量当前没有被锁住,则调用线程将该互斥量锁住,直到调用unlock之前,该线程一直拥有该锁。 
(2)如果当前互斥量被其他线程锁住,则当前的调用线程被阻塞住。 
(3)如果当前互斥量被当前调用线程锁住,则会产生死锁,,也就是说同一个线程中不允许锁两次。

unlock():解锁,释放对互斥量的所有权。

try_lock():尝试锁住互斥量,如果互斥量被其他线程占有,则当前线程也不会被阻塞,线程调用该函数会出现下面3种情况: 
(1)如果当前互斥量没有被其他线程占有,则该线程锁住互斥量,直到该线程调用unlock释放互斥量。 
(2)如果当前互斥量被其他线程锁住,则当前调用线程返回false,而并不会被阻塞掉。 
(3)如果当前互斥量被当前调用线程锁住,则会产生死锁。

条件变量std::condition_variable:

  条件变量是并发程序设计中的一种控制结构。多个线程访问一个共享资源(或称临界区)时,不但需要用互斥锁实现独享访问以避免并发错误(称为竞争危害),在获得互斥锁进入临界区后还需要检验特定条件是否成立:C++11中引入了条件变量,其相关内容均在<condition_variable>中。这里主要介绍std::condition_variable类。

(1)、如果不满足该条件,拥有互斥锁的线程应该释放该互斥锁,把自身阻塞(block)并挂到(suspend)条件变量的线程队列中

(2)、如果满足该条件,拥有互斥锁的线程在临界区内访问共享资源,在退出临界区时通知(notify)在条件变量的线程队列中处于阻塞状态的线程,被通知的线程必须重新申请对该互斥锁加锁。

  条件变量std::condition_variable用于多线程之间的通信,它可以阻塞一个或同时阻塞多个线程。std::condition_variable需要与std::unique_lock配合使用。std::condition_variable效果上相当于包装了pthread库中的pthread_cond_*()系列的函数。

当std::condition_variable对象的某个wait函数被调用的时候,它使用std::unique_lock(通过std::mutex)来锁住当前线程。当前线程会一直被阻塞,直到另外一个线程在相同的std::condition_variable对象上调用了notification函数来唤醒当前线程。

std::condition_variable对象通常使用std::unique_lock<std::mutex>来等待,如果需要使用另外的lockable类型,可以使用std::condition_variable_any类。

std::condition_variable类的成员函数:

(1)、构造函数:仅支持默认构造函数,拷贝、赋值和移动(move)均是被禁用的。

(2)、wait:当前线程调用wait()后将被阻塞,直到另外某个线程调用notify_*唤醒当前线程;当线程被阻塞时,该函数会自动调用std::mutex的unlock()释放锁,使得其它被阻塞在锁竞争上的线程得以继续执行。一旦当前线程获得通知(notify,通常是另外某个线程调用notify_*唤醒了当前线程),wait()函数也是自动调用std::mutex的lock()。

  wait分为无条件被阻塞和带条件的被阻塞两种。

——> > > 无条件被阻塞:调用该函数前,当前线程应该已经对unique_lock<mutex> lck完成了加锁。所有使用同一个条件变量的线程必须在wait函数中使用同一个unique_lock<mutex>。该wait函数内部会自动调用lck.unlock()对互斥锁解锁,使得其他被阻塞在互斥锁上的线程恢复执行。使用本函数被阻塞的当前线程在获得通知(notified,通过别的线程调用 notify_*系列的函数)而被唤醒后,wait()函数恢复执行并自动调用lck.lock()对互斥锁加锁。

——> > > 带条件的被阻塞:wait函数设置了谓词(Predicate),只有当pred条件为false时调用该wait函数才会阻塞当前线程,并且在收到其它线程的通知后只有当pred为true时才会被解除阻塞。因此,等效于while (!pred())  wait(lck).

(3)、wait_for:与wait()类似,只是wait_for可以指定一个时间段,在当前线程收到通知或者指定的时间超时之前,该线程都会处于阻塞状态。而一旦超时或者收到了其它线程的通知,wait_for返回,剩下的步骤和wait类似。

(4)、wait_until:与wait_for类似,只是wait_until可以指定一个时间点,在当前线程收到通知或者指定的时间点超时之前,该线程都会处于阻塞状态。而一旦超时或者收到了其它线程的通知,wait_until返回,剩下的处理步骤和wait类似。

(5)、notify_all: 唤醒所有的wait线程,如果当前没有等待线程,则该函数什么也不做。

(6)、notify_one:唤醒某个wait线程,如果当前没有等待线程,则该函数什么也不做;如果同时存在多个等待线程,则唤醒某个线程是不确定的(unspecified)。

  条件变化存在虚假唤醒的情况,因此在线程被唤醒后需要检查条件是否满足。无论是notify_one或notify_all都是类似于发出脉冲信号,如果对wait的调用发生在notify之后是不会被唤醒的,所以接收者在使用wait等待之前也需要检查条件是否满足。

std::condition_variable_any类与std::condition_variable用法一样,区别仅在于std::condition_variable_any的wait函数可以接受任何lockable参数,而std::condition_variable只能接受std::unique_lock<std::mutex>类型的参数。

std::notify_all_at_thread_exit函数:当调用该函数的线程退出时,所有在cond条件变量上等待的线程都会收到通知。

参考:

https://www.cnblogs.com/depend-wind/articles/10108048.html

https://www.cnblogs.com/zhanghu52030/p/9166737.html

2020-3-11------------------------------------------------------------------------------------------------------------------------------------------------------------

基类A,包含a, b两个方法,其中a调用了b,且b是virtual;

派生类B,重写了b,还新写了个c函数;

基类指针p指向B的对象,不能调用c,因为他也不知道派生类会有这么个函数;

p调用函数a的时候,a又调用了函数b,因为是virtual的且B中也重写了,因此会调用B中的b。

2020-3-6---------------------------------------------------------------------------------------------------------------------------------------------------------------------

            std::atan(y/x)std::atan2(y, x)

atan的情况下,要保证x不会等于0;atan2允许x等于0,不需要特别考虑。做除法就要考虑分布会不会存在等于0的风险。

不要用abs(), fabs()这种c的库,统一用std::abs()

2020-3-5--------------------------------------------------------------------------------------------------------------------------------------------------------------------

enum 与enum class:

1.3 问题3:enum的作用域
enum的中的 ” { } ” 大括号并没有将枚举成员的可见域限制在大括号内,导致enum成员曝露到了上一级作用域(块语句)中。

例如:

#include <iostream>
enum color{red,blue};//定义拥有两个成员的enum,red和blue在enum的大括号外部可以直接访问,而不需要使用域运算符。
int main() {std::cout << blue << std::endl;std::cin.get();return 0;
}

就如上面的代码,我们可以在blue的大括号之外访问它,color的成员被泄露到了该文件的全局作用域中(虽然它尚不具备外部链接性)。可以直接访问,而不需要域运算符的帮助。

但是这不是关键,有时我们反而觉得非常方便。下面才是问题所在:

问题:无法定义同名的枚举成员

enum color { red, blue };
//enum MyEnum { red, yellow }; ERROR, 重定义;以前的定义是“枚举数”

如上面的代码所示:我们无法重复使用red这个标识符。因为它在color中已经被用过了。但是,它们明明就是不同的枚举类型,如果可以使用相同的成员名称,然后通过域运算符来访问的话,该有多好!就像下面这样:

color::red

但是这是旧版的enum无法做到的。
引入了域,要通过域运算符访问,不可以直接通过枚举体成员名来访问(所以我们可以定义相同的枚举体成员而不会发生重定义的错误)

#include <iostream>enum class color { red, green, yellow};
enum class colorX { red, green, yellow };int main() {//使用域运算符访问枚举体成员,强转后打印std::cout << static_cast<int>(color::red) << std::endl;std::cout << static_cast<int>(colorX::red) << std::endl;std::cin.get();return 0;
}

参考:https://blog.csdn.net/sanoseiichirou/article/details/50180533?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

尽量用using而不是typedef

    //typedef std::shared_ptr<FeatureInfo> FeatureInfo_Ptr;using FeatureInfo_Ptr = std::shared_ptr<FeatureInfo>;

push_back(), 已知大小的情况下先reserve(),不需要随机访问的情况系下用list

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

memset

memset()函数原型是extern void *memset(void *buffer, int c, int count)        buffer:为指针或是数组,

c:是赋给buffer的值,

count:是buffer的长度.

int abs(int i);                   // 处理int类型的取绝对值

double fabs(double i); //处理double类型的取绝对值

float fabsf(float i);           /处理float类型的取绝对值

----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

1、vector<Eigen::Matrix4d,Eigen::aligned_allocator<Eigen::Matrix4d>>

2、bitset

3、int*, static_cast<int*>, reinterpret_cast<int*>不一样;

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------

定义为虚函数,继承之后存在同名函数,但是行为不同,可以使用基类指针或者引用指向;

BCD都继承自A,可以使用A指针指向,从而做到用数组“保存”不同类型的BCD,不管是什么类型,如果他们都存在与A的同名虚函数,那么调用的就是BCD各自的方法,如果没有定义为虚函数,那么在任何情况下调用的都是基类的方法;

如果不需要使用基类指针指向不同class,并调用同名函数,也没必须定义虚函数,反正也不影响调用父类的函数功能

--------------------------------------------------------------------------------------------------------------------------------------------------------------------------chrono计时:

std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now();LandmarkFeatureExtracter::extract(scan, features);GeometryFeatureExtracter::extract(scan, features);std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();std::chrono::steady_clock::duration used_time = end-start;std::cout << "used time: " << std::chrono::duration_cast<std::chrono::milliseconds>(used_time).count() << std::endl;

https://www.cnblogs.com/bianchengnan/p/9478638.html

机器人领域C++/ROS/TCP编程相关推荐

  1. 【机器人操作系统】ROS话题编程

    文章目录 自定义消息的实现过程及说明 一.功能包的创建 二.自定义话题消息 (1)创建自定义消息文件步骤 (2)添加编译选项步骤 三.创建发布者 四.创建订阅者 五.添加编译选项 六.编译运行 (1) ...

  2. 干货:机器人开源操作系统ROS

    导读:前不久,John 为大家介绍过物联网开源操作系统,或许大家还记忆犹新.今天,要介绍的是一款机器人领域的开源操作系统:ROS. 简介 ROS,英文全称 Robot Operating System ...

  3. socket中的TCP编程(调用免费聊天的机器人实现自动回复)

    socket中的TCP编程(调用免费聊天的机器人实现自动回复) 在无聊时间复习了socket编程,写了这个简易代码!!注意要在联网状态下跑 1:服务器模块: import socket import ...

  4. python机器人编程教程入门_机器人操作系统(ROS)入门必备:机器人编程一学就会...

    原标题:机器人操作系统(ROS)入门必备:机器人编程一学就会 ROS经过十几年的发展,已经得到了极大的推广和应用,尤其是在学术界.卡耐基梅隆大学机器人研究所的大部分实验室都是基于ROS编程的,现在所在 ...

  5. 机器人开发--Apollo ROS介绍

    机器人开发--Apollo ROS介绍 1 介绍 1.1 概述 1.2 历程 2 ROS的不足 大数据传输性能瓶颈 单中心的网络存在单点风险(ROS2为分布式避免该问题) 数据格式缺乏向后兼容 3 A ...

  6. 世界机器人领域12个前沿技术趋势

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达本文转自 | 新机器视觉 MIT机器人实验室主任.IEEE.AAAI ...

  7. Java刷题知识点之TCP、UDP、TCP和UDP的区别、socket、TCP编程的客户端一般步骤、TCP编程的服务器端一般步骤、UDP编程的客户端一般步骤、UDP编程的服务器端一般步骤...

    TCP和UDP是两个传输层协议,广泛应用于网络中不同主机之间传输数据.对任何程序员来说,熟悉TCP和UDP的工作方式都是至关重要的.这就是为什么TCP和UDP是一个流行的Java编程面试问题. Jav ...

  8. 客户案例|围观!卡耐基梅隆大学用上中国造?要玩转自主导航机器人领域?

    近日,卡耐基梅隆大学 Safe AI Lab (人工智能安全实验室) 赵鼎教授团队分享了其在自主导航机器人领域的最新研究方向,该项目以开源自主连接和自动化研究车辆平台(OpenCAV Platform ...

  9. 桌面、平板、手机和机器人操作系统(ROS)市场占有率数据和趋势分享(附引用2019版)

    机器人操作系统(ROS)国内用户排名第一!!! 排名第一 桌面和平板操作系统市场基本还是Windows垄断的天下(Desktop.tablet和console). computer 详细数据如下: 1 ...

最新文章

  1. shadow fight 1.6.0 内购
  2. iOS WKWebView ios9以上版本配置 与 设置UserAgent(用户代理), 解决点击web, 客户端接收不到web事件问题...
  3. VIJOS-P1192
  4. vscode如何设置自动保存时自动格式化代码
  5. MYSQL DELETE 别名
  6. golang后端php前端,Golang如何接收前端的参数
  7. C 主导、C++与 C# 为辅,揭秘 Windows 10 源代码!
  8. 【十五分钟Talkshow】如何理解并优化.NET应用程序对内存的使用
  9. MPCCI3.0.5\
  10. mysql合并两个表_MYSQL如何合并两个表
  11. 计算机经常自动关机怎么回事,教你电脑总是自动关机怎么办
  12. h5php大转盘抽奖,Vue.js实现大转盘抽奖总结及实现思路
  13. tkinter将图标写入py文件
  14. 巧用 Linux 定时任务
  15. seo是什么,干什么用,有什么作用(二)
  16. CentOS 7 系统部署之四:磁盘扩容与调整
  17. 【转】4G手机打电话为什么会断网 4G上网和通话不能并存原因分析
  18. GitLab将技术许可极狐公司-JH发行版来了
  19. 用Vue+Node从零开始实现拼多多前后端商城项目 — 记录踩坑之旅(上篇)
  20. 您的计算机无法启动f2,华硕笔记本电脑 开机按f2无法进入BIOS 无法进入安全模式 键盘键位失灵 仅开机键可用...

热门文章

  1. 996工作制职场人身体还能撑多久?
  2. Android8.1 添加修改默认壁纸
  3. 雷军卸任小米有品公司董事,仍持股70%;马斯克决定不加入推特董事会;一加10 Pro内核源代码公布|极客头条
  4. 通过 Colab 下载 Google Driver 上的大文件到内网服务器
  5. Prerender预渲染优化SEO
  6. 阿里云emas远程真机使用指南
  7. 怎么用算法把黄豆、绿豆以及红豆给区分出来,写出 代码。
  8. android 网络mp3格式,Android-使用MediaPlayer播放网络音频并且缓存
  9. java基本微信小程序的汉服租赁平台 uniapp 小程序
  10. CDCE913产生任意频率