The source code of the automatic watering device with Intel Edison/自动浇花系统源码

Hi All,
I would like share the source code of the automatic watering device.

将之前弄的自动浇花系统源码分享给大家。
代码写的很乱,见笑啦。
为了方便大家阅读,我加上了一些简单的注释,仅供参考。

water.ino

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
#include <Wire.h>

#include <SPI.h>
#include <WiFi.h>

#include <TimerOne.h>
#include "rgb_lcd.h"

rgb_lcd lcd;

const int colorR = 0x00; //0xff;
const int colorG = 0x00;
const int colorB = 0xff;

const int relayPin = 8;

volatile int timer_count = 0; // 定时器中断次数,每次0.1秒

#define humidity_sensor A0 // 湿度传感器接口
#define temperature_sensor A1 // 温度传感器接口
#define pin_buzzer 7 // 蜂鸣器接口
#define use_buzzer true // 是否启动蜂鸣器

#define interval 20 // 定时间隔,以秒为单位
#define water_pump_switch 8 // 控制水泵开关的接口,接继电器 (继电器高电平连通,低电平断开)
#define humidity_threshold 200 // 土壤湿度阈值,低于此值,则土壤偏干,需要灌溉
#define water_pump_duration 6 // 控制水泵灌溉时间,根据水泵水量确定(时间不宜过长,以免水溢出)

// Wifi 设置
char ssid[] = "xxxxx"; // SSID
char pass[] = "xxxxx"; // 无线密码 (use for WPA, or use as key for WEP)
int keyIndex = 0; // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;
//IPAddress server(74,125,232,128); // numeric IP for Google (no DNS)
char server[] = "iot.xxxxxx.com"; // name address for Google (using DNS)

// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
WiFiClient client;

// 枚举 COLOR 类型定义
enum COLOR {COLOR_BLACK, COLOR_BLUE, COLOR_GREEN, COLOR_CYAN, COLOR_RED, COLOR_PINK, COLOR_YELLOW, COLOR_WHITE};


///////////////////////////////////////////////////////
// 名称:setup()
// 作用:程序设置
// 参数:无
// 返回:无
///////////////////////////////////////////////////////
void setup()
{
// 设置串口,用于调试
Serial.begin(9600);

// 设置水泵开关接口,默认关闭
pinMode(water_pump_switch, OUTPUT);
digitalWrite(water_pump_switch, LOW);

pinMode(pin_buzzer, OUTPUT);

// 初始化LCD,设置背光颜色
lcd.begin(16, 2);
//lcd.setRGB(colorR, colorG, colorB);
LCD_SET_COLOR(COLOR_GREEN);

connect_wifi();

// 设置定时器中断触发间隔,以及定时器中断处理函数 (定时器不支持超长时间间隔,所以设置为0.1秒,通过累计触发,实现长时间间隔定时)
Timer1.initialize(100000); // set a timer of length 100000 microseconds (or 0.1 sec - or 10Hz => the led will blink 5 times, 5 cycles of on-and-off, per second)
Timer1.attachInterrupt(timerIsr); // attach the service routine here

// 显示系统名称
lcd.print(" Auto Watering");

// 第一次强制检查,以便更新屏幕显示
check_sensor(true);
}

///////////////////////////////////////////////////////
// 名称:loop()
// 作用:程序主循环
// 参数:无
// 返回:无
///////////////////////////////////////////////////////
void loop()
{
// 进入空闲状态,等待定时事件发生
idle();

// 更新Title显示
title();

// 检查传感器
check_sensor(false);

//get_respond();
}


//*****************************************************
// 以下为子函数
//*****************************************************


///////////////////////////////////////////////////////
// 名称:timerIsr()
// 作用:定时器中断处理函数
// 参数:无
// 返回:无
///////////////////////////////////////////////////////
void timerIsr() {
// 更新定时器中断计数
timer_count++;
}

void timer_rst_counter()
{
timer_count = 0;
}

///////////////////////////////////////////////////////
// 名称:timer_check_delay
// 作用:检查延时功能
// 参数:
// long seconds 延时时间间隔(秒)
// 返回:
// true 大于延时时间间隔
// false 小于延时时间间隔
// 说明:无
///////////////////////////////////////////////////////
bool timer_check_delay(long seconds)
{
if (timer_count >= seconds * 10)
return true;

return false;
}

///////////////////////////////////////////////////////
// 名称:buzzer
// 作用:蜂鸣器功能
// 参数:
// bool on_off (开关:true 开启,false 关闭)
// 返回:无
// 说明:可以通过use_buzzer 控制是否启用蜂鸣器功能
///////////////////////////////////////////////////////
void buzzer(bool on_off)
{
if(!use_buzzer)
return;
digitalWrite(pin_buzzer, on_off?HIGH:LOW);
}

///////////////////////////////////////////////////////
// 名称:LCD_SET_COLOR
// 作用:设置背光颜色
// 参数:
// COLOR color 背光颜色
// 返回:无
///////////////////////////////////////////////////////
void LCD_SET_COLOR(COLOR color) {

byte r, g, b;
r = bitRead(color, 2);
g = bitRead(color, 1);
b = bitRead(color, 0);

r = r * 0xFF;
g = g * 0xFF;
b = b * 0xFF;

lcd.setRGB(r, g, b);
}


///////////////////////////////////////////////////////
// 名称:idle()
// 作用:在LCD右下角显示IDLE...信息,每秒显示一个点
// 参数:无
// 返回:无
///////////////////////////////////////////////////////
void idle()
{
lcd.setCursor(9, 1);
lcd.print("IDLE");

int dot = millis() / 1000 % 4;

lcd.setCursor(13, 1);
switch (dot)
{
case 0:
lcd.print(" "); break;
case 1:
lcd.print(". "); break;
case 2:
lcd.print(".. "); break;
case 3:
lcd.print("..."); break;
}
}


///////////////////////////////////////////////////////
// 名称:working()
// 作用:在LCD右下角显示WORK...信息,每秒显示一个点
// 参数:无
// 返回:无
///////////////////////////////////////////////////////
void working()
{
lcd.setCursor(9, 1);
lcd.print("WORK");

int dot = millis() / 1000 % 4;

lcd.setCursor(13, 1);
switch (dot)
{
case 0:
lcd.print(" "); break;
case 1:
lcd.print(". "); break;
case 2:
lcd.print(".. "); break;
case 3:
lcd.print("..."); break;
}

}

///////////////////////////////////////////////////////
// 名称:title()
// 作用:在LCD右下角显示WORK...信息,每秒显示一个点
// 参数:无
// 返回:无
///////////////////////////////////////////////////////
long s = 0;
void title()
{
char buf[16];
sprintf(buf, "TEMP:%.1f", get_temperature());
long s1 = millis() / 1000;
if (s1 != s) {
s = s1;

if (s%2 == 0){
show_title("Auto Watering", 2);
}
else{
show_title(buf, 2);
}

}
}

///////////////////////////////////////////////////////
// 名称:show_title
// 作用:在1602第一行显示标题
// 参数:
// char *str 标题文本内容
// int space 标题前空格数
// 返回:无
///////////////////////////////////////////////////////
void show_title(char *str, int space)
{
// 清空第一行
lcd.setCursor(0, 0);
lcd.print(" ");

// 显示内容(越过之前空格)
lcd.setCursor(space, 0);
lcd.print(str);
}


///////////////////////////////////////////////////////
// 名称:get_temperature
// 作用:获取温度
// 参数:无
// 返回:
// 温度值 float 类型
///////////////////////////////////////////////////////
float get_temperature()
{
// Define the B-value of the thermistor.
// This value is a property of the thermistor used in the Grove - Temperature Sensor,
// and used to convert from the analog value it measures and a temperature value.
const int B = 3975;

int val = analogRead(temperature_sensor);

// Determine the current resistance of the thermistor based on the sensor value.
float resistance = (float)(1023 - val) * 10000 / val;

// Calculate the temperature based on the resistance value.
float temperature = 1 / (log(resistance / 10000) / B + 1 / 298.15) - 273.15;

return temperature;
}

///////////////////////////////////////////////////////
// 名称:blink_delay
// 作用:延时指定的时间间隔,同时闪烁屏幕,并显示工作信息
// 参数:
// int s 延时时间间隔,单位秒
// 返回:无
///////////////////////////////////////////////////////
void blink_delay(int s)
{
long start = millis();

// 加>= start 防止millis()溢出
while ( ((millis() - start) < 1000 * s ) && millis() >= start) {

// 显示工作信息
working();

// 延时0.1秒
delay(100);

// 交替更新LCD背光
LCD_SET_COLOR(COLOR(millis() / 1000 % 7 + 1));
}
}


///////////////////////////////////////////////////////
// 名称:check_sensor
// 作用:在指定的时间间隔内读取湿度传感器信息
// 判断土壤干燥程度,如果干燥,执行灌溉
// 参数:
// boolean b_force 是否强制检查
// 返回:无
///////////////////////////////////////////////////////
void check_sensor(boolean b_force) {

// Serial.print(timer_count);

// 达到定时时间间隔,读取传感器 0.1秒/count
// if (timer_count >= interval * 10 || b_force) {
if (timer_check_delay(interval) || b_force) {

// 重置定时器计数
// timer_count = 0;
timer_rst_counter();

// 读取土壤湿度传感器
int humidity = analogRead(humidity_sensor);

// 更新湿度显示
update_humidity(humidity);
//Serial.println("AAAA");

// 更新温湿度以及状态信息至网络
char info[256]; //="/water.php?h=0.2&t=28.2&s=1";
sprintf(info, "/water.php?h=%d&t=%f&s=%d", humidity, get_temperature(), (humidity <= humidity_threshold)?1:0);
Serial.println(info);

update_info(server, info);
get_respond();

// 土壤干燥,开始灌溉
if (humidity <= humidity_threshold) {
//Serial.println("BBBB");

// 开启蜂鸣器
buzzer(true);

show_title("Watering...", 4);
LCD_SET_COLOR(COLOR_RED);
water(water_pump_duration);

// 强制调用,更新湿度信息,如果土壤干燥,则继续浇灌
check_sensor(true);
}

// 关闭蜂鸣器
buzzer(false);
LCD_SET_COLOR(COLOR_GREEN);
//water_pump_off();
}

// 显示一些其它信息?
}


///////////////////////////////////////////////////////
// 名称:water
// 作用:灌溉(浇水)指定时长后关闭
// 参数:
// int duration 灌溉时长,单位秒
// 返回:无
///////////////////////////////////////////////////////
void water(int duration) {

// 开启水泵
water_pump_on();

// 持续浇水(已秒为单位),并闪烁屏幕提示用户,显示Work...
//delay(1000* duration);
blink_delay(duration);

// 关闭水泵
water_pump_off();

// To do: 更新操作显示
}


///////////////////////////////////////////////////////
// 名称:water_pump_on
// 作用:开启水泵
// 参数:无
// 返回:无
///////////////////////////////////////////////////////
void water_pump_on() {
digitalWrite(water_pump_switch, HIGH);
}



///////////////////////////////////////////////////////
// 名称:water_pump_off
// 作用:关闭水泵
// 参数:无
// 返回:无
///////////////////////////////////////////////////////
void water_pump_off() {
digitalWrite(water_pump_switch, LOW);
}




///////////////////////////////////////////////////////
// 名称:update_humidity
// 作用:更新湿度显示
// 参数:
// int humidity 湿度
// 返回:无
///////////////////////////////////////////////////////
void update_humidity(int humidity) {
char buf[20];
sprintf(buf, "Val:%04d", humidity);

lcd.setCursor(0, 1);
lcd.print(buf);
}



int num_len(int num) {
if (num == 0)
return 1;

int len = 0;
while (num > 0) {
num = num / 10;
len++;
}
return len;
}

void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());

// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);

// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}

void connect_wifi() {

// check for the presence of the shield:
if (WiFi.status() == WL_NO_SHIELD) {
Serial.println("WiFi shield not present");
// don't continue:
while(true);
}

String fv = WiFi.firmwareVersion();
if( fv != "1.1.0" )
Serial.println("Please upgrade the firmware");

// attempt to connect to Wifi network:
while (status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP network:
status = WiFi.begin(ssid, pass);

// wait 10 seconds for connection:
delay(1000);
}
Serial.println("Connected to wifi");
printWifiStatus();
}

void update_info(char * server, char * msg) {
Serial.println("\nStarting connection to server...");
// if you get a connection, report back via serial:
if (client.connect(server, 80)) {
Serial.println("connected to server");
// Make a HTTP request:
char buf[200];
sprintf(buf, "GET %s HTTP/1.1", msg);
//client.println("GET / HTTP/1.1");
client.println(buf);
client.println("Host: iot.godpub.com");
client.println("Connection: close");
client.println();
}
}

void get_respond() {
// if there are incoming bytes available
// from the server, read them and print them:
while (client.available()) {
char c = client.read();
Serial.write(c);
}

client.stop();

return;

// if the server's disconnected, stop the client:
if (!client.connected()) {
Serial.println();
Serial.println("disconnecting from server.");
client.stop();

// do nothing forevermore:
while(true);
}
}

之前的相关文章:


This page is synchronized from the post: The source code of the automatic watering device with Intel Edison/自动浇花系统源码

基于Intel Edison自动浇花系统的最终报告/The automatic watering device with Intel Edison


(* 这个图拿自baidu.com )

今天有朋友问我,你的自动浇花系统完成的如何了?
突然想起来,在steemit上挖的这个坑还没有填上。
其实这个小装置应该说已经完成了,但是由于我没有花可浇,所以就没真的去买土壤湿度传感器以及水泵之类的。
其实即便是有花可浇,也不舍得花1500人民币弄个浇花装置吧?那得多奢侈啊,哈哈。

好了,把项目总结文档发一下,算是填坑。

系统介绍

基于Intel® Edison的自动浇花系统

自动浇花系统做为作为智能家居的一个很典型的例子,既能解决实际的问题(自动浇花)减轻工作量;又很有学习意义, 其中涉及到传感器数据的读取、以及水泵等装置的控制。

Intel® Edison作为一款低成本片上系统 (SoC) 开发平台,支持发明者、企业家和消费产品设计人员原型构建并开发“物联网”(IoT) 和耐用计算产品。 Edison 模块可与 Edison 分路板或 Arduino Edison 板一起使用。后者可充当 Arduino Rev3 兼容罩的管座。

基于Intel® Edison的自动浇花系统将赋予自动浇花系统更多有意义的特性。

系统功能

  • 采集温度
  • 采集湿度 (通过电位器模拟)
  • LCD显示 (温度、湿度、工作状态等)
  • 控制水泵 (通过继电器)
  • 蜂鸣器报警
  • 定时器精准控制时长
  • 温湿度数据以及灌溉数据上传至网络

系统逻辑

整个系统分两个状态
1) 空闲状态
2) 灌溉状态

空闲状态

  • 液晶屏绿色背光
  • 液晶屏标题栏交替显示系统标题以及温度
  • 液晶屏第二行显示最后获取的湿度数据 并在右侧显示IDLE… 后边的(.)每秒动态变化

灌溉状态

系统按指定时间间隔检测湿度传感器。
当到达指定时间间隔(时间间隔可以通过全局变量设定)

  • 上报温湿度以及是否灌溉信息至网络

当湿度低于阈值,则认为土壤干燥,系统进入到灌溉状态

  • 液晶屏标题栏显示灌溉中
  • 液晶屏第二栏显示湿度数据 以及WORK…后边的(.)每秒动态变化
  • 液晶屏背光7彩闪烁
  • 蜂鸣器报警(可以通过全局变量设定)

为了防止水量溢出,采取多次少量的方案执行灌溉
灌溉持续时间5秒(值可以通过全局变量设定)
到达时间后,重新检测湿度,如果依旧干燥,则继续灌溉(存在风险,湿度传感器失效则灌溉一直持续,可以修改成30分钟只灌溉一次,滴灌效果)

主要技术

  • 土壤湿度传感器读取

土壤湿度传感器通过模拟口连接Edison
通过anologRead读取
详见代码

  • 温度传感器读取

Edison 使用的是NTC加运放的方式实现的温度传感器
通过模拟口连接
通过anologRead读取
并通过B值等进行计算获取
详见代码

  • 蜂鸣器控制

蜂鸣器使用数字口连接,高电平发声音,低电平关闭。
详见代码

  • 继电器控制

继电器使用数字口连接,高电平联通,低电平断开。
详见代码

  • 定时器使用

定时器使用Edison自带的定时器库
但是这个库有些BUG,无法定时较长时间。
所以对这个进行了封装和加强,使其能应用于更长时间控制。
详见代码。

  • RGB背光LCD使用

RGB背光LCD的使用基于西递的函数库
RGB背光LCD使用I2C链接。
西递的函数库部分功能实现的不够优雅,比如设置背光,
对此进行了修改
使其更加方便的应用于此项目。
详见代码。

  • WIFI链接

Edison自带WIFI功能,以及WIFI函数库
我们对此进行了一些小改动,并适度封装。
详见代码。

  • 网络数据发送

温湿度以及是否灌溉信息定时通过HTTP协议上报至网络。
GET请求格式大致如下:
/water.php?h=222&t=28.2&s=1
其中:
H为湿度
T为温度
s为是否执行灌溉
详见代码。

  • 服务器端

服务器端应该实现的功能包括但不限于:
接收并存储数据到数据库
提供展示页面以表格或者其它直观的方式展示数据。

本例中我使用BANAPI M2+ 自建了LMAP网站环境。
使用PHP接收数据。

因为服务器端属于另外的范畴,本例不做深入讨论。
服务器端最简单的示例代码如下:

1
2
3
4
5
6
<?php
printf("Humidity:\t%.2f\n", $_GET['h']);
printf("Temperature:\t%.2f\n", $_GET['t']);
$status = $_GET['s']==0?"False":"True";
printf("Watered:\t%s\n", $status);
?>

主要作用为将Edison发送的数据以一定格式显示。
可用于调试Edison发送网络数据部分。

主要模块

除了上述控制系统外,我们还需要一些模块来完成实际自动浇花应用。
但是因为这些模块比较简单,所以只在控制系统中模拟。

  • 土壤湿度传感器

土壤湿度传感器,使用起来非常简单,上述控制系统中我们使用电位器模拟,实际接线我们和电位器一样接线即可,用其中的AO口(模拟输出)
程序无需调整。

  • 水泵,软管/水箱/供电

实际浇灌需要水泵进行浇水。
水泵部分也比较简单,我们控制系统中用LED模拟,实际上与LED也没有什么区别。

5V水泵,将水泵浸入水箱,用软管连接出水口和花盆土壤。
5V供电,给电则水泵开启,实施灌溉。断电停止。

水箱无需特意购买,用4L的农夫山泉或者其它类似的瓶子即可。

因为Edison IO口推电流比较弱,所以可以用独立电源,找个5V2A以上的电源即可。
连接方式和我们控制系统的连线没区别,唯一供电部分换成独立电源即可。

最后我还缺一盆花。

好吧,就这样吧,坑填上啦。
再也不怕小伙伴们问我进度啦:)


之前的相关文章:


This page is synchronized from the post: 基于Intel Edison自动浇花系统的最终报告/The automatic watering device with Intel Edison

禁用香蕉派BananaPi M3上恼人的绿色LED

BananaPi M3

BananaPi M3是一款类似的 开源硬件单板计算机,具有如下特征:

  • 八核1.8GHz 强力CPU.
  • 2 GB LPDDR3 内存.
  • 8 GB eMMC储存.
  • 板载Wifi & BT.

之前写过几篇文章介绍过这款板卡,详情参见本文底部链接。

恼人的LED

但是这款板卡上有个绿色的LED,默认系统安装上以后,这个LED就闪啊闪的。
这个LED亮度还挺高,尤其是晚上,晃的人睡不着觉。

于是乎,就想能不能关掉这个LED。
QQ群里问了一下专业人士,告诉我用电烙铁把这个LED焊下来
呃,听起来似乎有点不靠谱。

百度一下,找到一个大神的这篇文章

【香蕉派进阶设置】一、关闭那个烦人的绿灯

大意是通过修改内核的配置文件达到关闭板载LED的目的

  • 首先编译bin2fex以及fex2bin两个工具
  • 用bin2fex将script.bin转换成fex格式(文本的配置文件)
  • 修改fex文件,将“leds_used = 1”改为等于0,另一个就是“leds_trigger_1”将双引号中的内容删除为空
  • 再用fex2bin转换回script.bin。

突然想起当年玩M1的时候也这样弄过,尽管也成功了,但是很繁琐。况且不知道是否试用于M3。
有没有更直接更简单的方式呢?

关闭方式

功夫不负有心人啊。
一顿胡乱查找后,终于发现了系统中这样一个目录
/sys/class/leds/green_led

这个是不是和板载LED有关呢?看看目录下都有啥?

1
2
3
4
5
6
7
8
9
-rw-r--r-- 1 root root 4096 Dec 20 12:07 brightness
-rw-r--r-- 1 root root 4096 Dec 20 12:59 delay_off
-rw-r--r-- 1 root root 4096 Dec 20 12:59 delay_on
lrwxrwxrwx 1 root root 0 Dec 20 12:01 device -> ../../../leds-gpio
-r--r--r-- 1 root root 4096 Dec 20 12:01 max_brightness
drwxr-xr-x 2 root root 0 Dec 20 11:56 power
lrwxrwxrwx 1 root root 0 Dec 20 12:01 subsystem -> ../../../../../class/leds
-rw-r--r-- 1 root root 4096 Dec 20 12:58 trigger
-rw-r--r-- 1 root root 4096 Dec 18 20:17 uevent

你一定会问是什么鬼?

经过我一番”苦心孤诣”的调研,总算大致搞明白三五分。

先来说这个brightness

字面上的意思就是亮度啦。这个值的默认值是255
我想当然的认为这个是PWM调制的亮度,实际上这个LED是接到数字口的,也就是说只有开|关两种状态。
传入0关闭,其它非零数字表示设置亮度为开

所以,要关闭LED,我们有个办法就是:

echo 0 > /sys/class/leds/green_led/brightness

看看,恼人的绿色LED是不是灭了??

更进一步

虽然我们已经关闭了这个绿色LED,但是实际上,我们只是把亮度关闭。
举例来说,好比我们开着电脑,但是把显示器关了。

那有没有办法彻底关闭这个LED呢?
让我们来看看/sys/class/leds/green_led/trigger这个文件

1
2
cat /sys/class/leds/green_led/trigger
none battery-charging-or-full battery-charging battery-full battery-charging-blink-full-solid ac-online usb-online rfkill0 mmc0 mmc1 mmc2 timer [heartbeat] backlight gpio default-on sunxi_respiration_trigger rfkill1 rfkill2 rfkill4

默认[heartbeat]这个是选中的
所以这个破LED就像心跳似的一闪一闪的。

1
2
3
注(Bug?): 
设置亮度为0,会改变/sys/class/leds/green_led/trigger 内容,默认为none
重新设置亮度为1,/sys/class/leds/green_led/trigger 内容,依旧为none,但是LED常亮

我们将其恢复默认,然后来看一下:

1
2
echo 255 > /sys/class/leds/green_led/brightness
echo heartbeat > /sys/class/leds/green_led/trigger

是不是又像心跳一样一闪一闪啦?

然后直接关闭
echo none > /sys/class/leds/green_led/trigger
是不是灭啦?并设置

秘籍哦

通过设置成timer,并设置delay_off和delay_on
就可以指定闪烁的时间间隔以及闪烁持续的时间。

更多玩法,你可以自己发掘啊。

我是写累了。

相关文章


This page is synchronized from the post: 禁用香蕉派BananaPi M3上恼人的绿色LED

用Arduino 制作双轮(玩具)自平衡车(四,安装电池等,遇到难题了) / DIY Arduino Two wheeled self balancing vehicle (4)

IMG_20161219_13094431034.jpg

继续我们的玩具自平衡车DIY之旅。
今天遇到一些麻烦,让我极为沮丧。我努力告诫自己,不要焦虑,慢慢来。
好了,不废话,继续。

安装电池

  • 上一篇帖子中我们已经组装好小车的底盘。是这样婶滴:
    IMG_20161217_07021661f02.jpg

  • 电池作为能量系统是必不可少的,前文中我们已经介绍了,使用的是3S航模电池
    IMG_20161217_07085687013.jpg

  • 将电池固定在这个光秃秃的底盘上似乎有点困难?别怕,一根扎带搞定!(背面)
    IMG_20161219_13090629347.jpg

  • 扎带自带粘贴,将电池和底盘绑在一起,粘住就可以了(侧面)
    IMG_20161219_13094431034.jpg

  • 为了方便连接,我用洞洞板把连线接头焊上,这样就可以插拔接线了(俯视)
    IMG_20161219_1312127c535.jpg

难题来了

电池是固定到底盘上了,扎带一绑so easy。
可是剩下的东西该如何固定呢?

我又拿出来一块底板。

  • 把Arduino UNO R3和L298N往上一摆就已经满了。我的MPU6050该往哪里放呢?
    IMG_20161219_131320a4b41.jpg

  • 难不成不用Arduino UNO R3,用Micro或者MINI,但是貌似固定是个问题(三者对比)
    IMG_20161219_13232837bfa.jpg

  • Micro啥的接线不如UNO R3方便,R3接线直接插拔就可以,方便调试。
    IMG_20161219_132350c7b99.jpg

  • Mini除了接线问题,还没有USB转串口调试下载口,这货更麻烦。
    IMG_20161219_13240786392.jpg

  • UNO R3 加扩展板的方式我觉得更蠢!
    IMG_20161219_131807b9f83.jpg

更大的难题

这次为了坚固,选择的金属(据说是铝合金)底板。
现在问题来了,这个板子上边的孔洞过少,我用UNO R3横竖都比过,没有可以直接固定的安装孔。
这下麻烦大了!!!

我需要尝试在金属铁板上打出一些合适的孔来固定我的控制板!

别我问静静是谁?我想静静了。

相关帖子列表


This page is synchronized from the post: 用Arduino 制作双轮(玩具)自平衡车(四,安装电池等,遇到难题了) / DIY Arduino Two wheeled self balancing vehicle (4)

用Arduino 制作双轮(玩具)自平衡车(三,组装底盘) / DIY Arduino Two wheeled self balancing vehicle (3)

IMG_20161217_07021661f02.jpg


今天继续这个双轮(玩具)自平衡车的小项目。
在这个系列相关帖子中,我计划顺便给大家普及一些相关的技术方面的知识。
让大家看完这个系列的帖子后,都能有所收获。
另外写这个帖子的过程也是我重新思索和学习的过程,有问题的话,请大家不吝赐教。


为了避免大家误会,我在标题中加了(玩具)字样。
区别于实际的载人平衡车。
载人的,其实和小的大同小异,只不过换更大的电机,更大容量的电池,原理都是一样的。

昨天我们介绍了制作双轮自平衡车所需要的主要材料
用Arduino 制作双轮自平衡车(二,主要材料) / DIY Arduino Two wheeled self balancing vehicle (2)

今天我们来把底盘组装起来。

组装底盘

  • 首先把带编码器的直流电机拿出来,就是这货
    IMG_20161216_18554359313.jpg

  • 找到电机支架,电机支架用于将电机固定至底盘上。
    IMG_20161216_185855443d6.jpg

  • 将电机固定至电机支架,用螺丝拧紧
    IMG_20161216_19021030734.jpg

  • 然后找到连轴器,所谓的联轴器就是用来把电机轴和车轮连接到一起
    IMG_20161216_1858006d1d9.jpg

  • 将联轴器固定在直流电机的轴上,将螺丝拧紧。(联轴器和电机截面接触部分留出一点缝隙,否则可能会影响转动)
    IMG_20161216_1904223d35e.jpg

  • 车轮,不必多说。此轮子非彼轮子哦。
    IMG_20161216_1858259945e.jpg

  • 将轮子与联轴器固定,这样一个用支架和联轴器固定好的电机轮就诞生啦
    IMG_20161216_1906164a8b2.jpg

  • 底盘的固定板,据说是铝合金的,一块这样的板子就要我18.88大洋啊
    IMG_20161216_185954f5349.jpg

  • 同样方法完成另外一组轮子,并将两组轮子用螺丝固定至底板上。并插好电机联线。
    IMG_20161216_191540039e9.jpg

  • 完工后的底盘
    IMG_20161217_07021661f02.jpg

一个底盘就组装好了,是不是很简单?
接下来的一系列尝试和开发都将是在这个底盘上完成。
(如果再失败,就可能考虑换步进电机了)

相关帖子列表


This page is synchronized from the post: 用Arduino 制作双轮(玩具)自平衡车(三,组装底盘) / DIY Arduino Two wheeled self balancing vehicle (3)

用Arduino 制作双轮自平衡车(二,主要材料) / DIY Arduino Two wheeled self balancing vehicle (2)

IMG_20161217_0703035bc23.jpg


在前文中,我说要直播用Arduino 制作双轮自平衡车
用Arduino 制作双轮自平衡车 / DIY Arduino Two wheeled self balancing vehicle

这个帖子我介绍一下主要材料

关于大小的问题

@myfirst 在上一个帖子中给我回复

历害了,我们小区好多人玩这个,偷懒,走个路还这玩意 :) 你要做出来了,我来做实验,准备摔几次

我给他的回复也顺便贴在这里:

哈哈,我计划做的是玩具平衡车。
如果能成功站起来,我就可以实现前进,后退,旋转等诸多功能。然后加上遥控以及一堆传感器探头,那么一定非常好玩的。

当然,前提是站起来。之前失败过一次,心里有阴影的。

大的,载人的,其实和小的大同小异,只不过换更大的电机,更大容量的电池,原理都是一样的。

简而言之,我做的平衡车不能载人。
当然了,成功的话能载物,一罐可乐啥的还是有可能的。

主要材料

实现一个平衡车的主要材料包含但不限于以下内容:

  • 车架 (车架,连接件,螺丝,铜柱之类乱七八糟的)
  • 能量单元 (就是电池啦,说成能量单元是不是很科幻的感觉)
  • 动力单元 (就是电机啦,这里我依然用直流电机,虽然说步进电机更好控制,但是不是还得重新买嘛)
  • 控制单元 (如果是普通的电动车,有电池有电机了,给电就能跑了,但是平衡车还需要一个大脑)
  • 通讯单元 (用于控制平衡车,初步打算用NRF24L01一类方案,当然也可能上ESP8266之类的WIFI模块)
  • 传感器部分 (超声波等,以后慢慢加吧)

上图啦

有句话叫做不要重复发明轮子,所以买现成的喽
IMG_20161217_0703035bc23.jpg

这货用来支撑车架的铝板,这货居然要18.88一块啊,白花花的银子啊
IMG_20161217_0709214a237.jpg

用来连接几层车架铝板的铜柱。长的短的我买了数千枚,话说管不住手咋办?剁了吗?
IMG_20161217_0710161c6c3.jpg

控制单元,这次我准备用Arduino UNO R3了。据说是山寨版本的,不过其实挺好用的。当然了,不排除用NANO, MINI, MIRCO等替代方案,各种模块我手头都有的。
IMG_20161217_0707537dfc9.jpg

顺便上一个上次失败项目用的Arduino 101,相当贵,也相当强悍,为何失败了呢?一定是我使用的方式不对。
IMG_20161217_0708092de08.jpg

L298N电机驱动模块。控制电机前进后退都指望它了。我手头应该还有另外一款电机驱动模块,据说更好,然而我找不到丫了,等找到的时候可能替换成那个,先放这个图在这吧
IMG_20161217_070828048f2.jpg

核动力电池,呃,开玩笑的啦,据说叫3S航模电池,动力强劲啊。前几天不小心短路了一次,接头的铜片像放烟花一样蒸发了。
IMG_20161217_07085687013.jpg

MPU6050模块 三维角度传感器6DOF 三轴加速度计电子陀螺仪。不敢用BMI160了。
IMG_20161217_19082624abb.jpg

动力就靠它了,传说中的直流电机,带霍尔编码器。
IMG_20161216_18554359313.jpg

其它

其它的比如联轴器啊,导线啊,支架啊啥的,就先不上照片了,太累了。
等做到对应步骤,再慢慢上图吧。
通讯部分和传感器部分暂时还用不到,等小车站起来以后才需要考虑的。
就这样吧,写累了。

相关帖子列表


This page is synchronized from the post: 用Arduino 制作双轮自平衡车(二,主要材料) / DIY Arduino Two wheeled self balancing vehicle (2)

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×