第一个版本,用了上网本做机器人 主机,通过其它终端遥控。实现其它确实很简单,还能独立完成一些复杂任务。但是遥控的角度上还是有些很多弊端,比如视频和控制都有明显延时,psp容易,上网本耗电过多,如果选择从机器人的电池获得供电,一次充满玩不了多久就没电了。基于上述情况,决定把遥控改了。
喜欢该贴的、下载代码的顺手点个支持吧
第一版:
材料清单:
2020铝型材若干
32路舵机控制板一块
Arduino uno控制板一块
上网本一台
11个180度舵机
2个360度舵机(当直流电机用)
舵机支架若干
usb摄像头一个配红外镜头
4个红外led灯
12V锂电池一块同时为上网本和控制板供电
搭好的机器人:
模式切换的测试视频:
wifi遥控(带视频传输)是可以用可烧写的无线路由器实现的,例如TP Link703N,也可以在网上买已经烧写好openwrt的。
手上没有这类路由器,偷个懒就用5年前的上网本来实现好了。上网本和uno利用串口通信,上网本上的程序用c语言编写。可轻松实现键盘事件。这样偷懒有个好处,可以利用移动设备直接对上网本遥控,从而控制机器人,比如使用windowsphone上的应用pcremote。也可以利用其他计算机对机器人实现远程遥控。简单的桌面托管(例如qq)就可以了,当然也可以自己编写。另外还可以用c语言和opencv实现视频识别等,让机器人独立完成一些任务。
手上有台闲置已久的psp。这里就是用psp disp来完成遥控,带视频流。
关于C语言的按键反应和串口通信,简单做下介绍。
这里以clr项目为例,示例代码如下,非常简单
#include "stdafx.h"
#include "windows.h"
using namespace System;
using namespace System::IO::Ports;
int main(array<System::String ^> ^args)
{
Console::WriteLine(L"Serial test");
SerialPort^ arduino;
arduino = gcnew SerialPort("COM3",9600);
arduino->Open();
int i=1;
while(1){
if(i%2==1)
arduino->WriteLine("H");
else
arduino->WriteLine("L");
Sleep(1000); //延时1秒,其头文件为window.h
i=i+1;
}
return 0;
}
前面提到过opencv。为了以后的任务,如视频识别等,决定直接使用opencv。对于这里的遥控任务而言,可以直接打开usb摄像头,而且自带了键盘事件函数。示例代码如下
#include "stdafx.h"
#include <opencv2/opencv.hpp> // opencv库函数
using namespace System;
using namespace System::IO::Ports;
using namespace cv;
int main(array<System::String ^> ^args)
{
Console::WriteLine(L"Serial test");
cvNamedWindow( "window1", CV_WINDOW_AUTOSIZE);
SerialPort^ arduino;
arduino = gcnew SerialPort("COM3",9600);
arduino->Open();
int i=1;
while(1)
{
char c = waitKey(1000); //延时1秒,等待键盘事件,返回键值
switch(c)
{
case 'h':
arduino->WriteLine("H");
break;
case 'l':
arduino->WriteLine("L");
}
}
cvDestroyWindow("window1"); // 销毁窗口
return 0;
} 复制代码
要使用opencv的函数,需要对项目做一些配置,可以参考中国官网上的安装教程。另外需要注意的是
waitKey()函数只有在打开了一个cv窗口的情况下有效。所以在主函数里第二行添加了语句:
cvNamedWindow( "window1", CV_WINDOW_AUTOSIZE); //创建一个cv窗口
再放几张界面的图片和截屏
两个四足模式的视频
局域网遥控
完整的c语言程序代码可以在附件下载
第二版:
还是继续要视频传输,和wifi遥控。这次用一个刷了openwrt的路由代替上网本,今后图像处理等任务可以交由上位机完成。因为不需要负载上网本,对机器人的结构做了些改动。
我选择了一个mini无线路由器。拆开壳改装的时候才发现主板和tp link 703n是一样的。然后就是把板子上的tp_in和tp_out接出两根线用于和arduino串口通信。供电不用miniusb口,还要跳出两根电源线,电源线负极也是串口通信的共地线。为了扩大点wifi信号范围,放弃了原有的wifi贴片天线,连接了一个外接天线。
硬件全部改造完成了,然后就是漫长的刷机过程。不多说了,网上资料教程多的是。嫌麻烦也可以从网上直接买个烧写好的路由器。连上摄像头和arduino就可以测试了。目前测试用的是网上的上位机软件(计算机和手机)。这些软件支持按键自定义,还不错,下位机部分就可以完全保持不变了。pc端上位机软件,过于花哨了,有的功能不需要的也放在上面。android端自定义功能不算太全面。
着手自己编写程序。等程序完成后再跟大家分享。最后还是要回归到psp控制,psp程序现在也只能自己编写了。程序的编写难点有两个,一个视频传输,另一个是数据的传输。
C++和opencv方案
前面说了,之后图像处理的任务会交给上位机。第一版中,控制端的计算机就是用的C++搭opencv的方案。所以继续沿用该方案设计pc端程序。 建立一个C++ console项目,添加相关opencv库的添加和路劲配置,可以参考网上的资料。
如果按照网上的资料进行路由器烧写,那么视频流的地址为 http://192.168.1.1:8080/?action=stream
路由器成功烧写openwrt的话,可以用firefox浏览器在改地址下成功打开摄像头。opencv里的VideoCapture是可以利用ip地址打开网络摄像头的
如果直接使用视频流的地址是打不开的,因为VideoCapture的参数需要一个文件拓展名,所以在使用的时候给它加上一个虚拟变量。烧写了openwrt的路由器传输的视频流是mjpg。我们新的视频流地址就是
http://192.168.1.1:8080/?action=stream&type=.mjpg
现在来看这部分的完整代码,轻松打开摄像头。 #include "stdafx.h"
#include "opencv2/opencv.hpp"
#include "highgui.h"
#include "iostream"
using namespace System;
using namespace cv;
using namespace std;
int main(array<System::String ^> ^args)
{
Console::WriteLine(L"Hello World");
cvNamedWindow( "camera", CV_WINDOW_AUTOSIZE);
cvMoveWindow("camera",0,0);
const string cameraAddress = "http://192.168.1.1:8080/?action=stream&type=.mjpg"; //带虚拟参数的视频流ip地址
VideoCapture vcap;
Mat frame;
if(! vcap.open(cameraAddress))
{
Console::WriteLine(L"ERROR");
return -1;
}
while(1)
{
char c = cvWaitKey(10);
vcap.read(frame);
imshow("camera",frame);
if(c==27)
break;
}
cvDestroyWindow("camera");
return 0;
} 复制代码
控制部分。 按照网上的资料给路由器烧写openwrt后,控制地址为 http:\\192.168.1.1
端口号为:2001 路由默认的通信波特率为9600
控制的实现使用C/C++的Network编程。首先需要添加头文件 System.dll
然后添加下面的命名空间
using namespace System;
using namespace Sytem::Net;
using namespace Sytem::Net::Sockets; 复制代码
定义一个IPAddress类对象来解析控制地址。
System::String^ controlip = "192.168.1.1"; // 不能包含 http:\\ 复制代码
定义一个IPEndPoint类对象,建立控制地址的端点。
System::String^ port = "2001"; 复制代码
最后定义一个Socket类对象,用Socket类的函数完成建立连接,数据发送和接收。
Socket^ c = gcnew Socket(ipe->AddressFamily,SocketType::Stream,ProtocolType::Tcp); 复制代码
其中scode和rcode的类型是字节数组,scode是要发送的数据,rcode用于保存要接收的数据
array<Byte>^ scode = Encoding::UTF8->GetBytes("arduino"); //arduino是要发送的数据,转换为Byte数组,保存到scod 复制代码
用下面的Arduino代码来测试路由器的串口控制。
int led = 13;
void setup(){
pinMode(led,OUTPUT);
Serial.begin(9600);
}
void loop(){
char c;
if(Serial.available())
c = Serial.read();
if(c == 49)
digitalWrite(led,HIGH);
else
digitalWrite(le,LOW);
} 复制代码
下面是包含摄像头打开和发送测试数据的代码。 #include "stdafx.h"
#include "opencv2/opencv.hpp"
#include "highgui.h"
#include "iostream"
#using <System.dll>
using namespace System;
using namespace System::Net;
using namespace System::Net::Sockets;
using namespace System::Text;
using namespace cv;
using namespace std;
int main(array<System::String ^> ^args)
{
Console::WriteLine(L"Hello World");
cvNamedWindow( "camera", CV_WINDOW_AUTOSIZE);
cvMoveWindow("camera",0,0);
const string cameraAddress = "http://192.168.1.1:8080/?action=stream&type=.mjpg";
System::String^ controlip = "192.168.1.1";
System::String^ port = "2001";
VideoCapture vcap;
Mat frame;
if(! vcap.open(cameraAddress))
{
Console::WriteLine(L"ERROR");
return -1;
}
IPAddress^ ips = IPAddress::Parse(controlip);
IPEndPoint^ ipe = gcnew IPEndPoint(ips,Convert::ToInt32(port));
Socket^ c= gcnew Socket(ipe->AddressFamily,SocketType::Stream,ProtocolType::Tcp);
c->Connect(ipe);
array<Byte>^ scode = Encoding::UTF8->GetBytes("1");
array<Byte>^ rcode = gcnew array<Byte>(256);
while(c->Connected)
{
scode = Encoding::UTF8->GetBytes("0");
c->Send(scode,scode->Length,SocketFlags::None);
//c->Receive(rcode,c->Available,SocketFlags::None);
char k = cvWaitKey(10);
vcap.read(frame);
imshow("camera",frame);
scode = Encoding::UTF8->GetBytes("1");
c->Send(scode,scode->Length,SocketFlags::None);
if(k==27)
break;
}
cvDestroyWindow("camera");
c->Close();
return 0;
} 复制代码
最后可以看到Arduino控制板上的led等L在闪烁。 现在来控制机器人。Arduino的代码完全不需要改动。把第一版的c++代码移植到上面的代码里就完成了。完整的代码可以从下面附件下。C++程序运行截图
安卓控制端的代码也完成了。相比之下,代码简单得多,就不多解释了。大家可以直接下载源码。稍微说明下,如果以我的安卓代码继续做的话,注意我用了自定义的SurfaceView类,其次Manifest文件里要添加以下代码,这是网络通信协议
<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" >
</uses-permission>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" >
</uses-permission> 复制代码
安卓控制界面照片
用安卓平板遥控的视频。PC端的遥控视频就不发了
下一阶段就是PSP的控制了,正在酝酿中。完成后再跟大家分享。可能还会编写windowsphone版本的。
喜欢该贴的、下载代码的顺手点个支持吧