上一篇中我们把基本的运行环境搭建完成了,这一篇中,我们实战通过树莓派B+连接HC-SR04超声波测距传感器,用c# GPIO控制传感器完成距离测定,并将距离显示在网页上.

1.HC-SR04接线

  传感器如下图:

  

  HC-SR04 模块可以测量 3cm – 4m 的距离,精确度可以达到 3mm.这个模块包括 超声波发射器、超声波接收器和控制电路三部分.该传感器有4个引脚:

  VCC,   超声波模块电源脚,接5V电源即可

  Trig,  超声波发送脚

  Echo,超声波接收检测脚

  GND,接地

1.1HC-SR04超声波模块工作原理:   

  (1) 树莓派向 Trig 脚发送一个至少 10us 的脉冲信号。
  (2) HC-SR04 接收到信号,开始发送超声波,并把 Echo置为高电平,然后准备接收返回的超声波
  (3) HC-SR04 接收到返回的超声波,把 Echo 置为低电平。
  (4) Echo 高电平持续的时间就是超声波从发射到返回的时间间隔。
  (5) 计算距离:距离(单位:m)  =  (start - end) * 声波速度 / 2

1.2 接线

      4 个引脚由 2 个电源引脚(Vcc 、GND)和 2 个控制引脚(Trig、Echo)组成。
  Vcc 和 Gnd 接 5v DC 电源,但不推荐用独立电源给它供电,应使用树莓派的 GPIO 口输出 5v 和 Gnd 给它供电。不然会影响这个模块的运行。
  Trig 引脚用来接收来自树莓派的控制信号。接任意 GPIO 口。
  Echo 引脚用来发送测距结果给树莓派。接任意 GPIO 口。

  对应树莓派40pin引脚对照表:

我这里把Trlg接到23,Echo接到24,VCC接到5V,(BCM编码方式)GND接GND:

这样线就接好了.开始编码阶段.

2.c# 程序

  打开上一章建立的空项目首先在Models新建一个类 SiteConfig:

 public class SiteConfig
{ /// <summary>
/// 超声波控制端 默认23
/// </summary>
public int TriggerPin { get; set; } /// <summary>
/// 超声波接收端 默认24
/// </summary>
public int EchoPin { get; set; } }

之后在 appsettings.json 中添加 这个节点:

"SiteConfig": {
"TriggerPin": ,
"EchoPin": ,
}

在 Startup.cs 类的ConfigureServices 方法添加

 services.Configure<SiteConfig>(Configuration.GetSection("SiteConfig"));

这样通过依赖注入我们就可以使用我们配置的变量了.这些无关紧要的东西写完后,我们在项目中新建文件夹 Playground 并在这个文件下建立Ultrasonic文件夹:

在Ultrasonic里面建立三个文件 IHcsr04Client.cs,Hcsr04Client.cs,Hcsr04ReadEventArgs.cs

IHcsr04Client:

 public interface IHcsr04Client
{
event EventHandler<Hcsr04ReadEventArgs> OnDataAvailable;
void Start();
void Stop();
}

Hcsr04Client:

 public class Hcsr04Client : IHcsr04Client
{
private readonly int _echo;
private readonly int _trigger;
private int _lastMeasurment = ;
public const int NoObstacleDistance = -;
private readonly object _locker = new object();
private readonly GpioController _controller;
private readonly Stopwatch _timer = new Stopwatch();
public event EventHandler<Hcsr04ReadEventArgs> OnDataAvailable; public bool IsRunning { get; set; } public Hcsr04Client(IOptions<SiteConfig> option, GpioController controller)
{
_echo = option.Value.EchoPin;
_trigger = option.Value.TriggerPin;
_controller = controller;
} public void Start()
{
lock (_locker)
{
IsRunning = true;
if (!_controller.IsPinOpen(_echo))
_controller.OpenPin(_echo, PinMode.Input); if (!_controller.IsPinOpen(_trigger))
{
_controller.OpenPin(_trigger, PinMode.Output);
_controller.Write(_trigger, PinValue.Low);
}
Task.Run(() => PerformContinuousReads());
}
}
public void Stop()
{
lock (_locker)
{
IsRunning = false;
if (_controller.IsPinOpen(_trigger))
_controller.ClosePin(_trigger);
if (_controller.IsPinOpen(_echo))
_controller.ClosePin(_echo);
}
}
private void PerformContinuousReads()
{
while (IsRunning)
{
var sensorData = RetrieveSensorData(); if (!IsRunning) continue;
OnDataAvailable?.Invoke(this, sensorData);
Thread.Sleep();
}
}
private Hcsr04ReadEventArgs RetrieveSensorData()
{
try
{
_timer.Reset(); while (Environment.TickCount - _lastMeasurment < )
{
Thread.Sleep(TimeSpan.FromMilliseconds(Environment.TickCount - _lastMeasurment));
} _controller.Write(_trigger, PinValue.High); // trigger上高电平
Thread.Sleep(TimeSpan.FromMilliseconds(0.01)); // 持续一段时间,发出足够的脉冲
_controller.Write(_trigger, PinValue.Low); // 设置低电平 if (!GpioEX.WaitForValue(_controller, _echo, PinValue.Low)) // echo等待低电平结束,记录时间
throw new TimeoutException(); _lastMeasurment = Environment.TickCount; _timer.Start(); if (!GpioEX.WaitForValue(_controller, _echo, PinValue.High)) // echo等待高电平结束,记录时间
throw new TimeoutException(); _timer.Stop(); TimeSpan elapsed = _timer.Elapsed; var distance = elapsed.TotalMilliseconds / 2.0 * 34.3; return new Hcsr04ReadEventArgs(distance); }
catch
{
return Hcsr04ReadEventArgs.CreateInvalidReading();
} }
}

Hcsr04ReadEventArgs:

 public class Hcsr04ReadEventArgs : EventArgs
{
internal Hcsr04ReadEventArgs(double distance)
{
Distance = distance;
} private Hcsr04ReadEventArgs(bool isValid) : this(Hcsr04Client.NoObstacleDistance)
{
IsValid = isValid;
} /// <summary>
/// 读数是否有效.
/// </summary>
public bool IsValid { get; } = true; /// <summary>
/// 是否检测到任何障碍物.
/// </summary>
public bool HasObstacles => Distance != Hcsr04Client.NoObstacleDistance; /// <summary>
/// 获取到障碍物的实际距离,以厘米为单位.
/// </summary>
public double Distance { get; } internal static Hcsr04ReadEventArgs CreateInvalidReading() => new Hcsr04ReadEventArgs(false);

最后在注入到服务:

 services.AddSingleton<IHcsr04Client, Hcsr04Client>();

代码都非常简单,也有相关注释.大家看一眼就懂了.之后就是网网页上展示了.

先弄一个Controller,在Controllers文件新建一个Hcsr04Controller和CarController的控制器:

 public class Hcsr04Controller : Controller
{
public static string iscsb = "stop";
private readonly IHcsr04Client _hcsr04;
private readonly IHubContext<ChatHub> _chatHub;
public Hcsr04Controller(IHcsr04Client hcsr04, IHubContext<ChatHub> chatHub)
{
_hcsr04 = hcsr04;
_chatHub = chatHub;
}
public async Task<IActionResult> Hcsr04On()
{
_hcsr04.OnDataAvailable += async (s, e) =>
{
if (!e.IsValid)
{
await _chatHub.Clients.All.SendAsync("ReceiveMessage", "", "声波没有返回,被折射掉了.");
}
else if (e.HasObstacles)
{
await _chatHub.Clients.All.SendAsync("ReceiveMessage", "", $"距离:{e.Distance:N2}cm.");
}
else
{
await _chatHub.Clients.All.SendAsync("ReceiveMessage", "", "未检测到障碍物.");
}
};
_hcsr04.Start();
iscsb = "start";
await _chatHub.Clients.All.SendAsync("ReceiveMessage", "", "开启超声波通知.");
return Content("超声波打开");
}
public async Task<IActionResult> Hcsr04Off()
{
_hcsr04.Stop();
iscsb = "stop";
await _chatHub.Clients.All.SendAsync("ReceiveMessage", "", "超声波关闭通知.");
return Content("超声波关闭");
}
}

我这里面使用了signalR,方便数据到达时候在web上面展示,SignalR的内容这里就不说了,就是简单的使用.

CarController就什么都不用改了.之后新建一个视图:

代码:

@{
ViewData["Title"] = "智能小车控制面板";
}
@section Css{
<link href="~/css/car.css" rel="stylesheet" />
}
<div class="text-center">
<h5 class="display-4">控制面板</h5>
<p>温度:<span id="wd">°C</span> 湿度:<span id="sd">%</span></p>
</div>
<ul class="Switch">
<li>
<input type="checkbox" name="Storage" id="csb" onclick="KZCSB(this)" />
超声波
<label for="csb"><em></em></label>
</li>
<li>
<input type="checkbox" name="Storage2" id="bz" onclick="KZBZ(this)" />
红外避障
<label for="bz"><em></em></label>
</li>
<li>
<input type="checkbox" name="Storage2" id="wf" onclick="KZWIFIYK(this)" checked="checked" />
WiFi遥控
<label for="wf"><em></em></label>
</li>
<li>
<input type="checkbox" name="Storage2" id="hw" onclick="KZHWYK(this)" />
红外遥控
<label for="hw"><em></em></label>
</li>
</ul> <div class="control-wrapper">
<div class="control-btn control-top" id="up" onclick="carmove(this,'up')">
<i class="fa fa-chevron-up">∧</i>
<div class="control-inner-btn control-inner"></div>
</div>
<div class="control-btn control-left" id="left" onclick="carmove(this,'left')">
<i class="fa fa-chevron-left"><</i>
<div class="control-inner-btn control-inner"></div>
</div>
<div class="control-btn control-bottom" id="down" onclick="carmove(this,'down')">
<i class="fa fa-chevron-down">∨</i>
<div class="control-inner-btn control-inner"></div>
</div>
<div class="control-btn control-right" id="right" onclick="carmove(this,'right')">
<i class="fa fa-chevron-right">></i>
<div class="control-inner-btn control-inner"></div>
</div>
<div class="control-round" id="pause" onclick="carmove(this,'pause')">
<div class="control-round-inner">
<i class="fa fa-pause-circle">P</i>
</div>
</div>
</div> <div class="c-box">
<div class="c-left">
<h5 style="text-align:center;margin-top:10px;">超声波数据</h5>
<p id="csbdata" style="color:Red;text-align:center"></p>
</div>
<div class="c-right">
<h5 style="text-align:center;margin-top:10px;">红外避障数据</h5>
<p id="bzdata" style="color:Red;text-align:center"></p>
</div>
</div> <div>
<label class="demo--label">
<input class="demo--radio" type="radio" name="demo-radio" checked="checked" value="0.4">
<span class="demo--radioInput"></span>
</label>
<label class="demo--label">
<input class="demo--radio" type="radio" name="demo-radio" value="0.6">
<span class="demo--radioInput"></span>
</label>
<label class="demo--label">
<input class="demo--radio" type="radio" name="demo-radio" value="0.8">
<span class="demo--radioInput"></span>
</label>
<label class="demo--label">
<input class="demo--radio" type="radio" name="demo-radio" value="1.0">
<span class="demo--radioInput"></span>
</label>
</div> @section Scripts{
<script src="~/js/signalr.js"></script>
<script>
$(document).ready(function () {
if (iscsb=="start") {
$("#csb").prop("checked",true);
} else {
$("#csb").prop("checked", false);
} }); // 控制超声波
function KZCSB(th) {
if ($(th).is(':checked')) {
$.get("/Hcsr04/Hcsr04On", function (data) {
iscsb = 'start';
console.log(data);
});
} else {
$.get("/Hcsr04/Hcsr04Off", function (data) {
$("#csbdata").empty();
iscsb = "stop";
console.log(data);
});
}
}
// signalR 接受传感器数据
var connection = new signalR.HubConnectionBuilder().withUrl("/chatHub").build(); connection.on("ReceiveMessage", function (type, msg) {
switch (type) {
case "":
$("#csbdata").text(msg);
break; case "":
$("#csb").prop("checked", true);break;
case "":
$("#csb").prop("checked", false);
$("#csbdata").empty();break;
}
}); connection.start().then(function () { }).catch(function (err) {
return console.error(err.toString());
}); connection.onclose(async () => {
$("#csbdata").empty();
$("#bzdata").empty();
console.info('监听到链接关闭');
await start();
}); async function start() {
try {
await connection.start();
console.log("connected");
} catch (err) {
console.log(err);
setTimeout(() => start(), ); // 断线重连
}
};
</script>
}

编码阶段就完成了,没啥含量,简单粗暴,能用就行.现在我们把代码生成完成把生成的一堆文件都ftp到我们树莓派的目录上面.

在树莓派上我们要重启我们的站点才能生效:

sudo systemctl restart kestrel-carapp.service

之后在浏览器输入树莓派的IP来看效果吧:

  今天超声波模块就弄完了.下一章把红外避障和电机驱动上,让它跑起来

使用asp.net core 3.0 搭建智能小车2的更多相关文章

  1. 使用asp.net core 3.0 搭建智能小车1

    跟随.net core 3.0 一起发布的System.Device.Gpio 1.0已经可以让我们用熟悉的C#原汁原味的开发莓派上面的GPIO了.并且在 Iot.Device.Bindings这个包 ...

  2. asp.net core 2.0+sqlsugar搭建个人网站系列(0)

    一些废话 马上就要过年了,回顾这一年最大的收获就是技术有了很大的提升,其他的方面没有什么改变,现在还是单身小屌丝一枚. 这一年来学习的主要重点就是asp.net core,中间也使用 core+EF做 ...

  3. Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架

    Asp.Net Core 2.0 项目实战(1) NCMVC开源下载了 Asp.Net Core 2.0 项目实战(2)NCMVC一个基于Net Core2.0搭建的角色权限管理开发框架 Asp.Ne ...

  4. win10下ASP.NET Core 2.0部署环境搭建(转)

    此文用于记录在win10环境下,新建的Asp.net Core 2.0 Web应用项目如何运行在IIS上 一.运行环境 操作系统: Window10 家庭中文版 版本 10.0.15063 版本 15 ...

  5. 初识ASP.NET Core 1.0

    本文将对微软下一代ASP.NET框架做个概括性介绍,方便大家进一步熟悉该框架. 在介绍ASP.NET Core 1.0之前有必要澄清一些产品名称及版本号.ASP.NET Core1.0是微软下一代AS ...

  6. ASP.NET Core 1.0 静态文件、路由、自定义中间件、身份验证简介

    概述 ASP.NET Core 1.0是ASP.NET的一个重要的重新设计. 例如,在ASP.NET Core中,使用Middleware编写请求管道. ASP.NET Core中间件对HttpCon ...

  7. 在 Mac OS 上使用 TypeScript 编写 ASP.NET Core 1.0 应用

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...

  8. 【原生态跨平台:ASP.NET Core 1.0(非Mono)在 Ubuntu 14.04 服务器上一对一的配置实现-篇幅1】

    鸡冻人心的2016,微软高产年. build 2016后 各种干货层出不穷. 1 Win10 集成了bash  ,实现了纳德拉的成诺,Microsoft Love Linux!!! 2 跨平台  ,收 ...

  9. ASP.NET Core 使用 JWT 搭建分布式无状态身份验证系统

    为什么使用 Jwt 最近,移动开发的劲头越来越足,学校搞的各种比赛都需要用手机 APP 来撑场面,所以,作为写后端的,很有必要改进一下以往的基于 Session 的身份认证方式了,理由如下: 移动端经 ...

随机推荐

  1. 一步一步带你在VS 2017中配置OpenGL

    在VS2017环境中配置OpenGL,我们分三步:配置GLFW.配置GLAD.导出项目模板. 配置GLFW 1.首先下载GLFW,点击这里,进入Github下载. 或者 点击这里从百度云下载,提取码为 ...

  2. [Python] Python 学习记录(2)

    1.range(x,y) [x,y) >>> range(0,4) #0,1,2,3 >>> range(1,4) #1,2,3 2.dics dics.get(k ...

  3. [WP8.1]RSA 使用BouncyCastle 公钥解密

    写应用的时候遇到个服务器返回私钥加密过的数据 ,然后要在客户端用公钥解密的需求 ,一直没找到方法,应用搁置了一个学期,多方搜索,结论就是.net没有实现公钥解密的方法,要自己实现,于是硬着头皮开始看  ...

  4. SpringBootSecurity学习(20)前后端分离版之OAuth2.0刷新token

    刷新token 前面的例子和配置都是从头开始申请授权码和令牌,现在来看一下如何根据获取令牌时,回参中的 refresh_token 来刷新令牌.现在在项目中配置的是内存模式的默认用户名密码,第一步先改 ...

  5. bat脚本自动安装Jmeter&Jdk

    一句话能解决的事情,绝对不要写一篇文章:一篇文章能解决的事情,绝对不要使用各种工具:一个工具能解决的事情,绝对不要跑东跑西…… 文章主要介绍脚本如何下载.安装.配置Jmeter&Jdk. 不多 ...

  6. .Net Core下使用HtmlAgilityPack解析采集互联网数据

    HtmlAgilityPack应该算是.Net下最好用的html解析库了. 因为最近帮朋友采集一些数据,在nuget里面搜索了好几个库,最后决定就用HtmlAgilityPack.并简单的记录下使用的 ...

  7. display——table-cell属性

    display的table和table-cell一般情况下用的不多,所以很少有人去关注它,但他们两个联手起来会给你惊喜! 当两个或者两个以上标签一起使用显示在同一行时,以前常用的是float.posi ...

  8. 原生js动态创建、获取、删除属性的几种方式

    1.创建属性 <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <ti ...

  9. JVM本地方法栈及native方法

    看到虚拟机栈和本地方法栈的区别的时候有点疑惑,因为本地方法栈为虚拟机的Native方法服务.以下转载一篇关于native方法的介绍: http://blog.csdn.net/wike163/arti ...

  10. [USACO10NOV]奶牛的图片Cow Photographs

    题目描述 Farmer John希望给他的N(1<=N<=100,000)只奶牛拍照片,这样他就可以向他的朋友炫耀他的奶牛. 这N只奶牛被标号为1..N. 在照相的那一天,奶牛们排成了一排 ...