内容简介:基于3G模块的树莓派基站定位
具体的AT命令请查阅相关手册,绝大多数命令是通用的,部分命令会随着生产厂家有所差异,这里列举有关基站定位的几个AT命令
#测试有无SIM Q: AT+CPIN? A: +CPIN:READY #信号强度 AT+CSQ +CSQ: 16,99 #运营商信息 AT+COPS? +COPS: 0,2,"46001" #基站信息 AT+CREG=2 AT+CREG? +CREG: 2,1,"AAAA","BBBBBB"
串口编程
c
首先对上面的AT命令进行测试,观察返回的信息, win 平台上有串口调试助手可以使用, linux 下也有 minicom ,或者像我一样直接上 C 语言测试串口收发
#include <stdio.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
int set_opt( int fd, int nSpeed, int nBits, char nEvent, int nStop );
int main( int argc, char **argv )
{
if ( argc != 3 )
{
printf( "Usage: ttytest device cmd\n" );
exit( 0 );
}
int fd;
char * cmgf = argv[2];
strcat( cmgf, "\r" );
char reply[128];
fd = open( argv[1], O_RDWR | O_NOCTTY | O_NDELAY );
if ( fd < 0 )
{
perror( "Can't Open Serial Port" );
return(-1);
}
/* 配置串口 */
set_opt( fd, 115200, 8, 'N', 1 );
write( fd, cmgf, strlen( cmgf ) );
printf( "write %s\n", cmgf );
sleep( 2 );
memset( reply, 0, sizeof(reply) );
read( fd, reply, sizeof(reply) );
printf( "reply :\n" );
printf( "%s\n", reply );
}
int set_opt( int fd, int nSpeed, int nBits, char nEvent, int nStop )
{
struct termios newttys1, oldttys1;
if ( tcgetattr( fd, &oldttys1 ) != 0 ) /* 保存原先串口配置 */
{
perror( "Setupserial 1" );
return(-1);
}
bzero( &newttys1, sizeof(newttys1) ); /* 将一段内存区域的内容全清为零 */
newttys1.c_cflag |= (CLOCAL | CREAD); /* CREAD 开启串行数据接收,CLOCAL并打开本地连接模式 */
newttys1.c_cflag &= ~CSIZE; /* 设置数据位数 */
switch ( nBits ) /*选择数据位 */
{
case 7:
newttys1.c_cflag |= CS7;
break;
case 8:
newttys1.c_cflag |= CS8;
break;
}
switch ( nEvent ) /* 设置校验位 */
{
case '0': /* 奇校验 */
newttys1.c_cflag |= PARENB; /* 开启奇偶校验 */
newttys1.c_iflag |= (INPCK | ISTRIP); /* INPCK打开输入奇偶校验;ISTRIP去除字符的第八个比特 */
newttys1.c_cflag |= PARODD; /* 启用奇校验(默认为偶校验) */
break;
case 'E': /* 偶校验 */
newttys1.c_cflag |= PARENB; /* 开启奇偶校验 */
newttys1.c_iflag |= (INPCK | ISTRIP); /* 打开输入奇偶校验并去除字符第八个比特 */
newttys1.c_cflag &= ~PARODD; /* 启用偶校验; */
break;
case 'N': /* 关闭奇偶校验 */
newttys1.c_cflag &= ~PARENB;
break;
}
switch ( nSpeed ) /* 设置波特率 */
{
case 2400:
cfsetispeed( &newttys1, B2400 ); /* 设置输入速度 */
cfsetospeed( &newttys1, B2400 ); /* 设置输出速度 */
break;
case 4800:
cfsetispeed( &newttys1, B4800 );
cfsetospeed( &newttys1, B4800 );
break;
case 9600:
cfsetispeed( &newttys1, B9600 );
cfsetospeed( &newttys1, B9600 );
break;
case 115200:
cfsetispeed( &newttys1, B115200 );
cfsetospeed( &newttys1, B115200 );
break;
default:
cfsetispeed( &newttys1, B9600 );
cfsetospeed( &newttys1, B9600 );
break;
}
if ( nStop == 1 ) /* 设置停止位;若停止位为1,则清除CSTOPB,若停止位为2,则激活CSTOPB。 */
{
newttys1.c_cflag &= ~CSTOPB; /* 默认为送一位停止位; */
}else if ( nStop == 2 )
{
newttys1.c_cflag |= CSTOPB; /* CSTOPB表示送两位停止位; */
}
/* 设置最少字符和等待时间,对于接收字符和等待时间没有特别的要求时 */
newttys1.c_cc[VTIME] = 0; /* 非规范模式读取时的超时时间; */
newttys1.c_cc[VMIN] = 0; /* 非规范模式读取时的最小字符数; */
tcflush( fd, TCIFLUSH ); /* tcflush清空终端未完成的输入/输出请求及数据;TCIFLUSH表示清空正收到的数据,且不读取出来 */
/* 在完成配置后,需要激活配置使其生效 */
if ( (tcsetattr( fd, TCSANOW, &newttys1 ) ) != 0 ) /* TCSANOW不等数据传输完毕就立即改变属性 */
{
perror( "com set error" );
return(-1);
}
return(0);
}
编译
gcc ttytest.c -o ttytest
使用方法就是 ttytest device cmd
python
安装 Python 的串口支持模块
sudo pip install pyserial -i https://pypi.douban.com/simple/
一个简单的串口程序框架
import serial
cmd="AT\r"
ser=serial.Serial('/dev/ttyUSB1',115200)
ser.write(cmd)
print ser.readline()
获取 AT 返回信息的代码,为了避免串口长时间等待加了超时处理
#coding=utf-8
import serial
import signal
import time
ser=serial.Serial('/dev/ttyUSB3',115200)
# Define signal handler function
def myHandler(signum, frame):
print("Recieve timeout!")
exit()
def time_out(fun):
def wrapper(*argv):
signal.signal(signal.SIGALRM, myHandler)
signal.alarm(5)
return fun(*argv)
return wrapper
@time_out
def getRes(cmd):
#保存OK之前的所有接收信息
res=''
#保存每一行的信息
line=''
#发出AT信息
ser.write(cmd)
#死循环
while True:
#读取每一个返回的字符
for c in ser.read():
#添加字符到res和line
res+=c
line+=c
#到达行末
if c == '\n':
#打印输出 便于调试
#print("Line: " + line)
#每一行如果匹配到 OK 或ERROR 则结束循环返回res
if not ((line.find("OK")) == -1):
return res
line = ''
# test start
req="AT+CREG?"
res=getRes(req+"\r")
print "req is "+req+"\nres is:"+res
req="AT+CSQ"
res=getRes(req+"\r")
print "req is "+req+"\nres is:"+res
# test end
测试结果
可以看到返回的一行如果以 +CREG 开头则包含运营商基站信息,其中 AAAA 格式的为 lac , BBBBBB 格式的为 CID ,均为十六进制,我们要提取并转化为十进制
str='''
+CREG: 2,1,AAAA,BBBBBB
OK
'''
lac=int((str.replace("\n","").replace("\r","").split(',')[2]),16)
cid=int((str.replace("\n","").replace("\r","").split(',')[3][:-2]),16)
print lac
print cid
获取API
基站信息获取基站位置
基站定位接口介绍以及API文档 传送门
params={
"mmc":"460",
"mnc":"01",
"lac":"",
"ci":"",
"output":"json",
}
返回范例:
{
"errcode": 0,
"lat": "30.495039",
"lon": "114.392479",
"radius": "403",
"address": "湖北省武汉市洪山区关山街道当代曙光嘉园2号楼-1单元;民族大道与南湖北路路口东南166米"
}
编写脚本从串口拿到的 lac 和 cid 获取基站的经纬度以及其他信息
def getStationLocation(longtitude, latitude):
getURL="http://api.cellocation.com/cell/"
params={
"mmc":"460",
"mnc":"01",
"lac":"",
"ci":"",
"output":"json",
}
try:
rep=urllib.urlopen(getURL,urllib.urlencode(params))
repdict=eval(rep.read())
except Exception, e:
print 'str(Exception):\t', str(Exception)
print 'str(e):\t\t', str(e)
return repdict
经纬度获取地名
上面拿到的只是基站的具体地理位置,我们仍然需要从基站的经纬度确定树莓派的大致位置
我们无法通过经纬度直观的知道自己在哪里,不过有提供好的 API 给我们调用,这里使用 腾讯地图 开放API,现阶段对开发者是免费的。
注册过后拿到开发密钥XXXXX-XXXXX-XXXXX-XXXXX-XXXXX
经纬度信息转为详细地理位置的API使用文档 传送门
返回的格式如下
{
"status": 0,
"message": "query ok",
"request_id": "6269494254796579061",
"result": {
"location": {
"lat": 30.494491,
"lng": 114.399033
},
"address": "湖北省武汉市洪山区民族大道163号桃园路",
"formatted_addresses": {
"recommend": "洪山区桃园路关山荷兰风情园",
"rough": "洪山区桃园路关山荷兰风情园"
},
...
}
脚本调用API获取地理位置
def getRPILocation(longtitude, latitude):
getURL="http://apis.map.qq.com/ws/geocoder/v1/"
params={
"location":longtitude+","+latitude,
"output":"json",
"key":"XXXXX-XXXXX-XXXXX-XXXXX-XXXXX",
}
try:
rep=urllib.urlopen(getURL,urllib.urlencode(params))
repdict=eval(rep.read())
except Exception, e:
print 'str(Exception):\t', str(Exception)
print 'str(e):\t\t', str(e)
return repdict
剩下的工作就是对拿到的 json 数据进行解析提取,比较简单就不做说明
以上所述就是小编给大家介绍的《基于3G模块的树莓派基站定位》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Python
Paul Barry / O'Reilly Media / 2010-11-30 / USD 49.99
Are you keen to add Python to your programming skills? Learn quickly and have some fun at the same time with Head First Python. This book takes you beyond typical how-to manuals with engaging images, ......一起来看看 《Head First Python》 这本书的介绍吧!