这是我设计的F450四轴飞行器飞控代码的一部分

运行在orangepi-zero上,操作系统是armbian,思路是使用node-ffi调用wiringpi的so库与GPIO通信,然后控制端逻辑代码使用typescript编写

需要注意的是node-ffi目前不支持node11版本以及以上,我使用的node版本是10

ffi对so库发起调用的效率并不高,但是在这里依然是可以满足通信的需求了

这里使用typescript封装了一个电机类,注释比较多,可以方便参考

下面是电机类

 import { GPIO } from '../gpio';
import WPIFFI from '../wiringpi-ffi'; /**
* 电机类
* 封装了PWM,电调的初始化方法以及电机档位的控制方法
*/
export class Motor {
/**
* 控制电机的GPIO口
*/
private gpio: GPIO;
/**
* 是否已经初始化PWM
*/
private pwmInitialized: boolean;
/**
* 是否已经初始化电调
*/
private controllerInitialized: boolean;
/**
* 当前电机转速档位
*/
private gear: number; /**
* 获取控制电机的GPIO口
*/
public get GPIO(): GPIO {
return this.gpio;
}
/**
* 获取PWM的初始化状态
*/
public get PWMInitialized() {
return this.pwmInitialized;
}
/**
* 获取电调的初始化状态
*/
public get ControllerInitialized() {
return this.controllerInitialized;
}
/**
* 获取电机的初始化状态(PWM且电调)
*/
public get Initialized() {
return this.PWMInitialized && this.ControllerInitialized;
}
/**
* 获取电机的当前档位
*/
public get Gear(): number {
return this.gear;
} /**
* 调用FFI初始化PWM
* @param value 初始化的脉冲宽度值
* @param range 脉冲可调范围
*/
private pwmInit(value: number = 0, range: number = 200) {
console.log(`[${this.gpio}] init: ${value} ${range}`);
if (WPIFFI.softPwmCreate(this.gpio, value, range)) {
throw(new Error(`[${this.gpio}] pwm initialization failed`));
}
}
/**
* 调用FFI设置PWM脉冲
* @param value 脉冲值,默认配置下,此值的范围为[0 ~ 200]
*/
private pulseSet(value: number) {
if (!this.PWMInitialized) {
console.log(`[${this.gpio}] pwm not initialized`);
return;
}
// 设置脉冲
console.log(`[${this.gpio}] set: ${value}`);
WPIFFI.softPwmWrite(this.gpio, value);
} /**
* 初始化PWM,即使能GPIO口的PWM时钟
* 这里设置时钟为200个单位,即:1s / (200 * 100us) = 50hz
*/
public PWMInit(): void {
if (!this.PWMInitialized) {
this.pwmInitialized = true;
this.pwmInit(0, 200);
} else {
console.log(`[${this.gpio}] pwm already initialized`);
}
}
/**
* @async
* 初始化控制电机的电调
* 因为电调初始化协议有时序性,所以这里使用setTimeout异步延时发送初始化信号
* 整个初始化过程会异步等待约10秒钟
* 如不能确定电机状态,请谨慎调用,二次初始化会导致油门开到最大
* 新西达电调的初始化协议,这里简单描述一下
* 1.初始化PWM时钟,使其能在GPIO口产生PWM信号(本程序的PWM频率为:1s / (200 * 100us) = 50hz,11个档位)
* 2.输出2ms的PWM脉冲,为设定的油门最大值
* 3.听到短促的滴滴声音后,输出1ms的PWM脉冲,设定的油门最小值
* 4.等待几秒钟之后,发送1ms~2ms之间的PWM脉冲,即可启动电机
*/
public ControllerInit(): Promise<void> {
return new Promise<void>((resolve, reject) => {
// 如果PWM没有初始化则报错
if (!this.PWMInitialized) {
reject(`[${this.gpio}] pwm not initialized`);
}
// 如果电调并未初始化
if (!this.ControllerInitialized) {
// 这里先设置了标志,防止异步重入的错误
this.controllerInitialized = true;
// 发送高脉冲
this.pulseSet(20);
// 延时发送低脉冲
setTimeout(() => {
this.pulseSet(10);
// 等待初始化完成返回
setTimeout(() => {
resolve();
}, 7000);
}, 3000);
} else {
console.log(`[${this.gpio}] controller already initialized`);
resolve();
}
});
}
/**
* @async
* 初始化电机
* 首先会初始化控制电机的GPIO口以使能PWM信号
* 其次会初始化控制电机的电调并异步等待完成
*/
public async Init(): Promise<void> {
this.PWMInit();
await this.ControllerInit();
}
/**
* 设置电机档位
* @param gear 电机档位,可调范围为[0 ~ 10]
*/
public GearSet(gear: number): void {
if (!this.PWMInitialized) {
console.log(`[${this.gpio}] pwm not initialized`);
return;
}
if (!this.ControllerInitialized) {
console.log(`[${this.gpio}] controller not initialized`);
return;
}
if (gear < 0 || gear > 10) {
console.log(`[${this.gpio}] the range of gear must be [0 ~ 10]`);
return;
}
const floorGear = Math.floor(gear);
// 实际脉冲范围为[10 ~ 20]
const value = floorGear + 10;
// 设置脉冲信号
this.pulseSet(value);
// 写入当前档位
this.gear = floorGear;
}
/**
* 设置电机档位并持续一段时间后退回之前的档位
* @param gear 电机档位,可调范围为[0 ~ 10]
* @param s 档位保持的时间,单位秒,超出此时间之后档位将会退回到之前的状态
* @param keep 是否回退
*/
public GearSetTimeout(
gear: number,
s: number,
keep: boolean = false,
): Promise<void> {
return new Promise<void>((resolve) => {
const ms = Math.floor(s * 1000);
const bakGear = this.gear;
this.GearSet(gear);
setTimeout(() => {
if (!keep) {
this.GearSet(bakGear);
}
resolve();
}, ms);
});
}
/**
* 在控制台输出设备的详情信息
*/
public Detail(): void {
console.log(`GPIO: ${this.GPIO}`);
console.log(`PWMInitialized[true/false]: ${this.PWMInitialized}`);
console.log(`ControllerInitialized[true/false]: ${this.ControllerInitialized}`);
console.log(`Gear[0 ~ 10]: ${this.Gear}`);
}
/**
* @constructor 构造函数,创建一个可用的电机对象
* @param gpio 控制电机的GPIO口,具体请查看实际硬件连接与OrangePi Zero的GPIO定义
*/
public constructor(gpio: GPIO) {
this.gpio = gpio;
this.pwmInitialized = false;
this.controllerInitialized = false;
this.gear = 0;
}
}

新西达电调初始化代码,使用nodejs ffi技术调用wiringpi,代码使用typescript编写的更多相关文章

  1. 使用scala通过JNI技术调用c++代码

    scala代码编写 Sample1.scala class Sample1 { // --- Native methods @native def intMethod(n: Int): Int def ...

  2. 基于.NetCore开发博客项目 StarBlog - (16) 一些新功能 (监控/统计/配置/初始化)

    系列文章 基于.NetCore开发博客项目 StarBlog - (1) 为什么需要自己写一个博客? 基于.NetCore开发博客项目 StarBlog - (2) 环境准备和创建项目 基于.NetC ...

  3. 20.2.翻译系列:EF 6中基于代码的数据库迁移技术【EF 6 Code-First系列】

    原文链接:https://www.entityframeworktutorial.net/code-first/code-based-migration-in-code-first.aspx EF 6 ...

  4. 一行代码搞定Dubbo接口调用

    本文来自网易云社区 作者:吕彦峰 在工作中我们经常遇到关于接口测试的问题,无论是对于QA同学还是开发同学都会有远程接口调用的需求.针对这种问题我研发了一个工具包,专门用于远程Dubbo调用,下面就让我 ...

  5. C++中调用OC代码

    前言 最近项目中为了方便维护,底层统一使用C++编写.由于是项目是做屏幕共享sdk,所以只能底层的压缩.编解码使用C++,屏幕捕获部分Mac和win就自己实现了.那么问题就来了,因为是面向接口编程,所 ...

  6. Matlab与C/C++联合编程之Matlab以MEX方式调用C代码(五)完整过程加示

    如下为本人亲证代码: 一: 编译器的安装与配置(环境不同,显示结果不同) 要使用MATLAB编译器,用户计算机上应用事先安装与MATLAB适配的以下任何一种ANSI C/C++编译器: 5.0.6.0 ...

  7. asp.net调用前台js调用后台代码分享

    asp.net调用前台js调用后台代码分享 C#前台js调用后台代码前台js<script type="text/javascript" language="jav ...

  8. 杯具,万达电商又换CEO

    万达电商CEO再离职.而这距他入职还差一个月才满一年. 昨晚.万达电商CEO董策告诉新浪科技6月3日已正式从万达电商离职.将去往澳洲照应家人.而谈到离职原因和万达电商时,董策以开会为由收了电话. 从2 ...

  9. stm32通过电调带动电机(可按键调速)

    这几天在做32通过电调带动电机的实验,上网一查,发现这方面的资料很少,经过自己的亲自实践,总结出以下经验,供大家参考. 论坛上也有很多人说自己在做,但是都遇到了同样的瓶颈.我想他们大多是pwm的频率和 ...

随机推荐

  1. 怎样获取xhr的当前状态

    一个XMLHttpRequets实例从创建到发起请求再到获取数据, 期间会有一些中间状态, 这些状态是必要的, 我们可以通过判断这些状态值来进行不同的动作. xhr中获取请求状态的属性是: xhr.r ...

  2. C#基础知识 (转)

    https://www.cnblogs.com/zhouzhou-aspnet/articles/2591596.html(原文地址) 本文是一个菜鸟所写,本文面向的人群就是像我这样的小菜鸟,工作一年 ...

  3. 用于Linq的去重 Distinct

            /// <summary>         /// 用于Linq的去重,扩展方法需要放到静态类中         /// </summary>          ...

  4. [JZOJ3521]道路覆盖--状压DP

    题目链接 略略略 分析 首先一看到使得最低的高度最高就想到了二分,于是就转化成了一个是否可行的问题 发现这个\(k\)都很小,考虑使用状态压缩DP 但是我一开始发现似乎并不好设计状态...如果这个\( ...

  5. js中数组方法及分类

    数组的方法有很多,这里简单整理下常用的21种方法,并且根据它们的作用分了类,便于记忆和理解. 根据是否改变原数组,可以分为两大类,两大类又根据不同功能分为几个小类 一.操作使原数组改变   1.数组的 ...

  6. struts-2.5.14.1中jar包引入

  7. 使用postman修改SAP Marketing Cloud contact主数据

    Marketing Cloud里的contact主数据,创建成功后也不是所有字段都能够被修改.在Personal data区域的字段是可以被修改的. 比如我在"客户属性"字段里维护 ...

  8. DDOS 攻击的防范教程--转载自阮一峰的博客

    一个多月前,我的个人网站遭受 DDOS 攻击,下线了50多个小时.这篇文章就来谈谈,如何应对这种攻击. 需要说明的是,我对 DDOS 并不精通,从没想过自己会成为攻击目标.攻击发生以后,很多素昧平生的 ...

  9. SpringMVC【二、项目搭建】

    HelloWorld搭建 1.用Maven WebApp框架创建一个项目 红框中的是后添加的 2.添加pom引用(此处因为要引用多个spring包,建议把版本号提出来放到Properties) 会导入 ...

  10. Image Processing and Analysis_8_Edge Detection:Theory of Edge Detection ——1980

    此主要讨论图像处理与分析.虽然计算机视觉部分的有些内容比如特 征提取等也可以归结到图像分析中来,但鉴于它们与计算机视觉的紧密联系,以 及它们的出处,没有把它们纳入到图像处理与分析中来.同样,这里面也有 ...