每一個物聯網系統都是由不同的智能單品組合起來的,智能單品在智能家居系統最常見,包含了空氣淨化器、智能燈泡、智能門鎖、智能電錶、智能水錶、智能燃氣表、智能門窗等。我們經過調研發現大部分的設備都需要具備3個基本的功能:遠程、控制、監測。
本項目以智能遙控小車為例,幫助大家理解掌握智能單品的開發過程以及LongTooth(長牙)通信技術的嵌入使用流程,通過對該技術的應用,最終安全高效的實現遠程、控制、監測3大功能。
LongTooth(長牙)
LongTooth(長牙)是N22開發的專利技術。是一種基於應用層,通過服務響應的方式,為服務與服務之間提供雙向多通道的Internet安全直連通信技術。開發者僅需幾行代碼上就可以在任何設備之間建立一個雙向通信通道,無需另外建立專用服務器,建立一個分佈式的IOT環境,服務交互的雙方可以直接通過Internet雙向通信。極大的降低了物聯網各類應用的開發難度、成本,獨特的分佈式架構讓服務交付更加簡潔、高效、安全。
現如今,LongTooth(長牙)技術在物聯網、工業物聯網、智慧城市、無邊界通信等領域得到了初步的應用。
項目準備
1、編譯工具
APP(此項目以IOS為例)代碼編譯工具:Xcode
Raspberry Pi代碼編譯工具: putty(連接)、filezilla(FTP)、notepad++(代碼編輯)
在Raspberry Pi上運行程序方法:程序完成後,在Raspberry Pi上運行程序即可實現對應功能,實現方法見《01-LongTooth(長牙)智能車代碼加載.doc》
2、配件清單
3、硬件處理
幾個硬件部件之間的接線示意圖如下:
經過處理,效果如下:
具體實現
1、動力系統實現
案例中我們的配件清單中已經購置了遙控小車,我們需要對遙控小車進行升級,通過樹莓派控制板實現遠程遙控。即對小車的動力系統主要部件:馬達以及步進電機實現遠程遙控。
(1)硬件控制流程
Ø 電源給Raspberry板供電;
Ø Raspberry板通過GPIO針腳給L298N模塊供電且控制L298N;
Ø L298N控制小車馬達。
(2)Raspberry板與L298N板的連接
Ø 經實測,L298N的5V電源針腳須供電3.3V;GND針腳須和Raspberry板的GND相連(共地);
Ø M1和M2模塊的兩個接頭分別接小車的前後輪馬達;
Ø 其他針腳的連接由代碼決定。
(3) 軟件控制流程
Ø Raspberry板上運行著一個LongTooth的demo的服務端;
Ø 手機端運行一個LongTooth的demo的客戶端;
Ø 客戶端發送指令,通過LongTooth傳送到服務端,從而控制小車。
經過分析,我們得到小車的控制邏輯圖如下:
2、 通信系統實現
(1)Raspberry設備端通電、聯網
Ø 初始化配置見3.2 Raspberry Pi系統配置具體介紹;
Ø 網絡配置{有線網絡轉成無線網絡,具體操作見(3)無線網絡配置}
(2)LongTooth(長牙)服務註冊
APP控制端:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.view.backgroundColor = [UIColor whiteColor];
UITapGestureRecognizer *gestureTap = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(viewTapped:)];
gestureTap.delegate = self;
[self.view addGestureRecognizer:gestureTap];
//啟動註冊長牙
[self registerLongTooth];
//創建UI
[self createUI];
}
Raspberry設備端:
int output_run(int id)
{
// 長牙啟動入口
…………
printf("app ---------> longtooth -- Start begin --\r\n");
lt_lan_mode_set(true);
lt_register_host_set("118.178.233.149", 53199);
lt_start(devid, appid, appkey, machineid, lt_event_handler_impl);
// 註冊服務關鍵代碼
printf("%s lt_start ltid:%s\r\n",__FUNCTION__,lt_id());
……
while(1){
sleep(1);
}
return 0;
}
(3)無線網絡配置
本課程中我們要實現小車的遠程操作,所以小車需要能夠連接無線網絡,才能實現遠程操作。
APP控制端:
Ø 發送請求獲取小車無線網列表
[self.longtoothHandler sendInsWithRemoteLtid:self.carIdString ServiceName:LONGTOOTH_SERVICEWIFI insData:nil block:^(NSString *returnStr) {
}];
Ø 發送對應網絡密碼
[self.longtoothHandler sendInsWithRemoteLtid:self.carIdString ServiceName:LONGTOOTH_SERVICEWIFI_PASSWORD insData:data block:^(NSString *returnStr) {
if ([returnStr isEqualToString:LONGTOOTH_SERVICEWIFI_PASSWORD]) {
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
UIAlertController *alertCtrl1 = [UIAlertController alertControllerWithTitle:@"無線網絡" message:@"設定成功" preferredStyle:UIAlertControllerStyleAlert];
[alertCtrl1 addAction:[UIAlertAction actionWithTitle:@"確定" style:UIAlertActionStyleCancel handler:nil]];
[self presentViewController:alertCtrl1 animated:YES completion:nil];
});
}
}];
Tips:以上內容選擇小車發回來的無線網名稱,將對應的密碼發回給小車,小車進行無線網配置。
Raspberry設備端
lt_service_add(service_connection_wirelesswifi, lt_connection_wirelesswifi);//serching wifi and send to app
lt_service_add(service_recv_wifipassword, lt_recv_wifipassword);// recv account and password from app
最終效果:
(4)通信建立、身份認證
APP控制端:
Ø 核實確認Raspberry設備端ID,在App界面輸入確認連接
Tips:上圖中的步驟:1、長牙啟動後本地狀態;2、當前設備ID;3、遠程設備ID;4、確認連接。
Ø 發送連接請求
#pragma mark - 確定連接
- (void)confirmConnectAction
{
dispatch_async(dispatch_get_main_queue(), ^{
[self.view endEditing:YES];
self.hud = [OmniBoxAlertHUD loadingHUDWithMessage:[NSString stringWithFormat:@"%@",@"連接中..."]];
[self.hud show];
});
//網絡請求加載提示,UI顯示
[self.longtoothHandler sendInsWithRemoteLtid:self.LTCaridTextField.text ServiceName:LONGTOOTH_CONNECTION insData:nil block:^(NSString *returnStr) {
if ([returnStr isEqualToString:LONGTOOTH_CONNECTION]) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.hud performSelector:@selector(dismiss) withObject:nil afterDelay:0];
//跳轉到小車控制界面
PlayerVideoController *playCtrl = [[PlayerVideoController alloc] init];
playCtrl.carLongToothID = self.LTCaridTextField.text;
[self presentViewController:playCtrl animated:YES completion:nil];
});
}
}];
}
Raspberry設備端:
收到App端連接請求,並反饋給App連接狀態
void lt_connection_confirm(const lt_tunnel ltt,
const char* ltid_str,
const char* service_str,
int data_type,
const char* args,
size_t argslen)
{
printf("request from ltid:%s args:%s\r\n",ltid_str,service_str);
char *resp_buf = "alive";
int ret = lt_respond(ltt, LT_ARGUMENTS, resp_buf, strlen(resp_buf), NULL,NULL);
if(ret == 0){
printf("app ----> lt_respond succeed -- [%d] : %s ret:%d\n", strlen("alive"), "alive",ret);
}else{
printf("app ----> lt_respond failed -- [%d] : %s ret:%d\n", strlen("alive"), "alive",ret);
}
return ;
}
Tips: 當小車收到App的連接請求時,會觸發此函數。並通過lt_respond方法告訴App連接成功。
3、指令傳輸
APP控制端:
Ø 操作按鈕控制小車;
Ø 點擊按鈕發送指令,以前進為例。
__block NSArray *prizeArr = @[@"前進", @"右轉", @"後退", @"左轉"];
self.carControlButton = [[CarControlButton alloc] initWithFrame:CGRectMake(100, 100, s_height-40, s_height-40) prizeArr:prizeArr progress:^(NSInteger currentProgress, NSInteger totalProgress) {
// weakSelf.progess.progress = currentProgress / (float)totalProgress;
} completion:^(NSInteger index) {
NSLog(@"%ld",index);
if (index == 1) {//前進
self.speedLabel.text = [NSString stringWithFormat:@"前進速度:%d",30];
self.speedPogressView.progress=0.3;
_isRunAhead = YES;
_speedNumbers = 30;
NSString *str = [NSString stringWithFormat:@"a %d",30];
[self.longtoothHandler sendInsWithRemoteLtid:self.carLongToothID ServiceName:LONGTOOTH_CARCONTROL insData:[str dataUsingEncoding:NSUTF8StringEncoding] block:^(NSString *returnStr) {
if ([returnStr isEqualToString:LONGTOOTH_CARCONTROL]) {
NSLog(@"16");
}
dispatch_async(dispatch_get_main_queue(), ^{
[self.parameterDataArr insertObject:returnStr atIndex:0];
[self.carParameterTbView reloadData];
});
}];
}else if (index == 2){//後退
Tips:以上代碼第一個藍色字體部分為創建控制小車的操作板,前進,後退,左轉,右轉,啟動,暫停。以前進為例,第二個藍色字體部分為發送前進指令後給的初始速度顯示在當前界面上。第三個藍色字體部分為發送指令,調用LongTooth(長牙)。指令參數:self.carLongToothID;//連接的小車ID;LONGTOOTH_CARCONTROL;//小車控制服務;str;//為發送指令參數。前進:a 30(初始速度)。
Raspberry設備端:
void lt_carcontrol(const lt_tunnel ltt,
const char* ltid_str,
const char* service_str,
int data_type,
const char* args,
size_t argslen)
{
int val = 0, ret = 0, flag = 0;// error flag
int my_data_type = LT_ARGUMENTS;
char respond_buf[50] = "Command OK";
// get command
char command;
if(args == NULL ){
printf("%s args error\r\n",__FUNCTION__);
return ;
}
strncpy(&command, args, 1);
// get value
char val_str[3];
memset(val_str ,0, 3);
if(argslen > 2){
strncpy(val_str, args + 2, argslen - 2);
val = atoi(val_str);
}else{
val = 0;
}
printf("args:%s arglen:%d val:%d val_str:%d\r\n",args,argslen,val,val_str);
if(val < 0 || val > 100){
printf("value invaid, it should bewteen 0 and 100, included\n");
flag = EVALUEERROR;
}
Tips:以上代碼中的
lt_carcontrol()函數為控制小車的函數,當app控制小車時會進入此函數,根據app發來的數據(數據主要包括commond,val兩個部分)進行解析,判斷,從而對小車進行相應的操作。commond為命令(控制小車前進,後退等操作),val為值(控制小車速度)。4、動作執行
APP控制端:
Ø 小車發送前進指令後可查看當前前進速度;
Ø 可打開視頻開關按鈕,查看小車採集的錄像。
如下圖:
Raspberry設備端:
if(flag == 0){
switch(command){
case 'a':// run Ahead
car_run_ahead(val);
sprintf(respond_buf, "run ahead, speed = %d", val);
break;
case 'b':// run Back
car_run_back(val);
sprintf(respond_buf, "run back, speed = %d", val);
break;
case 'l':// turn Left
car_turn_left(val);
sprintf(respond_buf, "turn left");
break;
case 'r':// turn Right
car_turn_right(val);
sprintf(respond_buf, "turn right");
break;
case 'h':// Halt
car_turn_stop();
sprintf(respond_buf, "turn stop");
break;
case 'p':// Park(stop)
car_motor_dc_stop();
sprintf(respond_buf, "car stop");
break;
default:
flag = ECOMMANDERROR;
printf("error command\n");
break;
}
}
Tips:Raspberry 解析App控制指令後通過car_run_ahead(var)來輸出L298N小車前進,後退等信號,然後驅使馬達運轉。
5、指令反饋
Raspberry設備端:
ret = lt_respond(ltt, my_data_type, respond_buf, strlen(respond_buf), NULL,NULL);
if(ret == 0){
printf("app ----> lt_respond succeed -- [%d] : %s ret:%d\n", strlen(respond_buf), respond_buf,ret);
}else{
printf("app ----> lt_respond failed -- [%d] : %s\n ret :%d", strlen(respond_buf), respond_buf,ret);
}
Tips:動作執行完以後,再通過lt_respond(給App一個響應)。
APP控制端:
Ø 小車收到指令給出響應觸發App響應函數(方法);
Ø App收到響應參數通過Block回調刷新UI,在界面顯示;
Ø
self.returnBlock(str);//block回調更新UI 響應狀態@implementation LongToothServiceResponseHandlerImpl
- (void)handle:(id<longtoothtunnel>)ltt withLongToothId:(NSString *)ltid withServiceName:(NSString *)service dataTypeIs:(NSInteger)dataType withArguments:(NSData *)args attach:(id<longtoothattachment>)attachment{/<longtoothattachment>/<longtoothtunnel>
NSLog(@"1234");
if ([service isEqualToString:LONGTOOTH_CARCONTROL]) {
NSString *str = [[NSString alloc] initWithData:args encoding:NSUTF8StringEncoding];
NSLog(@"%@",str);
self.returnBlock(str);
結語
以上內容為您分享瞭如何利用Raspberry Pi、遙控小車、LongTooth(長牙)通信技術來開發遠程遙控小車。通過本項目幫助大家理解掌握智能單品的開發過程以及LongTooth(長牙)通信技術的嵌入使用流程,通過對該技術的應用,最終安全高效的實現遠程、控制、監測3大功能。
更多內容,盡在LongTooth
閱讀更多 LongTooth長牙Robin 的文章