此代码库为MQTT-C(https://mqtt.org/software/ -> Client libraries -> C -> MQTT-C。窦平已clone到http://172.22.85.50/EE-SWDD/GOS/MQTTClient.git )仓库。 examples文件夹里面含有按照供应商HCM运作规则所发CAN信号至HCM的运行脚本lightshow.cpp,里面含有基于examples/simple_subscriber.c的代码,并包含MQTT broker端口信息。
此代码库cJSON文件夹含有cJSON源码(https://github.com/DaveGamble/cJSON ),为解析MQTT信息。
注意:本项目是由ARM架构编译的,x86需要重新编译。以下是相应步骤。
Ubuntu可使用Docker。当拿到Ubuntu image后(terminal可运行docker pull ubuntu),装上以下工具包:
帮助:运行Docker时可使用volume,保证Docker环境代码可修改并同步,例子:docker run -dt --name lightshow -v /Users/mingjieliang/project/lightshow-mqtt:/lightshow-mqtt ubuntu
apt update
apt install build-essential
apt install vim
apt install sudo
apt install net-tools
apt install iproute2 -y
apt install cmake
编译此代码库:
cd /lightshow-mqtt/cJSON/
mkdir build
cd build
cmake ..
make
make install
sudo /sbin/ldconfig -v
#现在可在主目录lightshow-mqtt下运行./lightshow_executor。如修改了lightshow.cpp需要重新编译:
#在主目录ightshow-mqtt(cd ../../)
gcc -c -Wall -g -I include/ src/*
g++ -c -Wall -g -I include/ examples/lightshow.cpp -pthread
g++ -g -o lightshow_executor mqtt.o mqtt_pal.o lightshow.o -pthread -lcjson
#运行:
./lightshow_executor
生成灯光秀的程序为lightshow_operator.rb。lightshow_operator.rb为Ruby脚本;运行前先确保系统已安装Ruby,并运行gem install mqtt
。一切就绪后便可执行ruby lightshow_operator.rb
。lightshow_operator.rb为灯光秀项目的活文档,意思为代码内容和业务与逻辑的描述与命名吻合,并带解释和翻译。
灯光秀是对于不同灯组的亮灭(动作)进行编辑。灯组信息为以下格式:模式(0-28), 最低亮度(0-10), 最高亮度(0-10), 开始时间(0-255,1代表10毫秒), 结束时间(0-255,1代表10毫秒), 灯组号(1-24(左)或25-48(右))(例子:"12,0,10,0,100,1")。模式为供应商所固定HCM灯闪模式种类;最低亮度和最高亮度来控制灯组亮度;开始时间和结束时间来控制灯组闪动时间长度;灯组号为供应商所编排灯组号数。灯组与供应商固定模式详细信息可查询wiki。
车左右边各有24盏灯组,合起来HCM一共有48盏灯组。lightshow.cpp运行HCM信号下载时将每帧发48盏灯组信息转化成16进制的CAN信号到HCM。因此,灯组信息是与每一帧CAN信号相关的。相关16进制转化逻辑可参考供应商CANoe项目.dbc文件。lightshow_operator.rb灯光动作生成需要提供单边(左或右)灯亮的灯组信息,然后会根据用户选择自动生成相关的灯灭帧信号(每帧的灯组信息)并在运行HCM下载时自动添加上没用上灯组的CAN信号。
lightshow_operator.rb自动生成的灯组信息帧信号以两组分别为亮灭的灯组信息加上循环次数为最小单位(例子:"12,0,10,0,100,1" "12,0,0,0,100,1" 1)。每组可含有一个以上的灯组信息,每个灯组信息为单边的一盏灯组。灯组信息帧信号是以上数据架构的原因为运行HCM下载时循环次数之前的所有灯组信息将分为一半,一半亮的为一帧,另一半灭的为下一帧。所有动作或效果由此数据架构为基础,动作或效果差异全靠在此数据架构基础上进行改动。
以下为解释数据架构里灯组信息的变化是如何生成不同的动作或效果。以下输出来自于Ruby运行环境irb:
irb(main):428:0> [1,2].zip([-1,-2]).join(" ")
=> "1 -1 2 -2"
irb(main):430:0> ([1, 2] + [-1, -2]).join(" ")
=> "1 2 -1 -2"
如上1和2可为左边灯组1和灯组2的亮和灭帧,-1和-2为右边灯组1和灯组2的亮和灭帧,可见所有灯组闪亮可有的顺序都可归纳为以上两种,并都能用zip和+/concat的数组函数来实现。zip更是把同灯组的亮帧与灭帧绑在一起的实现方式:把1和2当为两个不同灯组的亮帧,-1和-2分别为它们的灭帧。
灯光秀动作可分为两类:节奏闪和连续闪。节奏闪定义为一个或多个灯组亮灭相间的动作(例子:亮 | 灭 | 亮 | 灭 | 亮 | 灭 | 亮 | 灭);灯亮和灯灭的时长相等,都决定于灯组信息的开始与结束时间。连续闪定义为多个灯组连续灯亮然后最后灯灭作为停顿的动作(例子:亮1|亮2|亮3|亮4|亮5|亮6|灭);每个灯组灯亮之间没时长间隔,最后的灯灭作为停顿有时长间隔。
之前提过,灯组信息是与每一帧CAN信号相关的。通过测试,发现暂时HCM无法兼容同一帧里不同灯组信息含有不同的开始或结束时间。因此,可执行效果也同时受限。动作灯组信息生成完毕后,为可删除多余帧数并同时保持数据架构的完整(一半亮一半灭,亮为一帧,灭为一帧)可使用"0,0,0,0,0,-1"来取代灯组信息(运行HCM下载时所有全为"0,0,0,0,0,-1"的帧数会直接被删除)。把多组动作结合在一起便可形成一首灯光秀。项目主目录里的beautiful_pursuit
和leave_the_door_open
为灯光秀例子。
直接运行lightshow_operator.rb会显示帮助:
运行失败。可运行模式:download(运行HCM下载)、lightshow(运行灯光秀)、can(转换灯光灯光秀灯组信息为CAN信号)、generate(生成下载到HCM的灯光秀灯组信息帧信号)、generate_and_download(生成下载到HCM的灯光秀灯组信息帧信号并运行下载)、get_tempo(节奏计算器)和to_supplier_defined_csv(把灯光秀灯光秀灯组信息生成供应商所定格式CSV)。
每个lightshow_operator运行模式都有相应的帮助和参数检查。对于根据按照歌曲来编辑一个灯光秀,可按照以下顺序来操作ruby lightshow_operator.rb
:
1)get_tempo
(节奏计算器)可按照歌曲片段长度输入节拍周期(例如300(毫秒))并陪上音乐循环播放(例如安装sox(apt-get/brew install sox)),看着相应节拍的闪动帮助自己用听力听出“自然频率“并计算出灯光秀灯组信息参数。例子:第一个窗口:ruby lightshow_operator.rb get_tempo 2.8 5.1
,第二个窗口:play beautiful.mp3 trim 2.8 \=5.1 repeat 100
。当输入节拍周期后(需要按回车),########################################
会按照节拍频率闪动。继续输入节拍周期将立即改变########################################
闪动频率。
所计算出的动作信息是为填写单边灯组信息所用。如果想生成节奏闪动作,“节奏闪需要x帧”代表在所提供歌曲片段长度里按照所输入节拍周期需要x帧,或x/2个次数循环(因为节奏闪是亮灭相间,而数据架构是亮为一帧,灭为一帧,亮和灭为一个循环,亮和灭的帧数相等)。x往往不是整数,因此可用"0,0,0,0,0,-1"来控制实际帧数(例子:13.2帧可理解为14帧或7个循环再把最后一灭帧灯组信息手动改为"0,0,0,0,0,-1")。“节奏闪每帧灯组结束时间参数为x”可直接填写单边灯组信息里的结束时间(如开始时间非0,需要把x加上开始时间)。
如果想生成连续闪动作,单边灯组信息的结束时间最佳效果一般为3,滚动闪(看下方的——(——2 ——1.1).1.1)最佳效果一般为7。“节奏闪每帧灯组结束时间参数为x”的x可为连续闪停顿时长间隔提供参考。x减去单边灯组信息数量乘以单边灯组信息的结束时间为一般最佳效果。虽“节奏闪需要x帧”的x/2可为连续闪动作的循环次数提供参考,实际帧数需要使用"0,0,0,0,0,-1"来进行调整。
2)download
将以上所述数据架构的的灯组信息帧信号下载到HCM里面。例子:ruby lightshow_operator_new.rb download "1,0,0,10,20,5" "1,0,0,10,20,29" "0,0,0,0,20,5" "0,0,0,0,20,29" 1 "1,0,0,10,20,5" "1,0,0,10,20,29" "0,0,0,0,20,5" "0,0,0,0,20,29" 1
。执行完毕后将打印出动作总帧数和时间长度*(暂时不适用于连续闪)。
3)generate
(生成灯光秀灯组信息帧信号)和generate_and_download
(生成灯光秀灯组信息帧信号并运行下载)可按照所提供单边(左或右)灯组信息生成以上所述数据架构的灯光秀动作灯组信息帧信号。例子:ruby lightshow_operator.rb generate "12,0,10,0,100,1" "12,0,10,0,100,3"
。
以下对生成灯光秀动作灯组信息问答流程进行解释:
-1 双边左右灯闪:是否单边(左或右)还是双边(左和右)灯闪。如果单边,提供左边或右边灯。如果双边,提供左边会自动生成右边灯组信息;提供右边会自动生成左边灯组信息。
-2 灯组合一起闪:如果提供两个以上灯组,动作是每个灯组同步闪还是一个一个闪。
——2.1 灯组合非一起闪时连续闪(时长越短连续越快):如果灯组一个一个闪,生成连续闪动作。
=2.1.1 连续闪时每次所有灯组闪动结束后停顿时间:连续闪动作的停顿时长。
——2.1.2 将按照灯组顺序亮灭节奏式闪动:非生成连续闪动作即生成节奏闪动作。
=1.1 左右边灯同步闪:车两边的车灯是否同步闪动。
(——2 ——1.1).1 左右边灯异步和灯组合非一起闪时左右交错闪: 非两边车灯同步闪动时按照灯组信息顺序左右先后交错闪动。全部灯组闪完为一个循环。
——(——2 ——1.1).1.1 左右边灯异步和灯组合非一起闪时左右滚动闪(注意实际灯组左右位置先后): 非两边车灯同步闪动时按照灯组信息顺序从左(或右)滚动至右(或左)闪动。一个来回动作为一个循环。
——(——2 ——1.1).1.1.1 将每边先后各个灯组先后闪: 非两边车灯同步闪动时按照灯组信息顺序先闪完左边(或右边)所有灯组再闪右边(或左边)所有灯组。全部灯组闪完为一个循环。
-3 单次灯组闪动次数:控制一个动作里每个灯组信息闪动的次数。
-4 总循环次数:整个生成后动作灯组信息的总循环次数。
=#为所对应上层选项答“是”
——#为所对应上层选项答“否”
generate
将打印出所生成灯组信息帧信号的download
命令。generate_and_download
将直接运行download
。
4)lightshow
将运下载完毕后的灯光秀。提供的时长参数(毫秒)是为了灯光秀结束后发送关闭灯光秀信号到HCM。
5)to_supplier_defined_csv
将以上所述数据架构的的灯组信息帧信号生成供应商所定格式的CSV。此CSV可使用lightshow.can下载到HCM(lightshow.can为原供应商灯光秀CANoe项目里lightshow.can的重构版)。
6)can
将打印出所提供灯组信息参数转化为16进制的CAN信号。
1)HCM需要每帧信号以步骤数0到7循环。
2)供应商固定模式0为灭,1为亮。2到28为各种闪动模式。详情参考wiki。
3)暂时HCM只支持一共300帧信号。详情参考wiki。
4)暂时download
所算出的灯光秀时间长度不完善。需要兼容连续闪和一些edge cases。因此运行lightshow
时需要按照歌曲输入实际时长。这为未来开发任务。
5)一些效果暂时仍需要“骚操作”/手动改所生成帧信号的相关灯组信息参数。这为未来开发任务。