网站内容资源建设,渭南市建设项目,如何打造网站,响应式设计网站怎么做文章目录 1.本方向内学习内容#xff1a;1.1.动作#xff1a;1.1.1.案例接口定义:1.1.2.案例通信模型#xff1a;1.1.3.服务器端代码#xff1a;1.1.4.客户端源代码#xff1a;1.1.5.动作命令行操作#xff1a; 1.2.参数#xff1a;1.2.1.查看参数列表#xff1a;1.2.2… 文章目录 1.本方向内学习内容1.1.动作1.1.1.案例接口定义:1.1.2.案例通信模型1.1.3.服务器端代码1.1.4.客户端源代码1.1.5.动作命令行操作 1.2.参数1.2.1.查看参数列表1.2.2.参数查询与修改1.2.3.参数文件保存与加载 2.本方向外学习内容2.1.Java SE类和对象2.1.1.类定义和使用:2.1.2.类的实例化this引用为什么要有this引用什么是this引用this引用的特性: 2.1.3.对象的构造及初始化2.1.3.1.构造方法 2.1.4.封装2.1.5.包2.1.5.1.自定义包 2.1.6.static: 1.本方向内学习内容
1.1.动作
动作的底层逻辑就是基于服务和话题来实现的。 客户端发送一个运动的目标想让机器人动起来服务器端收到之后就开始控制机器人运动一边运动一边反馈当前的状态如果是一个导航动作这个反馈可能是当前所处的坐标如果是机械臂抓取这个反馈可能又是机械臂的实时姿态。当运动执行结束后服务器再反馈一个动作结束的信息。整个通信过程就此结束。
由2服务和1话题合成 动作的三个通信模块有两个是服务一个是话题当客户端发送运动目标时使用的是服务的请求调用服务器端也会反馈一个应带表示收到命令。动作的反馈过程其实就是一个话题的周期发布服务器端是发布者客户端是订阅者。所以说动作接口数据类型是服务接口数据类型和话题接口数据类型封装而成的新的数据结构。 案例–机器人画圆 假设我们有一个机器人我们希望通过动作的通信方法让机器人转个圈请编程实现动作通信中客户端和服务器端的实现过程。 运行效果
启动两个终端分别运行一下命令启动动作示例的服务端和客户端
$ ros2 run learning_action action_move_server
$ ros2 run learning_action action_move_client终端中我们可以看到客户端发送动作目标之后服务器端开始模拟机器人运动每30度发送一次反馈信息最终完成运动{Result1}并反馈结束运动的信息。
1.1.1.案例接口定义:
ROS2标准接口定义一般是Goal、Result、Feedback。 我找了一会儿但并没有直接找到能够使用的ROS2标准接口定义。仅找到了一个斐波那契示例的接口上述的机器人画圆案例明显不能使用现成的接口于是我们只好自定义如下learning_interface/action/MoveCircle.action
bool enable # 定义动作的目标表示动作开始的指令
---
bool finish # 定义动作的结果表示是否成功执行
---
int32 state # 定义动作的反馈表示当前执行到的位置包含三个部分 第一块是动作的目标enable为true时表示开始运动 第二块是动作的执行结果finish为true表示动作执行完成 第三块是动作的周期反馈表示当前机器人旋转到的角度。 完成定义后还需要在功能包的CMakeLists.txt中配置编译选项让编译器在编译过程中根据接口定义自动生成不同语言的代码
...
find_package(rosidl_default_generators REQUIRED)
rosidl_generate_interfaces(${PROJECT_NAME} action/MoveCircle.action)
...1.1.2.案例通信模型
通信模型就是这样客户端发送给一个动作目标服务器控制机器人开始运动并周期反馈结束后反馈结束信息。
1.1.3.服务器端代码
import time
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
from rclpy.action import ActionServer # ROS2 动作服务器类
from learning_interface.action import MoveCircle # 自定义的圆周运动接口class MoveCircleActionServer(Node):def __init__(self, name):super().__init__(name) # ROS2节点父类初始化self._action_server ActionServer( # 创建动作服务器接口类型、动作名、回调函数self,MoveCircle,move_circle,self.execute_callback)def execute_callback(self, goal_handle): # 执行收到动作目标之后的处理函数self.get_logger().info(Moving circle...)feedback_msg MoveCircle.Feedback() # 创建一个动作反馈信息的消息for i in range(0, 360, 30): # 从0到360度执行圆周运动并周期反馈信息feedback_msg.state i # 创建反馈信息表示当前执行到的角度self.get_logger().info(Publishing feedback: %d % feedback_msg.state)goal_handle.publish_feedback(feedback_msg) # 发布反馈信息time.sleep(0.5)goal_handle.succeed() # 动作执行成功result MoveCircle.Result() # 创建结果消息result.finish True return result # 反馈最终动作执行的结果def main(argsNone): # ROS2节点主入口main函数rclpy.init(argsargs) # ROS2 Python接口初始化node MoveCircleActionServer(action_move_server) # 创建ROS2节点对象并进行初始化rclpy.spin(node) # 循环等待ROS2退出node.destroy_node() # 销毁节点对象rclpy.shutdown() # 关闭ROS2 Python接口
完成代码的编写后需要设置功能包的编译选项让系统知道Python程序的入口打开功能包的setup.py文件加入如下入口点的配置
entry_points{console_scripts: [action_move_server learning_action.action_move_server:main,],},注意格式为触发程序节点名最好和节点名一致 功能包.节点py源代码文件名main
1.1.4.客户端源代码
import rclpy # ROS2 Python接口库
from rclpy.node import Node # ROS2 节点类
from rclpy.action import ActionClient # ROS2 动作客户端类from learning_interface.action import MoveCircle # 自定义的圆周运动接口class MoveCircleActionClient(Node):def __init__(self, name):super().__init__(name) # ROS2节点父类初始化self._action_client ActionClient( # 创建动作客户端接口类型、动作名self, MoveCircle, move_circle) def send_goal(self, enable): # 创建一个发送动作目标的函数goal_msg MoveCircle.Goal() # 创建一个动作目标的消息goal_msg.enable enable # 设置动作目标为使能希望机器人开始运动self._action_client.wait_for_server() # 等待动作的服务器端启动self._send_goal_future self._action_client.send_goal_async( # 异步方式发送动作的目标goal_msg, # 动作目标feedback_callbackself.feedback_callback) # 处理周期反馈消息的回调函数self._send_goal_future.add_done_callback(self.goal_response_callback) # 设置一个服务器收到目标之后反馈时的回调函数def goal_response_callback(self, future): # 创建一个服务器收到目标之后反馈时的回调函数goal_handle future.result() # 接收动作的结果if not goal_handle.accepted: # 如果动作被拒绝执行self.get_logger().info(Goal rejected :()returnself.get_logger().info(Goal accepted :)) # 动作被顺利执行self._get_result_future goal_handle.get_result_async() # 异步获取动作最终执行的结果反馈self._get_result_future.add_done_callback(self.get_result_callback) # 设置一个收到最终结果的回调函数 def get_result_callback(self, future): # 创建一个收到最终结果的回调函数result future.result().result # 读取动作执行的结果self.get_logger().info(Result: {%d} % result.finish) # 日志输出执行结果def feedback_callback(self, feedback_msg): # 创建处理周期反馈消息的回调函数feedback feedback_msg.feedback # 读取反馈的数据self.get_logger().info(Received feedback: {%d} % feedback.state) def main(argsNone): # ROS2节点主入口main函数rclpy.init(argsargs) # ROS2 Python接口初始化node MoveCircleActionClient(action_move_client) # 创建ROS2节点对象并进行初始化node.send_goal(True) # 发送动作目标rclpy.spin(node) # 循环等待ROS2退出node.destroy_node() # 销毁节点对象rclpy.shutdown() # 关闭ROS2 Python接口完成代码的编写后需要设置功能包的编译选项让系统知道Python程序的入口打开功能包的setup.py文件加入如下入口点的配置 entry_points{console_scripts: [action_move_client learning_action.action_move_client:main,action_move_server learning_action.action_move_server:main,],},1.1.5.动作命令行操作
动作的常用命令行操作如下
$ ros2 action list # 查看服务列表
$ ros2 action info action_name # 查看服务数据类型
$ ros2 action send_goal action_name action_type action_data # 发送服务请求
1.2.参数
1.2.1.查看参数列表
$ ros2 param list1.2.2.参数查询与修改
如果想要查询或者修改某个参数的值可以在param命令后边跟get或者set子命令
$ ros2 param describe action_move_client use_sim_time # 查看某个参数的描述信息!
$ ros2 param get action_move_client use_sim_time # 查询某个参数的值
$ ros2 param set action_move_client use_sim_time True # 修改某个参数的值1.2.3.参数文件保存与加载
$ ros2 param dump turtlesim turtlesim.yaml # 将某个节点的参数保存到参数文件中
$ ros2 param load turtlesim turtlesim.yaml # 一次性加载某一个文件中的所有参数
2.本方向外学习内容
2.1.Java SE类和对象
OOP面向对象类型的语言主要依靠对象的交互完成一件事情。我们不用关注具体的实现过程只需要找准对象理清对象之间的交互关系即可。 面向过程 传统的方式注重的是洗衣服的过程少了一个环节可能都不行。
面向对象
以面向对象方式来进行处理就不关注洗衣服的过程具体洗衣机是怎么来洗衣服如何来甩干的用户不用去关心只需要将衣服放进洗衣机倒入洗衣粉启动开关即可通过对象之间的交互来完成的。 注意面向过程和面相对象并不是一门语言而是解决问题的方法没有那个好坏之分都有其专门的应用场景。
2.1.1.类定义和使用:
类是用来对一个实体(对象)来进行描述的主要描述该实体(对象)具有哪些属性(外观尺寸等)哪些功能(用来干 啥)描述完成后计算机就可以识别了。 比如洗衣机它是一个品牌在Java中可以将其看成是一个类别。 属性产品品牌型号产品重量外观尺寸颜色… 功能洗衣烘干、定时… 类的定义格式
// 创建类
class ClassName{
field; // 字段(属性) 或者 成员变量
method; // 行为 或者 成员方法
}class为定义类的关键字ClassName为类的名字{}中为类的主体。 类中包含的内容称为类的成员。属性主要是用来描述类的称之为类的成员属性或者类成员变量。方法主要说明类具有哪些功能称为类的成员方法。
class WashMachine{public String brand; // 品牌public String type; // 型号public double weight; // 重量public double length; // 长public double width; // 宽public double height; // 高public String color; // 颜色public void washClothes(){ // 洗衣服System.out.println(洗衣功能);
}public void dryClothes(){ // 脱水System.out.println(脱水功能);
}public void setTime(){ // 定时System.out.println(定时功能);
}
}采用Java语言将洗衣机类在计算机中定义完成经过javac编译之后形成.class文件在JVM的基础上计算机就可以识别了。 注意事项
一般一个文件当中只定义一个类main方法所在的类一般要使用public修饰(注意Eclipse默认会在public修饰的类中找main方法)public修饰的类必须要和文件名相同不要轻易去修改public修饰的类的名称如果要修改通过开发工具修改。类名注意采用大驼峰定义。
2.1.2.类的实例化
定义了一个类就相当于在计算机中定义了一种新的类型与intdouble类似只不过int和double是java语言自带的内置类型而类是用户自定义了一个新的类型比如PetDog类和Student类。它们都是类(一种新定义的类型)有了这些自定义的类型之后就可以使用这些类来定义实例(或者称为对象)。 用类类型创建对象的过程称为类的实例化在java中采用new关键字配合类名来实例化对象。 注意事项 1.new 关键字用于创建一个对象的实例. 2.使用 . 来访问对象中的属性和方法. 3.同一个类可以创建对个实例.
this引用
为什么要有this引用
public class Date {public int year;public int month;public int day;public void setDay(int y, int m, int d){year y;month m;day d;}
public void printDate(){System.out.println(year / month / day);
}
public static void main(String[] args) {
// 构造三个日期类型的对象 d1 d2 d3Date d1 new Date();Date d2 new Date();Date d3 new Date();// 对d1d2d3的日期设置d1.setDay(2020,9,15);d2.setDay(2020,9,16);d3.setDay(2020,9,17);// 打印日期中的内容d1.printDate();d2.printDate();d3.printDate();}
}以上代码定义了一个日期类然后main方法中创建了三个对象并通过Date类中的成员方法对对象进行设置和打 印代码整体逻辑非常简单没有任何问题。 但是细思之下有以下两个疑问 1. 形参名不小心与成员变量名相同
public void setDay(int year, int month, int day){year year;month month;day day;
}三个对象都在调用setDate和printDate函数但是这两个函数中没有任何有关对象的说明setDate和 printDate函数如何知道打印的是那个对象的数据呢
什么是this引用
this引用指向当前对象(成员方法运行时调用该成员方法的对象)在成员方法中所有成员变量的操作都是通过该引用去访问。只不过所有的操作对用户是透明的即用户不需要来传递编译器自动完成。
public class Date {public int year;public int month;public int day;public void setDay(int year, int month, int day){this.year year;this.month month;this.day day;}
public void printDate(){System.out.println(this.year / this.month / this.day);}
}this引用的特性:
this的类型对应类类型引用即哪个对象调用就是哪个对象的引用类型。this只能在成员方法中使用。在成员方法中this只能引用当前对象不能再引用其他对象。this是“成员方法”第一个隐藏的参数编译器会自动传递在成员方法执行时编译器会负责将调用成员方法 对象的引用传递给该成员方法this负责来接收。 2.1.3.对象的构造及初始化
通过前面知识点的学习得知在Java方法内部定义一个局部变量时必须要初始化否则会编译失败。
2.1.3.1.构造方法
构造方法(也称为构造器)是一个特殊的成员方法名字必须与类名相同在创建对象时由编译器自动调用并且在整个对象的生命周期内只调用一次
public class Date {public int year;public int month;public int day;// 构造方法// 名字与类名相同没有返回值类型设置为void也不行// 一般情况下使用public修饰// 在创建对象时由编译器自动调用并且在对象的生命周期内只调用一次
public Date(int year, int month, int day){this.year year;this.month month;this.day day;System.out.println(Date(int,int,int)方法被调用了);
}
public void printDate(){System.out.println(year - month - day);
}
public static void main(String[] args) {// 此处创建了一个Date类型的对象并没有显式调用构造方法Date d new Date(2021,6,9); // 输出Date(int,int,int)方法被调用了d.printDate(); // 2021-6-9}
}特性
名字必须与类名相同。没有返回值类型设置为void也不行。创建对象时由编译器自动调用并且在对象的生命周期内只调用一次(相当于人的出生每个人只能出生一次)构造方法可以重载(用户根据自己的需求提供不同参数的构造方法)如果用户没有显式定义编译器会生成一份默认的构造方法生成的默认构造方法一定是无参的。
public class Date {public int year;public int month;public int day;public void printDate(){System.out.println(year - month - day);
}
public static void main(String[] args) {Date d new Date();d.printDate();}
}上述Date类中没有定义任何构造方法编译器会默认生成一个不带参数的构造方法。 注意一旦用户定义编译器则不再生成。
构造方法中可以通过this调用其他构造方法来简化代码 public class Date {public int year;public int month;public int day;// 无参构造方法--内部给各个成员赋值初始值该部分功能与三个参数的构造方法重复// 此处可以在无参构造方法中通过this调用带有三个参数的构造方法// 但是this(1900,1,1);必须是构造方法中第一条语句
public Date(){//System.out.println(year); 注释取消掉编译会失败this(1900, 1, 1);//this.year 1900;//this.month 1;//this.day 1;
}
// 带有三个参数的构造方法
public Date(int year, int month, int day) {this.year year;this.month month;this.day day;}
}注意 this(…)必须是构造方法中第一条语句
2.1.4.封装
面向对象程序三大特性封装、继承、多态。而类和对象阶段主要研究的就是封装特性。何为封装呢简单来说就是套壳屏蔽细节。 Java中主要通过类和访问权限来实现封装类可以将数据以及封装数据的方法结合在一起更符合人类对事物的认知而访问权限用来控制方法或者字段能否直接在类外使用。Java中提供了四种访问限定符 比如 public可以理解为一个人的外貌特征谁都可以看得到 protected:主要是用在继承中继承部分详细介绍 default(默认): 对于自己家族中(同一个包中)不是什么秘密对于其他人来说就是隐私了 private只有自己知道其他人都不知道
public class Computer {private String cpu; // cpuprivate String memory; // 内存public String screen; // 屏幕String brand; // 品牌----default属性
public Computer(String brand, String cpu, String memory, String screen) {this.brand brand;this.cpu cpu;this.memory memory;this.screen screen;
}public void Boot(){System.out.println(开机~~~);
}public void PowerOff(){System.out.println(关机~~~);
}public void SurfInternet(){System.out.println(上网~~~);}
}
public class TestComputer {public static void main(String[] args) {Computer p new Computer(HW, i7, 8G, 13*14);System.out.println(p.brand); // default属性只能被本包中类访问System.out.println(p.screen); // public属性 可以任何其他类访问
// System.out.println(p.cpu); // private属性只能在Computer类中访问不能被其他类访问
}
}注意一般情况下成员变量设置为private成员方法设置为public。
2.1.5.包
在面向对象体系中提出了一个软件包的概念即为了更好的管理类把多个类收集在一起成为一组称为软件包。有点类似于目录,与Ros中的功能包。比如为了更好的管理电脑中的歌曲一种好的方式就是将相同属性的歌曲放在相同文件下也可以对某个文件夹下的音乐进行更详细的分类。 在Java中也引入了包包是对类、接口等的封装机制的体现是一种对类或者接口等的很好的组织方式比如一个包中的类不想被其他包中的类使用。包还有一个重要的作用在同一个工程中允许存在相同名称的类只要处在不同的包中即可。 简单来说许多类放在一个包packag中类是文件类的上级目录就是包文件夹而许多包又可以进行分类和整合。上面说的同一包是指和该类并列的类的集合的最小目录文件夹/包。 比如Test.java是文件 com.test是文件夹。文件要放在文件夹内。com.test.Test.java才是一个文件的绝对地址。 建议显式的指定要导入的类名. 否则容易出现冲突的情况. 在这种情况下需要使用完整的类名
import java.util.*;
import java.sql.*;
public class Test {public static void main(String[] args) {java.util.Date date new java.util.Date();System.out.println(date.getTime());
}
}可以使用import static导入包中静态的方法和字段
import static java.lang.Math.*;
public class Test {public static void main(String[] args) {double x 30;double y 40;// 静态导入的方式写起来更方便一些.// double result Math.sqrt(Math.pow(x, 2) Math.pow(y, 2));double result sqrt(pow(x, 2) pow(y, 2));System.out.println(result);}
}2.1.5.1.自定义包
基本规则 在文件的最上方加上一个 package 语句指定该代码在哪个包中. 包名需要尽量指定成唯一的名字,通常会用公司的域名的颠倒形式(例如 com.hel.demo1). 包名要和代码路径相匹配. 例如创建 com.hel.demo1 的包, 那么会存在一个对应的路径 com/hel/demo1 来存储代码. 如果一个类没有 package 语句, 则该类被放到一个默认包中 操作步骤:
在 IDEA 中先新建一个包: 右键 src - 新建 - 包 在弹出的对话框中输入包名, 例如 com.hel.demo1在包中创建类, 右键包名 - 新建 - 类, 然后输入类名即可.
2.1.6.static:
static修饰的成员变量称为静态成员变量静态成员变量最大的特性不属于某个具体的对象是所有对象所共享的。
【静态成员变量特性】
不属于某个具体的对象是类的属性所有对象共享的不存储在某个对象的空间中既可以通过对象访问也可以通过类名访问但一般更推荐使用类名访问类变量存储在方法区当中生命周期伴随类的一生(即随类的加载而创建随类的卸载而销毁)
Java中被static修饰的成员方法称为静态成员方法是类的方法不是某个对象所特有的。静态成员一般是通过静态方法来访问的。
【静态方法特性】
不属于某个具体的对象是类方法可以通过对象调用也可以通过类名.静态方法名(…)方式调用更推荐使用后者不能在静态方法中访问任何非静态成员变量静态方法中不能调用任何非静态方法因为非静态方法有this参数在静态方法中调用时候无法传递this引用