纪念社区成立的7周年-梦与实

随风

转眼间创万联社区已经陪伴大家7年了,不知道朋友们是否还记得那个艳阳高照的下午,我们意气风发的在新会一中的操场上讨论着对未来科技的畅想。也许时间早就将一切抹平了,但我依旧清晰记得当时的愿景,希望做一个智能电梯系统或者是远程的煤气中毒报警系统。我和孙,李三人组成了最初的小组,我们奔走于化学实验室和简陋的杂物间,靠着市面上的物联网模块我们终于做出了能够检测和远程手机报警的模块,在孙的邀请下梁充当海报设计,随后余和进也加入到小组中,rslly小组正式形成,这就是我们域名rslly的来源。我们的产品虽然不是很新颖,但凭借着实用和高技术含量(高中生而言)我们顺利进入了区的比赛。成功晋级区的比赛后,我感到了自研的必要性,必须设计出一个属于我们自己的物联网平台和电路板。随后的故事大家也知道了我们凭借着自研的平台和微信交互电气的廉价理念我们拿到了省二的奖项,奠定了社区的基础。

高考之后大家相继进入了各大高校,我们原始的小组齐聚在一起的机会变得非常少了。但疫情阶段的新工具腾讯会议成为了我们新的交流方式,我们社区的性质也开始由比赛团队转变为开源社区,致力于构建Aiot的平台和解决方案。社区得到了比较大的发展,大约在我大三上学期阶段社区规模达到最大,社区设计出来的衍生产物和大量文章得到了比较好的应用和传播。这阶段虽然整体比较好,但却也逐渐显现出了内部团队的管理问题,人数的增多以及缺乏有效的组织,目标逐渐迷失,过大的目标和空的梦想逐渐使得人心离散。到了大三下学期的时候就业压力的逐渐增大,社区逐渐进入了休眠时期,物联网的普及化使得社区的技术已经显得不再先进,我们尝试过植物工厂,鱼菜共生等方案,甚至是数字孪生的激进方案,但团队本身的吸引力明显不如从前,也没有真正产生非常有价值的东西,社区事实上走到了迷茫时期。

随着大模型的横空出世,Zeeland等人的积极探索使得社区空前活跃,虽然由于就业影响,人数不如从前,但是Agent框架以及Ic平台等项目的出现,社区从事实上进入了全新的阶段,以开源项目为主导的阶段。Agent+Iot的构想使得通用Aiot平台成为了从梦想到现实的一大步。我们仍旧在迷雾中探索,但在探索中我们又认识了Rymcu的ronger等人,他们的言行给了我们极大的鼓励,也许我们未必能成为一个真正的开源社区,但这些探索亦足以使得我们感受到了作为一个程序员的浪漫,感谢大家的支持和鼓励,欢迎有同样爱好的朋友加入,我们期待你的加入。ruanrongman/IntelliConnect: A Powerful iot platform core.

ESP32相较于ESP8266物联网领域应用的优势

ESP32是集成2.4GHz Wi-Fi和蓝牙双模的单芯片方案,具有超高的射频性能、稳定性、通用性和可靠性,以及超低的功耗,满足不同的功耗需求,适用于各种物联网应用场景

ESP32系列是ESP8266的升级版,具有比ESP8266更出色的性能以及更优秀的能力。

特性     ESP32ESP8266
处理器核心Xtensa®双核32位 LX6 微处理器Xtensa® 单核 32位 L106
最大时钟频率最高达240MHz最高达160MHz
GPIO引脚数量3417
ADC通道数181
DAC通道数20
UART数32
I2C数2不确定
SPI接口数4不确定
WiFi支持802.11b/g/n802.11b/g/n
蓝牙支持低功耗蓝牙4.2(BLE)不支持  
开发环境MicroPython/Arduino/Esp-idfarduino
ESP32-S和ESP8266功能对比表

ESP32相比于ESP8266功能上的优势

  • 双核处理器,运行效率提高
  • 丰富的I/O接口
  • 支持蓝牙模式
  • 支持多种开发环境

ESP32主要优势在于其集成了Wi-Fi和蓝牙功能,ESP32 可作为独立系统运行应用程序或是主机 MCU 的从设备,通过 SPI / SDIO 或 I2C / UART 接口提供 Wi-Fi 和蓝牙功能,这对于构建物联网或无线控制应用比较方便。我们分享过一篇ESP8266的Wi-Fi功能介绍(https://mp.weixin.qq.com/s/seiJUJV-2KVESwViiNxnmA),本次我们来分享ESP32的蓝牙功能。

蓝牙原理:

蓝牙技术规定每一对设备之间进行蓝牙通讯时,必须一个为主端,另一为从端,才能进行通信,通信时,必须由主端进行查找,发起配对,建链成功后,双方即可收发数据。蓝牙主端设备发起呼叫,首先是查找周围可被查找的蓝牙设备。

主端设备找到从端蓝牙设备后,与从端蓝牙设备进行配对时输入从端设备的PIN 码,也有设备不需要输入PIN码。配对完成后,从端蓝牙设备会记录主端设备的信任信息,此时主端即可向从端设备发起呼叫,已配对的设备在下次呼叫不需要重新配对。已配对的设备,做为从端的蓝牙耳机也可以发起建链请求,但做数据通讯的蓝牙模块一般不发起呼叫。 链路建立成功后,主从两端之间即可进行双向的数据通讯。在通信状态下,主端和从端设备都可以发起断链,断开蓝牙链路。

蓝牙优势:

蓝牙技术利用短距离、低成本的无线连接替代了电缆连接,从而为现存的数据网络和小型的外围设备接口提供了统一的连接。

ESP32-S支持低功耗蓝牙(BLE)

简介

BLE是指低功耗蓝牙(Bluetooth Low Energy),也被称为蓝牙4.0。它是蓝牙技术的一种变体,旨在消耗更少的电量,具有便携性,并且可以在无线传输距离较短的范围内实现低速数据传输。

优点

  • 低功耗:设备大部分时间处于休眠状态,当事件发生需要工作时,才由休眠态唤醒进入工作态,工作完成后又进入休眠态,因此它功耗低;
  • 低延迟:连接速度很快,毫秒级的连接速度;
  • 远距离:长达数百米的通信距离;
  • 低成本:由于其工作在2.4GHz的ISM频段,使用该频段无需向各国的无线电资源管理部门申请许可证,省下了一笔费用;
  • 抗干扰能力强:工作在2.4GHz的ISM频段的设备有很多,当周围处在该频段的设备多了,就会互相造成干扰,因此蓝牙采用了跳频方式来扩展频谱。

协议标准

蓝牙技术联盟(SIG)沿用经典蓝牙的规范内容,为蓝牙低功耗定义了一些profile,一台设备可以使用多个profile,这些profile定义了一个设备在特定应用情景下如何工作,制造商应通过在实现中遵循特定的profile以确保兼容性。对于协议规范要有个大概了解。

应用

  • 智能家居:智能家居各种设备如智能锁、窗帘、家电等能够实现数据互联互通
  • 医疗健康:心率监测仪器、低频按摩器等利用BLE技术进行数据传输和监测
  • 运动健康:智能手表、智能手环等通过BLE技术实时监测用户的运动数据,如步数、心率、卡路里消耗等
  • 工业领域:胎压监测系统利用BLE技术实时监测轮胎的胎压情况
  • 汽车电子:通过在物品上安装BLE标签,企业实时监控物品的位置和状态

传感设备(心跳带、血压计、温度传感器、共享单车锁、智能锁、防丢器、室内定位)

蓝牙比Wi-Fi应用上的优势:

在一些信号不太好的地方使用一些设备,使用蓝牙比Wi-Fi更加方便了,比如我们常见的共享单车扫描解锁就运用低功耗蓝牙智能锁芯,如果单车在偏远的郊区如果单车在比较偏远的郊区信号不好,单车智能锁芯片接收不到云端后台的开锁指令,就会导致开锁失败。

哈啰出行宣布旗下共享单车全面适配北斗-太原新闻网(太原日报报业集团)-太原日报报业集团

这时就需要用到蓝牙通信, 由于蓝牙无须依赖网络系统,而且蓝牙近距离传输上具有精确率、速度快等特点,故而开锁成功率会比网络开锁要快了。

共享单车开锁流程


ESP32在物联网领域的应用

  • 低功耗芯片 ESP32-S3专为物联网(I0T)设备而设计,应用领域包括:
  • 智能家居
  • 工业自动化
  • 智慧农业
  • POS 机
  • 服务机器人
  • 音频设备
  • 通用低功耗IOT传感器集线器
  • 通用低功耗 loT 数据记录器
  • 医疗保健
  • 消费电子产品
  • 摄像头视频流传输
  • USB 设备
  • 语音识别
  • 图像识别
  • Wi-Fi+ 蓝牙网卡
  • 触摸和接近感应

创万联技术分享创万联,社区致力于物联网和人工智能的开源社区论坛。

在物联网方面,本次我们友情推广兄弟社区RYMCU新开源上市的ESP32-DevKitC、RY-STM32F407开发板。

在人工智能方面,本次介绍我们开源的IntelliConnect平台

概述

  • 本项目基于springboot2.7开发,使用spring security作为安全框架
  • 配备物模型和完善的监控模块
  • 支持多种大模型和先进的Agent智能体技术提供出色的AI智能,可以快速搭建智能物联网应用
  • 支持多种iot协议,使用emqx exhook作为mqtt通讯,可扩展性强
  • 支持微信小程序和微信服务号
  • 使用常见的mysql和redis数据库,上手简单
  • 支持时序数据库influxdb

安装运行

  • 安装mysql和redis数据库,高性能运行推荐安装时序数据库influxdb
  • 安装java17环境
  • 修改配置文件application.yaml
  • java -jar IntelliConnect-1.8-SNAPSHOT.jar

项目特色

  • 极简主义,层次分明,符合mvc分层结构
  • 完善的物模型抽象,使得iot开发者可以专注于业务本身
  • AI能力丰富,支持Agent智能体技术,快速开发AI智能应用

项目连接:https://github.com/ruanrongman/IntelliConnect

最后,我们关注人工智能方面时事,2024 年 10 月 8 日,瑞典皇家科学院宣布,将 2024 年诺贝尔物理学奖授予美国普林斯顿大学教授 约翰·J·霍普菲尔德(John J. Hopfield )和加拿大多伦多大学教授杰弗里·E·辛顿( Geoffrey E. Hinton),以表彰他们“在人工神经网络机器学习方面的基础性发现和发明”。

智能体重塑Aiot新时代

随风

Aiot并不是一个很新的概念,物联网本身连接了大量的物理设备,而连接本身并不能带来真正的价值,真正有价值的是其收集的海量数据以及远程控制能力,因此当物联网与AI结合,AI所带来的巨大数据处理能力和规划能力,能够使得物联网应用的优点得到更大的发挥,因此Aiot成了物联网未来发展的重要赛道。

创万联社区很早就关注Aiot的发展,但是前期的Ai通用性不足,模型能力破碎,必须要将针对不同的场景开发不同的模型和算法,这将导致通用物联网平台与AI的结合变得困难,这将极大的约束Aiot的发展,但是大模型和agent技术极大的解决了这一困境,这是因为agent技术具有一定的自主规划能力和通用性,因此可以给场景各异的iot应用赋予通用的AI能力。

然而当前agent框架仍在发展,比较著名的如国外的langchain,国产的agently和promptulate,这些框架主要是给予互联网从业者和通用能力构建的,并不是针对iot的场景进行开发的,因此需要自行开发相应的tools,tools的开发其实看似简单,但实际上开发合适的tools也是一个颇具挑战的工作。

因此创万联根据实际需求,开发出了一款agent+iot的平台inteliconnect,这款平台能够支持常见的物联网协议,支持使用时序数据库influxdb进行时序数据存储以提升存储效率。还搭载有脚本引擎,支持后续的自主脚本开发。关键的是这款平台可以全面支持agent能力引入,开箱即用,下面是其能力展示,后续我们将在github进行开源,我们还将提供了一个开源社区技术交流群,欢迎你来分享知识,交流技术。

欢迎关注我们的社区公众号

谷歌iot core停止运行,chatGPT大火,我们如何看待

wonder

2023年注定是不平凡的一年,年初我们经历了疫情政策的开放,过了一个史上最长寒假。然而科技却并没有停下它的脚步,反而迎来了人工智能的iphone时刻,chatgpt和gpt4以及国内的文心一言,通义千问,这些AI大模型引爆了人们对于人工智能的关注和对人类社会未来的思考。

作为一个人工智能和物联网社区,我们很早就开始关注gpt的发展,chatgpt没有推出前,我们就观察到了gpt系列产品。但令人遗憾的是我们一直觉得ai语言模型不具备很强的推理能力,主要是依赖于语料库进行回答。虽然我们很早就觉得采用语言模型可能是实现AGI以及物联网平台接口的最佳选择,实际我们也是这么做的。我们开发出了家庭安全卫士,它的主要交互方式就是基于语言交互的。但是我们从来就没有想象过语言模型能发展到如此高度,其中的智能涌现令人细思极恐。

人工智能的大火的时候,物联网却遭到了诸多不利消息。谷歌iot core平台将于今年8月正式停止服务。物联网似乎已经成了时代的弃子。iot服务的领域主要是制造业,农业等一些领域。而现有的物联网平台主要是互联网大厂制作,对于行业的垂直理解不够丰富,使得云平台成了中看不中用的东西。并没有发挥出预想的生产力。因此iot的未来必须是结合人工智能,而不是继续像互联网一样的扩张思维。

然而chatgpt诞生之后,小社区和个人已经宣告无力参与Ai的研发。大模型所需要的资金和计算资源都是难以想象的。而我们能做的只能是参与应用开发。将大模型作为AI时代的操作系统,去发挥它的价值,因此我们无需悲观。有了大模型,物联网会得到更好的发展,我们将真正迎来数据时代。

物联网操作系统的任务调度初步认识

随风

任务调度是操作系统的基本功能。任务调度使得用户程序感觉自己在独占cpu。但是cpu是有限的,任务又那么多,操作系统是如何做到合理分配cpu时间的呢。其实rtos基本上是根据优先级抢占式调度,然后如果任务优先级相同就按照时间轮转片调度。

时间轮转片算法并不难,然而我阅读了大量的时间轮转片介绍的博客始终没有具体的硬件实现介绍。大部分博客都是仿真实现,这其实和真实的内核实现有着很大的差距。因为仿真切换你根本没法实现硬件中断机制,而真实的内核是利用中断机制来实现任务调度的。

为什么内核要使用中断机制而不是直接像普通程序那样编写。这其实非常显然,内核调度肯定占用的资源越低越好,实时性越高越好。而中断机制就能提供这样的属性。中断机制可以说是计算机最具革命性的一个设计,它大大提高了计算机系统的响应速度。

当看到利用中断机制的介绍时候我脑海里已经浮现了一种内核调度的实现方法。利用systick中断,systick中断实现流水灯相信大家都曾经编写过,因此想到利用systick来进行任务切换是一种非常自然的想法,只要设置好中断的时间间隔,那么就实现了时间片的设计。事实上tos系统同样利用了systick中断。下面是tos系统时基的入口。

void SysTick_Handler(void)
{
	if (tos_knl_is_running())
  {
    tos_knl_irq_enter();
    tos_tick_handler();
    tos_knl_irq_leave();
  }
}

但是仅仅利用systick中断肯定是要出问题的。因为单片机还要处理其它中断,在Cortex-M3中,如果OS在某个中断活跃时,抢占了该中断,而且又发生了任务调度,并执行了任务,切换到了线程运行模式,将直接触发Fault异常。这肯定是不行的,但你肯定会说不如直接把systick设置为最低优先级不就行了吗?当然可以,异常确实不会发生了,然而你仔细想想会发生什么?

仔细想好像也没问题啊。的确很难想到,但是我们处理中断的流程是怎么样的?第一步是关中断,然后保存现场再开中断,执行程序,最后再关中断,恢复现场然后开中断。这样做就是为了现场不被破坏同时保证更高优先级的中断能够正常被响应。一般OS在调度任务时,也是要关闭中断,也就是进入临界区,而OS任务调度是要耗时的,这就会出现一种情况:
在任务调度期间,如果新的外部中断发生,CPU将不能够快速响应处理。这对于智能驾驶这样的场景你能忍受吗?

到了这里你似乎走到了穷途末路。的确只利用systick在软件层面已经没有更好的办法了。但是狡猾的内核大佬利用了一个叫做pendsv的中断,这个中断很奇怪,它能够像普通外设中断一样悬起。它是系统级别的异常,但它又天生支持缓期执行。有了它我们就能轻松避免了不能快速处理的问题,pendsv会自动等待所有的中断处理完毕再进行任务切换的操作。

到了这里我们已经得到了一种较为成熟的os调度方案。

  1. 滴答定时器中断,制作业务调度前的判断工作,不做任务切换。
  2. 触发PendSV,PendSV并不会立即执行,因为PendSV的优先级最低,如果此时正好有中断请求,那么先响应中断,最后等到所有优先级高于PendSV的中断都执行完毕,再执行PendSV,进行任务调度。

那么tos系统也是这样实现的吗?我们看看源码。那么我们要启动tos系统,入口肯定要调用启动的api,源代码api头文件注释是get the kernel start to run, which means start the multitask scheduling.中文意思就是启动内核,意味着启动多任务调度。

__API__ k_err_t tos_knl_start(void)
{
    if (tos_knl_is_running()) {
        return K_ERR_KNL_RUNNING;
    }

    k_next_task = readyqueue_highest_ready_task_get();
    k_curr_task = k_next_task;
    k_knl_state = KNL_STATE_RUNNING;
    cpu_sched_start();

    return K_ERR_NONE;
}

可以看到前几行都是检测和获取任务的一些信息,重点在于 cpu_sched_start() ,这个是用来启动cpu任务调度的。刚才那个加了宏_api_表明它还是属于用户api,下面正式进入内核世界。

可奇怪的是它的实现c文件很短,就又调用了一个函数 port_sched_start 。

__KERNEL__ void cpu_sched_start(void)
{
    port_sched_start();
}

继续前进已经没有c文件了,迎面而来的是汇编语言。我熟悉8051汇编,但是对于arm的汇编,我并不是很熟悉,但是又不是考试,还是可以查手册的。粗略看了看,大概知道这是一段很重要的代码。

NVIC_INT_CTRL   EQU     0xE000ED04                              ; Interrupt control state register.
NVIC_SYSPRI14   EQU     0xE000ED20                              ; System priority register (priority 14).
NVIC_PENDSV_PRI EQU     0x00FF0000                              ; PendSV priority value (lowest).
NVIC_PENDSVSET  EQU     0x10000000                              ; Value to trigger PendSV exception.

我们看一下注释,这不就是设置pendsv为设置为最低优先级吗,到这里我们还不清楚它与systick的关系,但至少已经证实它肯定利用了pendsv。幸运的是我滚动一下鼠标就发现的

pendsv的中断处理子程序(汇编我们还是不要叫函数吧)

这段代码很复杂,但是只要有点51单片机的功底,还是猜得出它在干什么,其实就是操作系统最重要的工作,任务堆栈的切换。它借用了寄存器实现的现场的保护。至此我们完全证明tos系统利用pendsv进行上下文切换。

我们还看到这样一段注释

@ set pendsv priority lowest
@ otherwise trigger pendsv in port_irq_context_switch will cause a context swich in irq
@ that would be a disaster

翻译过来跟我们上面描述的完全一致。

我们再去找systick,得到了这个函数

__API__ void tos_tick_handler(void)
{
    if (unlikely(!tos_knl_is_running())) {
        return;
    }

    tick_update((k_tick_t)1u);

#if TOS_CFG_TIMER_EN > 0u && TOS_CFG_TIMER_AS_PROC > 0u
    timer_update();
#endif

#if TOS_CFG_ROUND_ROBIN_EN > 0u
    robin_sched(k_curr_task->prio);
#endif
}

unlikely这是内核的一种优化函数,暂时不用管它,我们全力看 robin_sched ()函数。

__KERNEL__ void robin_sched(k_prio_t prio)
{
    TOS_CPU_CPSR_ALLOC();
    k_task_t *task;

    if (k_robin_state != TOS_ROBIN_STATE_ENABLED) {
        return;
    }

    TOS_CPU_INT_DISABLE();

    task = readyqueue_first_task_get(prio);
    if (!task || knl_is_idle(task)) {
        TOS_CPU_INT_ENABLE();
        return;
    }

    if (readyqueue_is_prio_onlyone(prio)) {
        TOS_CPU_INT_ENABLE();
        return;
    }

    if (knl_is_sched_locked()) {
        TOS_CPU_INT_ENABLE();
        return;
    }

    if (task->timeslice > (k_timeslice_t)0u) {
        --task->timeslice;
    }

    if (task->timeslice > (k_timeslice_t)0u) {
        TOS_CPU_INT_ENABLE();
        return;
    }

    readyqueue_move_head_to_tail(k_curr_task->prio);

    task = readyqueue_first_task_get(prio);
    if (task->timeslice_reload == (k_timeslice_t)0u) {
        task->timeslice = k_robin_default_timeslice;
    } else {
        task->timeslice = task->timeslice_reload;
    }

    TOS_CPU_INT_ENABLE();
    knl_sched();
}

从源码中可以看到,时间片调度算法的实现非常简单,当时钟节拍来临的时候,将就绪列表中第一个任务控制块的时间片值递减,如果递减到0,则移到就绪列表的队尾去,让出此次执行机会,内核发生调度。我们重点看 knl_sched()函数。

__KERNEL__ void knl_sched(void)
{
    TOS_CPU_CPSR_ALLOC();

    if (knl_is_inirq()) {
        return;
    }

    if (knl_is_sched_locked()) {
        return;
    }

    TOS_CPU_INT_DISABLE();
    k_next_task = readyqueue_highest_ready_task_get();
    if (knl_is_self(k_next_task)) {
        TOS_CPU_INT_ENABLE();
        return;
    }

    cpu_context_switch();
    TOS_CPU_INT_ENABLE();
}

这个就是检查一下当前是否有中断发生,还有检查一下锁是否释放,然后调用函数 TOS_CPU_INT_DISABLE()关闭中断,调用 cpu_context_switch() 进行上下文切换。不出意外,终点一定是汇编实现。

果然我们已经离开了c语言世界,进入汇编世界。看代码

port_context_switch
    LDR     R0, =NVIC_INT_CTRL
    LDR     R1, =NVIC_PENDSVSET
    STR     R1, [R0]
    BX      LR

这是什么?这是什么?触发pendsv异常,到了这里我们已经破解了tos系统的任务调度器的基本原理。这表明tos系统和freertos的实现机制是大差不差的。

内核是非常复杂的东西,我们一定要充满敬畏,不要随意去修改,但是了解内核还是很有必要的,否则应用层的很多东西我们理解可能都是错误的。在此,真的太佩服太佩服内核大佬了,瞬间觉得应用层开发那点困难不算什么了。

最后来个传送门

物联网操作系统的初步探索

随风

近几年物联网飞速发展,市面上也出现了很多物联网操作系统。比较有名的有rt-thread,tencentos-tiny以及鸿蒙等。这些物联网系统各有差异,这符合物联网碎片化的生态现状。下面我将以tencentos-tiny为例子分析一下目前物联网操作系统的一些特点。

打开tencentos-tiny的官网,映入眼帘的是比较熟悉的代码结构。分别是内核,驱动,网络以及一些辅助的工具,这和大多数的嵌入式操作系统是类似的。

我们再来看看下面这张图。

这张图是tos系统官网给出的架构,可以看出它的模块化设计是非常优秀的。内核只包含了最为重要的特性,即任务调度,时间以及内存管理,以及ipc通讯的组件。而物联网的工具箱则被放置于内核之外。我们用vscode阅读一下它的内核源码。

可以看到它的确非常的精简,每个功能的实现代码有些甚至只有几百行。这样精简的实现,使得它可以轻松移植到stm32f1这样的芯片。

但是如果进行全量移植的话,f1这样的芯片内存空间仍然不是很足,但是tos系统可以轻松的裁剪,移植的体验也非常不错,如果你不需要其它的功能的话,你只需要把kernel和arch目录以及tos_config复制到你的工程就行了,当然你还得进行一些微调,比如系统时钟脉冲设置,但我花了一些时间也就顺利移植成功了。

可能到现在你有个疑问,stm32真的有必要使用操作系统吗?的确,裸机编程能满足大多数场景了,但是如果你想实现实时性很强,任务又非常多的话,使用操作系统的确非常便捷。tos系统采用了抢占式的任务调度。高优先级任务就绪的时候会立即打断低优先级的任务。相同优先级的就是使用时间片调度。这样能保证高优先的任务能优先被处理。tos系统还提供了任务之间通讯的机制,互斥锁,消息队列以及事件机制。这使得基于任务编程成为轻松的事情。否则的话你就只能一个循环加中断或者dma等。这样的cpu利用率以及响应速度都并不能让人非常满意。

tos系统如果仅仅有上述任务调度功能,它就不能称为物联网操作系统,而顶多叫做实时操作系统。tos系统提供了非常强大的网络工具,可以兼容esp8266等众多芯片,提供了一个统一的at指令框架以及各种协议栈的支持。都说抽象是软件的灵魂。tos系统实现了at指令的抽象框架到sal层的抽象框架,从而虚拟出socket接口。有人觉得这不是多此一举吗?这当然不是,实际上这个设计和“一切皆文件”是有异曲同工之妙的。不过由于tos系统是腾讯开发的,它当然要给很便捷的api给自家的iot平台,但这些工具的确方便了物联网的开发。下面引用一下腾讯知乎的一张图,它清晰地阐述了sal接口的好处。

不过说了这么多,sal接口对我的吸引力并没有那么大,实际上我们使用的通讯芯片一般都是确定的一种,并不太可能替换另外一种,但是移植这抽象层占用的flash空间又是真实存在的,因此我倒不如直接at指令来的方便。

物联网操作系统的产生屏蔽了纷繁复杂的物联网硬件,提供了一些较为统一的接口,据说鸿蒙还提供了分布式软总线,但我还没有看过。但是我感觉只靠这样的一个操作系统就能一统江湖,估计还是任重道远。不过我发现了一个有趣的现象,人们正打算在物联网操作系统中提供js引擎。我觉得这个技术未来确实有比较好的前途。我们下次再讨论一下js引擎对于物联网的影响。

最后来个传送门,祝大家元旦快乐。

云原生下挣扎的java

随风

java曾经的确是风光无限,现在也依然热度不减。但眼下的java的确已经面临了严峻的挑战。java语言曾经的面向对象特性和虚拟机特性使得它非常适合大规模的上层应用,更重要的是它是跨平台的,一次编译,到处运行使得java空前成功。

java不是跨平台的第一人,但绝对是那个时代做到最优秀的。在开发简易程度和性能上做到了良好的平衡。但是令人想不到的是,随着科技的发展,那些曾经的独门武功竟然成了巨大的绊脚石。

jvm成就了java。jvm是一种hotspot虚拟机。如果你对jvm有所了解,你一定会惊叹它的博大精深和设计巧妙。jvm的存在,产生了一大批jvm语言,这是因为jvm其实是语言无关的。jvm语言著名的有kotlin,groovy和scala。你只需要实现字节码规范,你就可以驾驭jvm。这为jvm生态打下了坚实基础,同时jvm的jit编译器极大的改善了性能,使得java语言效率远高于python。jvm的线程模型也非常不错,这比python解析器可要高级得多。jvm还有出色的垃圾回收器,你可以用指令选择不同场景下的垃圾回收器。包括串行的,并行的。以及最新的g1垃圾回收器和zgc回收器。这些垃圾回收器已经满足绝大部分场景。基于最新的JDK15来看,“停顿时间不超过10ms”和“支持16TB的堆”这两个目标已经实现,并且官方明确指出JDK15中的ZGC不再是实验性质的垃圾收集器,而且建议投入生产了。

但是风水轮流转,云原生时代的到来,使得java瑟瑟发抖。那些引以为豪的优秀特性变得不再重要,首先是一次编译,到处运行。现在但凡新一点的语言,跨平台已经成为标配,而且不需要拖着一个沉重的jvm。加上docker的流行,环境已经不是什么问题了。在无服务器应用则更惨了,无服务器应用弹性伸缩,依赖于函数模块的快速启动,而jvm启动需要预热,因为jit需要一定的预热时间,加上类加载的设计。这一下好了,启动速度直接龟速。 如果写过springboot你一定对它的启动速度印象深刻。隔壁go语言的启动简直是快如闪电啊。第三就是面向对象机制,使其适合大规模的编程,可惜随着微服务的流行,人们已经不再追求巨石应用,而是切分成一个个小应用。java冗长的语法,怎么比得过函数式的程序语言呢。最后是高并发场景,这是java当年的强项。java凭借着优秀的高并发支持而流行。但是如今它一对一的线程模型加上各种复杂的锁机制,导致新手根本无法上手。而隔壁nodejs根本就是单线程加事件循环,实现了巨大的吞吐量,不需要锁机制,加上js天生容易掌握,java再次完败。

但是java是否就此停止挣扎了呢,当然不可能。java世界看到了威胁,正开始准备一个超级大招-graalvm。有了它我们就不需要jvm这个累赘了。https://www.graalvm.org/

graalvm的官网映入眼帘的就是高性能,云原生,多种语言。下面排着各种语言的logo。这不免让人疑惑,难道它所有语言都支持。不错,它几乎全支持我们常见的语言,这使得我们多种语言互操作变得十分简单。它最重要的功能当然就是解决java的弊端。它实现的java编译为本地二进制代码。双击就能够运行。从而实现了高速启动,使得Java不至于在云原生时代无所适从。配合springnative,你就能实现java云原生场景的快速启动。

graalvm 的设计是令人惊叹的,java不是一种满足封闭原则的语言,它带有很强的动态性。如类加载机制。这些难以通过静态编译实现,但是 graalvm 有自己的独门武功,可以通过多次运行辅助分析出程序里的动态部分。限于篇幅,这里就不再赘述了。

这篇文章涉及到了较多的新名词,但只要阅读了cwl公众号的那篇云计算时代的文章应该还是对这些新名词有一定了解的。这里立一个flag,下篇文章带大家实操 graalvm ,体验一下云原生java的魅力。

最后来个传送门

浅谈物联网平台设计的那些事

随风

物联网发展到了今天,可以说是有了长足的发展。各大科技公司的公有物联网平台纷纷上线,也提供了许多不俗的功能。不过人们也开始发现,物联网时代似乎仍然离我们很远,那究竟是什么阻碍了物联网的发展?

很多人第一印象觉得是算力,通讯技术和电池技术的约束。这样认为也不是没有道理。算力,通讯技术和电池技术确实是物联网技术之中很重要的一环。通讯技术决定了物联网产品是否能够稳定地进行信息传输,算力决定了智能设备的信息处理能力。电池技术则决定了设备的续航时间。但是约束物联网发展的也许并不是这些,而是我们究竟能用物联网做些什么,以及使用物联网究竟能带来哪些根本性的好处。

目前大多数的公有云平台事实上是to c模式的。保罗万象,偏向于监控生产过程。然而实际上我们需要的恰恰是垂直应用场景,也许是智能家居的或者是工业互联网的。智能家居事实上已经比较成熟,但在工业应用物联网上仍然存在不少硬伤,稳定性以及业务多变性。就像蓬勃的互联网一样,不存在一种互联网产品能满足所有需求。互联网只是一个概念,物联网也如此。因此需要有出色的物联网应用,方能发挥物联网的最大价值。而目前物联网应用开发的生态还很薄弱,缺乏相应的框架系统,大部分仅仅只是mqtt实现库,缺乏业务级别的支撑。因此开发者不得不自行设计业务框架。这无疑耗时耗力。

物联网的中间件以及相应的开发模式仍很贫瘠,大部分物联网项目的终点是监控,这无疑难以发挥它本身应有的互联价值。设备之间的联动仍然是难以像设想中的那样完美。资本是逐利的,连接量的提升并不能直接像互联网场景那样获得巨大的商业价值。因此物联网的商业模式并不能直接复制互联网的模式,物联网时代是属于创新者的,创新者将会赢得最后的胜利。

讨厌的npe如何去除

java语言的null大概就像c语言的空指针一样非常讨厌。特别是业务复杂的时候,多层判断简直让人抓狂,kotlin语言就针对这个问题进行了优化。那么作为java语言的编程者是不是就坐以待毙了呢?当然不是。我们可以使用Optional进行优化。

先强调Optional并不能消除null,这是不现实的,也不必要。在不复杂的场合,我们直接判断就可以了。Optional本质上也不是什么黑魔法,它就是一个容器,跟arraylist是一个性质的。因而可以得知,使用它必然产生一定开销,如果是算法比赛这类场景那还是建议不要用了,毕竟输入输出我们都希望多快好省。

Optional作为返回值是非常理想的选择。聪明的你撸了一个非常好的类,但在Optional还没出现之前,你不得不使用null作为某些情况的返回值,最终使得使用者相当抓狂。Optional作为返回值,可以摆脱这一噩梦。业务上需要空值时,不要直接返回null,可以选择使用 Optional.empty()。使用者使用Optional#ifPresent就可以比较好的减少null带来的困扰。

聊聊java并发那些事情

随风

随着摩尔定律日渐失效,多核心编程已经是不得不面对的现实。而java从一开始就设计成了一种支持多线程的语言。那么我们如何使用java来进行多线程程序的编写呢?很简单,一般来说,在java开启一个多线程,我们有三种方法,这几种方法使用场合不一样,并没有孰优孰劣。

1.继承Thread类,这种方法很简单,但是java是单继承的,这阻碍了你业务的继承扩展,因此并不适用于需要继承扩展的场合。

2.实现Runnable接口,这种方法比较灵活而且简单。后面文章也主要使用这种方法。这种方法只需要实现run方法就可以轻松创建一个线程。

3.实现Callable接口,这种方法功能最为强大,可以在任务结束后返回值。call方法还能够抛出异常。而run方法并不能返回值。

下面是创建线程的简单例子。

package com.company;



class MyThread2 implements Runnable{
    private static int count = 0;// 计数器

    @Override
    public void run() {
       synchronized (this) {
           ++count;

           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               e.printStackTrace();
           }
           System.out.println(count);
       }
    }
}
public class test {
    public static void main(String args[]){
         MyThread2 myThread2=new MyThread2();
         Thread t1=new Thread(myThread2,"t1");
         Thread t2=new Thread(myThread2,"t2");
         Thread t3=new Thread(myThread2,"t3");
         t1.start();
         t2.start();
         t3.start();
    }
}

可以看出创建一个线程还是相当的简单的,但令人头疼的其实是线程同步问题。上述代码中++count并不是一个atomic操作。实际上包含了查询,+1和赋值操作,这样的结果就是在并发中会产生所谓的线程同步问题,读者可以试着把同步字段删除。这将会导致结果为333,这与设计的初衷就发生了违背。为什么会这样呢?原因很简单,sleep的时候线程将会被挂起,这样其它线程就会相继进行++count操作然后也被挂起。最后输出的当然是最终的数值3。因此如果我们需要使其线程同步的话,我们需要加上互斥锁,通过锁的竞争确保其同步。但这样的代价是多线程实际上退化了。这样就导致了性能实际上没有提高,反而由于上下文切换等下降了。

可能读者会觉得这样一段小代码没有什么实际用途,其实这种想法是错误的,java springboot controller实际上是单例多线程的,因此如果我们在@controller下使用全局变量将会导致跟上面一样的错误。如果我们做的是购物系统,那么很遗憾,你这个系统将会产生超卖问题。当有人可能会说,我们呢平时crud也没感觉要加锁,其实数据库的事务本来就是atomic的,所以并不需要加锁。因此我们技术人要感谢前人的努力,才使得现在做一个web应用如此简单,但是简单的背后却是tomcat和spring全家桶这样的大黑箱。如果我们不努力研究黑箱的本身,那么最终我们就只能是一个crud程序猿。

最后卖个广告,创万联新一代物联网平台正在火热建设中,其中包含了大量的优秀特性。更安全,接口更加规范,极大提高了“柔性”程度。平台跟项目绑定的时代也许将要彻底告别,我们欢迎各位开源人士的加入,你们的加入是我们组织的福气。让我们共同迎接aiot和数字孪生的美好未来。