一、设计初衷:
当过爸爸妈妈的都有类似感受:小孩慢慢长大,学说话,学走路,而自己平时上班太忙,陪小孩的时间自然就少了!为了弥补心中遗憾,很多我认识的朋友中会在自己家里安装WIFI IP camera方便自己随时查看小孩在家是否有哭闹或者做一些不安全的事,而也有很少一部分喜欢DIY的朋友选择了自己动手,我也是其中之一。
二、项目发展历程
尤其是当我女儿在2岁左右的时候,此时才刚好学会说话,走路,我是特别希望自己能多点时间陪伴她,于是这个项目在当时2015.8启动了。
这款安卓手机远程陪伴机器人项目经过了2年的反复改进,目前有三个版本,分别是2015/2016/2017三个版本, 虽然从外观,硬件和软件app上都有很大变动,但都是围绕主要功能来改进的:远程视频陪伴。
三、优势:
设计之初不完全是为了DIY,我是希望能够做出一款实用便宜易用的产品,所以没有采用常用的DIY开源硬件方案例如arduino,而是选择了价格便宜,功耗极低的蓝牙BT4.0和MCU控制一体TI最新芯片CC2541来做控制方案。当然也相信大家能理解我为什么会选择android手机来做机器人大脑。
项目过程中遇到最大难题是android手机兼容性问题,在APP的开发过程中,这个问题花最多时间和精力才做到今天这种程度,我个人感觉是非常有成就感的。
因为类似项目不止我一个人想做,但最后都因为这个问题而放弃,包括国外2012很火的romo机器人,国内也有不少这样的公司,他们最终都不得不选择苹果的手机或者平板来做。这里面主要是解决了app在没有root权限的情况下待机以后还会长时间不掉线,还可以随时被唤醒。
与WIFI IP camera对比:
1)可以到处跑,因为不需要插着电源线;2)省电,待机长,所以不用担心充电问题。3)监控温湿度声音情况。
四、功能:
1)远程视频(android手机+webrtc)
2)蓝牙遥控车(20天待机 BT4.0 CC2541)
3)百度语音识别和聊天(android手机编程)
4)温湿度传感器 (DHT11传感器模块)
5)声音传感器
下图是完整的实物零件图,基本上是从淘宝上面淘的(除了控制底板),
2)小车底盘(淘宝上面有非常多的小车底盘卖,自己任选),
3)马达:TT马达3元/个
4)轮子:2元/个
5)锂电池:2200mAH 7.4V + 充电器 一起30元
1)控制板包括:
蓝牙模块CC2541:11元
电机模块:5元
稳压模块:5元
温湿度传感器:5元
底板:自己设计的,自己也可以用面包板或者飞线来代替,只是可能会比较乱不好看。
自己算算很便宜吧!
CrabRobot是一款小孩陪伴机器人APP, 已经通过小米审核,可以在小米应用商店搜索CrabRobot
1、两大功能:
组装后效果图,个人挺满意的 ^_^:
七、开放资源
https://github.com/luojin012/Android-phone-telepresence-robot
1、开源:控制电路板,结构,控制板软件;app免费使用
2、app接口免费使用,接口开放
这里列举下蓝牙命令接口,
例如通过蓝牙发送命令:
1) b2;\n
小车以2的速度前行,如果是负数就倒车
2) t3;\n
小车以3的速度转弯,负数的话就是反方向转弯
温湿度传感器命令:
如果小车控制板上有温湿度传感器,也可以按照下面格式发送数据到APP
DHT:60.2;28.5
60.2是湿度,28.5是温度。
控制板的代码是开源的基于CC251蓝牙模块C51核写的
读取温湿度代码,这里要感谢“甜甜的大香瓜”,在他的基础上修改来的,少走了弯路。
//******************************************************************************
//name: DHT11_Read_Humiture
//introduce: DHT11的读温湿度函数
//parameter: none
//return: TRUE:读取正确,FALSE:读取错误
//author: 甜甜的大香瓜
//email: [email protected]
//changetime: 2016.04.11
//******************************************************************************
void DHT11_Read_Humiture(uint8 *pDHT11_data)
{
uint8 nHumidity_integer;
uint8 nHumidity_decimal;
uint8 nTemperature_integer;
uint8 nTemperature_decimal;
uint8 nChecksum;
uint8 nChecksum_count;
uint8 nFLAG;
// EA = 0;
//主机开始信号
SET_PIN_OUT; //IO口配置为输出
SET_DATA_PIN; //输出高电平
// Delay_Us(100000);
CLR_DATA_PIN; //输出低电平
Delay_Us(4000); //延时至少18MS
SET_DATA_PIN; //输出高电平
Delay_Us(4);
//切换到DHT11端发数据
SET_PIN_IN; //IO口配置为输入
Delay_Us(4);
if(DATA_PIN == 0)
{
//DHT11响应
nFLAG = 2;
EA = 0;
while((DATA_PIN == 0) && (nFLAG++));
nFLAG = 2;
while((DATA_PIN == 1) && (nFLAG++));
//DHT11读值
nHumidity_integer = DHT11_Read_Char(); //湿度高位,整数
nHumidity_decimal = DHT11_Read_Char(); //湿度低位,小数
nTemperature_integer = DHT11_Read_Char(); //温度高位,整数
nTemperature_decimal = DHT11_Read_Char(); //温度低位,小数
nChecksum = DHT11_Read_Char(); //校验和
EA = 1;
//结束
SET_DATA_PIN;
//计算校验和
nChecksum_count = nHumidity_integer + nHumidity_decimal + nTemperature_integer + nTemperature_decimal;
//验证数据正确性
if(nChecksum == nChecksum_count)
{
//正确,则将读出的值保存到全局变量
pDHT11_data[0] = nHumidity_integer;
pDHT11_data[1] = nHumidity_decimal;
pDHT11_data[2] = nTemperature_integer;
pDHT11_data[3] = nTemperature_decimal;
}
else
{
//错误,则值全为0
pDHT11_data[0] = 0;
pDHT11_data[1] = 0;
pDHT11_data[2] = 0;
pDHT11_data[3] = 0;
EA = 1;
return ;
}
}
else
{
//错误,则值全为0
pDHT11_data[0] = 0;
pDHT11_data[1] = 0;
pDHT11_data[2] = 0;
pDHT11_data[3] = 0;
EA = 1;
return ;
}
EA = 1;
return ;
}
命令接受解析控制,可以看到和上面命令例子 是对应的。
void car_stop()
{
motor_Set(motor_A0, 0);
motor_Set(motor_A1, 0);
motor_Set(motor_B0, 0);
motor_Set(motor_B1, 0);
car.left=car.right=0;
car.carn=0;
}
/*void motor_Set( uint8 pin_d, uint8 mode )
{
//
// cmd_st.key_timer=0;
// PIN_setOutputValue(hKeyPins, pin_d, mode);
pin_d=mode;
}
*/
void cmd_pase(char *data_c,int len)
{
int i;
//char *data_c=Receive_CMD[0].receive_buf;
//memset(RX2_Buffer,0,BUF_LENTH);
for(i=0;i0)
car.right+=2;
else
car.right-=2;
car.left=-car.right;
//motor_Set(duoji_A, 1);
douji.x=0;
car.carn=0;
break;
}
else if(data_c[i]=='b') // both motor speed
{
car.right=car.left= atoi(data_c+i+1);
//motor_Set(duoji_A, 1);
douji.x=0;
car.carn=0;
//if(car.right==2)
// car_led = ~car_led;
break;
}
}
}
void receing_data(char datar)
{
if(datar==';')
{
Receive_CMD[0].receive_buf[Receive_CMD[0].receive_len++] = 0;
Receive_CMD[0].receive_status=2;
idle_buf++;
/////
cmd_pase(Receive_CMD[0].receive_buf,Receive_CMD[0].receive_len);
Receive_CMD[0].receive_status=0;
Receive_CMD[0].receive_len=0;
}
else
//else if(Receive_CMD[0].receive_status<2)
{
Receive_CMD[0].receive_buf[Receive_CMD[0].receive_len++] = datar;
Receive_CMD[0].receive_status=1;
if(Receive_CMD[0].receive_len>max_rebuf)
Receive_CMD[0].receive_len=0;
}
}
#if 1
void car_control()
{
// car_led = (car.left||car.right);
car.left_count++;
if((car.left_count>=8))
{
car.left_count=1;
if(car.left!=1)
{
motor_Set(motor_A0, 0);
motor_Set(motor_A1, 0);
}
}
if(car.left==0)
{ // stop
motor_Set(motor_A0, 0);
motor_Set(motor_A1, 0);
}
if(car.left==car.left_count)
motor_Set(motor_A0, 1);
//motor_A0=1;
if(car.left==-car.left_count)
motor_Set(motor_A1, 1);
//motor_A1=1;
////////////*/
car.right_count++;
if((car.right_count>=8))
{
car.right_count=1;
if(car.right!=1)
{
// car.right=0;
motor_Set( motor_B0, 0 );
motor_Set( motor_B1, 0 );
}
}
if(car.right==car.right_count)
{
motor_Set(motor_B0, 1);
//car_led = 1;
}
// motor_B0=1;
if(car.right==(-car.right_count))
{
motor_Set(motor_B1, 1);
// car_led = 1;
}
if(car.right==0)
{ // stop
motor_Set(motor_B0, 0);
motor_Set(motor_B1, 0);
}
}
让我开心的是,隔壁家的男孩比我们家的女儿更喜欢玩;另外有次我把样品拿出去玩时,有个妈妈问有没有开始卖,她也需要一个来照看她家的老人和小孩。
https://item.taobao.com/item.htm?id=552635703115 想自己DIY的伙伴可以联系我,提供3D打印相关外壳及其它硬件!QQ:1074814960