上一篇中我们把基本的运行环境搭建完成了,这一篇中,我们实战通过树莓派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. gulp简单使用

    1.安装gulp,由于某些在下不能解决的原因,故使用gulp 3.9.1版本 安装命令: npm install gulp@3.9.1 注意不要直接使用 : npm install gulp 安装,直 ...

  2. CSS技巧(1)· CSS渐变 linear-gradient

    前言: 不论在网页设计中,还是传统的媒介中,各种尺寸,颜色,角度的图案在视觉中无处不在,要想在网页中实现复杂的图案,其过程往往不够理想,过去,我们可以创建一个单独的位图文件,然后每次需要做调整的时候, ...

  3. Spark 学习笔记之 Streaming Window

    Streaming Window: 上图意思:每隔2秒统计前3秒的数据 slideDuration: 2 windowDuration: 3 例子: import org.apache.kafka.c ...

  4. Vue中使用key的作用

    key的作用是为了在diff算法执行时更快的找到对应的节点,提高diff速度 key具有唯一性 vue中循环需加 :key=“唯一标识” ,唯一标识可以使item里面id index 等,因为vue组 ...

  5. 用CSS绘制实体三角形并说明原理

    ;;margin:0 auto;border:6px solid transparent;border-top: 6px solid red;} 1.采用的是均分原理 盒子都是一个矩形或正方形,从形状 ...

  6. 一文掌握在Word中快速编写公式

    在使用Word编写文章时,总会遇到书写数学公式的情况.使用Word的公式输入工具需要频繁地使用鼠标,因而编写公式会显得繁琐麻烦,那么有什么办法可以优雅地在Word中书写公式呢?其实Word早在Word ...

  7. 货物运输 51Nod - 1671

    公元2222年,l国发生了一场战争. 小Y负责领导工人运输物资. 其中有m种物资的运输方案,每种运输方案形如li,ri.表示存在一种货物从li运到ri. 这里有n个城市,第i个城市与第i+1个城市相连 ...

  8. 像艺术家一样思考 Think Like an Artist

    艺术家是如何获得灵感,如何找到自己的独特风格和主题的? 艺术家在绘画.写作.表演或歌唱前不会去征求谁的允许,而是随心而行 要想在数字时代获得满足感,我们需要变得有创造性 1.艺术家富有事业心 艺术家是 ...

  9. drf框架接口文档

    drf框架接口文档 REST framework可以自动帮助我们生成接口文档. 接口文档以网页的方式呈现. 自动接口文档能生成的是继承自APIView及其子类的视图. 一.安装依赖 pip insta ...

  10. python selenium自动化常用关键字

    工具安装: 1.安装python 2.安装selenium库(dos命令下进入selenium-2.53.2存放路径,执行pip install selenium-2.53.2) 3.将浏览器驱动放到 ...