@4th-law/typings-public 中文文档教程
许可证状态:
Typings
4th Law 的 Typings 模块提供了将新模块与 4th Law 框架集成的结构。 Typings 模块包括有关如何格式化传感器配置文件、执行器配置文件、用户输入配置文件和控制模式的信息。
配置文件是一个节点模块,它在某些硬件(例如相机或伺服器)之间创建接口,并允许您的 javascript 或打字稿从所述配置文件发送或接收信息。 这种抽象和模块化级别使得更换新硬件变得更加容易,因为逻辑接口不会改变。 我们将配置文件细分为传感器和执行器,传感器有一个特定的子类,称为用户输入。 模态是为物理平台(例如无人机、自动驾驶汽车或机器人)实例化控制系统的节点模块。
Profiles
如上所述,配置文件有两个类别,由私有 _category 变量标识为“SENSOR”或“ACTUATOR”。 它们还有一个 _type 标识传感器或执行器的类别。 目前有五种执行器,["MECHANICAL", "HYDRAULIC", "PNEUMATIC", "THERMAL", "ELECTRICAL"]
,和14种传感器,["THERMAL" , "电气", "声学", "化学", "环境", "接近", "力", "压力", "光学", "位置", "导航", "离子", "流体", " AUTOMOTIVE"]
,请注意“THERMAL”和“ELECTRICAL”处的重叠。 所有这些都在 NProfile.EType 枚举中指定。
配置文件还具有 _make、_model、_id、_version 和可选的 _specs 变量。 这些描述如下:
- _make is the manufacturer id of your sensor or actuator, and is a string
- _model is the model id of your sensor or actuator, and is a string
- _id is the product id of your sensor or actuator, and is a string
- _version is the version of your profile, formatted as "vX.X.X"
- _sampleInterval is an optional parameter that holds, as number, the period of time in milliseconds between updates to the value of _lastDataPoint, a variable that will be explained in greater detail under the Sensor section.
- _specs, another optional parameter, holds any information that is specific to your sensor or actuator. If there's information like framerate for a camera, you should include it in the _specs object as a key: value pair. For example, the _specs variable for a camera profile might look something like this:
_specs = {
framerate: 25,
width: 200,
height: 100,
}
注意 _category 是 NProfile.ECategory 类型,可以在 typings index.d.ts 文件中找到,它可以是 ACTUATOR 或 SENSOR,而 _type 变量是 NProfile.EType 类型,也可以是在 typings index.d.ts 文件中找到。
_category, _type, _make, _model, _id, _version 都会自动打包成一个对象,由info()函数返回。 如果您在配置文件中定义了 _specs 和/或 _sampleInterval 变量,它们也会自动包含在 info() 返回的对象中。
Sensor
传感器提供一种特定的功能,即提供一个系统(无人机、机器人等)信息,无论是亮度、相机图像、温度、酸度,还是刚刚键入的键。 我们区分了两大类传感器,即常规传感器和输入设备。 这种区别不仅仅是概念上的区别,因为它们各自以不同的方式处理数据。 虽然常规传感器在某种意义上是被动的(用户必须调用才能接收数据),但 InputDevice 是主动的并且将释放您可以捕获的事件。
Regular Sensor
常规传感器有一个名为 _lastDataPoint 的私有变量,它由 data() getter 函数返回,称为 profile.data
。 您必须对传感器配置文件进行编程,以便它以可接受的频率更新 _lastDataPoint 的值。 这意味着如果您过于频繁地调用 data(),您可能会得到重复的值,因为您可能在 _lastDataPoint 有机会更新之前调用了 data()。 或者,如果您以太低的频率调用 data(),您可能无法捕获 _lastDataPoint 的值,即 _lastDataPoint 的值可能在两次调用 data() 之间更新不止一次,这意味着您会丢失那些价值观。 除非您自己将一些逻辑构建到配置文件中,否则您将无法使用此数据。
InputDevice
输入设备的运行逻辑与常规传感器不同。 他们没有使用必须访问的变量,而是使用在构造时传入的 EventEmitter。 在内部,只要有新数据进来(或者你希望对你的配置文件进行编程),事件发射器就会被触发,如果我们有一个外部事件发射器的引用(原则上我们应该有,因为我们传入了它)我们可以用来监听这些事件,并在它们发生时采取行动。 这样,除非事件以某种方式中断,否则我们不会丢失数据,并且没有真正的方法对我们的传感器进行过度采样,因为 IT 将数据发送给我们。
Actuator
执行器配置文件是提供与执行器(例如伺服或直流电机)接口的配置文件。 这些配置文件的基本特征是用作系统的输出设备,因此提供了通过 target() setter 函数设置目标输出值的内置功能,称为 profile.target = targetValue
。 还有一个名为 current() 的函数,称为 currentValue = profile.current
,它返回配置文件的当前输出。 可以让 current() 返回与 target() 相同的值,但增加了这种额外的灵活性,以允许您处理执行器不明智或不可能不连续更改其输出的情况。 因此,您必须自己将逻辑编程到您的配置文件中,以指示 _target 和 _current 变量之间的关系。
NData
数据命名空间定义了您将发送到配置文件和从配置文件接收的数据的结构。
EUnit 枚举指定您可以附加到数据的不同单位,并包含 [METER、METERperSECOND、METERperSECOND2、DEGREE、DEGREEperSECOND, DEGREEperSECOND2],其中 METERperSECOND2 是米每秒的平方,DEGREEperSECOND2 是每平方秒的度数。
NData.IValue 指定一个数字值和一个 EUnit 单位,以帮助避免在您的传感器生成具有不同单位的信息时发生混淆。
NData.ITelemetry 将线性和角位置、速度和加速度指定为
linear_position: {
x: NData.IValue
y: NData.IValue
z: NData.IValue
}
angular_position: {
yaw: NData.IValue
pitch: NData.IValue
roll: NData.IValue
}
linear_velocity: {
x: NData.IValue
y: NData.IValue
z: NData.IValue
}
angular_velocity: {
yaw: NData.IValue
pitch: NData.IValue
roll: NData.IValue
}
linear_acceleration: {
x: NData.IValue
y: NData.IValue
z: NData.IValue
}
angular_acceleration: {
yaw: NData.IValue
pitch: NData.IValue
roll: NData.IValue
}
NData.ITelemetry 还包括有关传感器名称的信息、传感器的特定 ID(从您平台上的其他传感器中挑选出来)、坐标系位置、速度和加速度数据,以及时间戳。 此信息被编码为
name: string
id: string
system: NData.ECoordinateSystem
ts: number
NData.ECoordinateSystem 可帮助您指定您的位置数据是在地理球坐标(纬度和经度)中还是在 bodycentric 笛卡尔坐标中,值为 [GEOSPHERICAL, BODYCARTESIAN]。
还有一个枚举 EDimensionType 由即将提到的 ActuatorInput 接口使用,它指定一个值是指随时间的连续变化(速度)、随时间的离散变化(步数)还是绝对期望的位置。 为方便起见,EDimensionType 枚举如下所示:
enum EDimensionType {
VELOCITY = "VELOCITY", // could be rectilinear, curvilinear, or angular
POSITION = "POSITION", // same as the velocity comment
STEPS = "STEPS", // passes the number of steps a stepper motor needs to move
}
为了帮助组织来自传感器并发送到执行器的信息,我们提供了 ISensor 和 IActuatorInput 接口。
ISensor 接口有名称变量[一个字符串]、一个id 变量[一个字符串]、一个ts 变量[一个数字] 和一个数据变量[任何类型]。 name 包含传感器的名称,id 包含此数据来自您平台上的特定传感器的唯一标识符,ts(时间戳)表示此数据生成的时间,data 变量包含传感器的实际内容数据。
IActuatorInput 接口具有值 [ 数字 ]、类型 [ NProfile.EType ]、维度类型 [EDimensionType] 和可选范围 [ 数组中的两个数字 ] 变量。 该值是执行器实际执行所需的信息,其余信息主要是为了便于在代码中强制执行正确性。 range 变量指定值的边界,因此如果您超出此值,您可以抛出错误或相应地处理事件。
Locations
NData.ITelemetry NData.ISensor NData.IValue NData.EUnit NData.ECoordinateSystem
NProfile.Category NProfile.E类型 NProfile.EDimensionType NProfile.IActuatorInput
License Status:
Typings
4th Law's Typings module provides structure for integrating new modules with 4th Law's framework. The Typings module includes information about how to format Sensor profiles, Actuator profiles, User input profiles, and control Modalities.
A profile is a node module that creates an interface between some piece of hardware, such as a camera or servo, and allows your javascript or typescript to send or receive information from said profile. This level of abstraction and modularity makes it easier to swap new hardware in, since the logical interface doesn't change. We subdivide profiles into Sensors and Actuators, and Sensors have a specific subclass called a User Input. Modalities are node modules that instantiate a control system for a physical platform, such as a drone, self-driving car, or robot.
Profiles
Profiles, as stated above, have two categories, identified by the private _category variable as either "SENSOR" or "ACTUATOR". They also have a _type which identifies the class of sensor or actuator. There are currently five kinds of actuators, ["MECHANICAL", "HYDRAULIC", "PNEUMATIC", "THERMAL", "ELECTRICAL"]
, and 14 kinds of sensors, ["THERMAL", "ELECTRICAL", "ACOUSTIC", "CHEMICAL", "ENVIRONMENTAL", "PROXIMITY", "FORCE", "PRESSURE", "OPTICAL", "POSITIONAL", "NAVIGATIONAL", "IONIC", "FLUIDIC", "AUTOMOTIVE"]
, note the overlap at "THERMAL" and "ELECTRICAL". All of these are specified in the NProfile.EType enum.
Profiles also have a _make, _model, _id, _version, and optional _specs variables. These are described below:
- _make is the manufacturer id of your sensor or actuator, and is a string
- _model is the model id of your sensor or actuator, and is a string
- _id is the product id of your sensor or actuator, and is a string
- _version is the version of your profile, formatted as "vX.X.X"
- _sampleInterval is an optional parameter that holds, as number, the period of time in milliseconds between updates to the value of _lastDataPoint, a variable that will be explained in greater detail under the Sensor section.
- _specs, another optional parameter, holds any information that is specific to your sensor or actuator. If there's information like framerate for a camera, you should include it in the _specs object as a key: value pair. For example, the _specs variable for a camera profile might look something like this:
_specs = {
framerate: 25,
width: 200,
height: 100,
}
Note that _category is of type NProfile.ECategory, which can be found in the typings index.d.ts file and is either ACTUATOR or SENSOR, while the _type variable is of type NProfile.EType, which can also be found in the typings index.d.ts file.
_category, _type, _make, _model, _id, and _version are all automatically packaged into an object, and returned by the info() function. If you define the _specs and/or _sampleInterval variables in your profile, they will also be automatically included in the object returned by info()
Sensor
Sensor provide a specific kind of functionality, which is to provide a system (drone, robot, etc.) with information, whether it be brightness, camera images, temperature, acidity, or what key was just typed. We establish a distinction between two broad types of sensors, regular Sensors and InputDevices. The distinction is more than a conceptual one, because they each handle data in different ways. While a regular sensor is in some sense passive (the user must make a call to receive data), an InputDevice is active and will release an event that you can capture.
Regular Sensor
A regular sensor has a private variable called _lastDataPoint, which is returned by the data() getter function, called as profile.data
. You will have to program the sensor profile so that it updates the value of _lastDataPoint at an acceptable frequency. This means that if you call data() too frequently, you could potentially get duplicate values back, since you could have called data() before _lastDataPoint had a chance to be updated. Alternatively, if you call data() at too LOW a frequency, you could fail to catch values of _lastDataPoint, that is the value of _lastDataPoint could be updated more than once in between two calls of to data(), meaning you would have lost those values. Unless you build in some logic on your own into the profile, this data will not be available to you.
InputDevice
Input Devices operate on a different logic from Regular Sensors. Instead of having a variable that must be accessed, they use an EventEmitter which is passed in at construction. Internally, the event emitter is fired whenever new data comes in (or however you wish to program your profile), and if we have a reference to the event emitter externally (which in principle we should have since we passed it in) which we can use to listen for these events, acting on them as they happen. In this way, unless an event is somehow interrupted, we cannot miss data, and there's no real way to oversample our sensor, since IT sends data to US.
Actuator
Actuator profiles are profiles that provide an interface with an actuator, such as a servo or DC motor. The basic characteristic of these profiles is to serve as output devices for your system, and as such provide built-in functionality for setting target output values through the target() setter function, called as profile.target = targetValue
. There is another function called current(), called as currentValue = profile.current
, which returns the current output of the profile. It's possible to have current() return the same value as target(), but this extra flexibility has been added to allow you to work with cases where it is ill-advised or impossible for your actuator to discontinuously change it's output. Accordingly, you will have to program yourself the logic into your profile that dictates the relationship between the _target and _current variables.
NData
The Data Namespace defines the structure of data that you will be sending to and receiving from your profiles.
The EUnit enum specifies different units you can attach to your data, and contains [METER, METERperSECOND, METERperSECOND2, DEGREE, DEGREEperSECOND, DEGREEperSECOND2], with METERperSECOND2 is meters per second squared, and DEGREEperSECOND2 being degrees per second squared.
NData.IValue specifies a number value and an EUnit unit, to help avoid confusion if you have sensors generating information with different units.
NData.ITelemetry specifies linear and angular positions, velocities, and accelerations as
linear_position: {
x: NData.IValue
y: NData.IValue
z: NData.IValue
}
angular_position: {
yaw: NData.IValue
pitch: NData.IValue
roll: NData.IValue
}
linear_velocity: {
x: NData.IValue
y: NData.IValue
z: NData.IValue
}
angular_velocity: {
yaw: NData.IValue
pitch: NData.IValue
roll: NData.IValue
}
linear_acceleration: {
x: NData.IValue
y: NData.IValue
z: NData.IValue
}
angular_acceleration: {
yaw: NData.IValue
pitch: NData.IValue
roll: NData.IValue
}
NData.ITelemetry also includes information about the name of the sensor, the specific id of the sensor (to pick it out from other sensors on your platform), the coordinate system for the position, velocity, and acceleration data, as well as a timestamp. This information is encoded as
name: string
id: string
system: NData.ECoordinateSystem
ts: number
NData.ECoordinateSystem helps you specify whether your position data is in geospherical coordinates (latitude and longitude) or in bodycentric cartesian coordinates, values are [GEOSPHERICAL, BODYCARTESIAN].
There is also an enum EDimensionType is used by the soon-to-be mentioned ActuatorInput interface that specifies whether a value is meant as a continuous change over time (velocity), a discrete change over time (number of steps), or an absolute desired position. The EDimensionType enum is shown below for convenience:
enum EDimensionType {
VELOCITY = "VELOCITY", // could be rectilinear, curvilinear, or angular
POSITION = "POSITION", // same as the velocity comment
STEPS = "STEPS", // passes the number of steps a stepper motor needs to move
}
To help organize information coming from sensor and being sent to actuators, we provide the ISensor and IActuatorInput interfaces.
The ISensor interface has name variable [ a string ], an id variable [ a string], a ts variable [ a number ] and a data variable [ of any type ]. The name holds the name of the sensor, the id holds the unique identifier of the particular sensor on your platform this data came from, the ts (timestamp) indicates when this data was generated, and the data variable holds the actual contents of the sensor data.
The IActuatorInput interface has value [ a number ], type [ NProfile.EType ], dimensionType [EDimensionType], and optional range [ two number in an array ] variables. The value is the information the actuator needs to actually actuate, the rest of the information is primarily for ease of enforcing correctness in your code. The range variable specifies the boundaries of what value should be, so that in case you go outside this value you can throw an error or handle the event accordingly.
Locations
NData.ITelemetry NData.ISensor NData.IValue NData.EUnit NData.ECoordinateSystem
NProfile.Category NProfile.EType NProfile.EDimensionType NProfile.IActuatorInput