This commit is contained in:
cxc
2022-06-27 09:51:30 +08:00
commit 8cb96b4c5e
101 changed files with 11110 additions and 0 deletions

430
lib/pages/compass_page.dart Normal file
View File

@ -0,0 +1,430 @@
import 'dart:async';
import 'dart:typed_data';
import 'dart:math';
import 'package:fengshui_compass/components/my_icon.dart';
import 'package:fengshui_compass/pages/login_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_serial_port_api/flutter_serial_port_api.dart';
import 'package:stream_transform/stream_transform.dart';
import '../utils/recv_parse.dart';
class CompassPage extends StatefulWidget {
const CompassPage({Key key}) : super(key: key);
@override
State<StatefulWidget> createState() => _CompassState();
}
class _CompassState extends State<CompassPage> {
// 串口相关
bool isPortOpened = false;
SerialPort _serialPort;
StreamSubscription _subscription;
// 传感器状态
bool isLock = true;
bool isUpClose = true;
bool isSideClose = true;
double w_x = 0.5;
double w_y = 0.5;
// 与磁北极夹角
double myaw = 0.0;
String distance = "";
var lista = [];
var listb = [];
var listc = [];
void initDevice() {
}
@override
void initState() {
super.initState();
initPort();
}
Future<void> initPort() async {
// 20ms接收一次串口数据防抖定义接收缓存
final debounceTransformer = StreamTransformer<Uint8List, dynamic>.fromBind(
(s) => s.transform(debounceBuffer(const Duration(milliseconds: 20))));
if (!isPortOpened) {
Device theDevice = Device("/dev/ttyS2", "/dev/ttyS2");
var serialPort = await FlutterSerialPortApi.createSerialPort(
theDevice, 115200,
parity: 0, dataBits: 8, stopBit: 1);
bool openResult = await serialPort.open();
setState(() {
_serialPort = serialPort;
isPortOpened = openResult;
});
await openRange();
_subscription = _serialPort.receiveStream
.transform(debounceTransformer)
.listen((recv) {
// recvData - 9E01040100000000000000065E
String recvData = formatReceivedData(recv);
print("Receive format: $recvData");
parsingRecvCom(recvData);
// 解析收到的结果,得到陀螺、地磁、测距结果
});
await openCompass();
}
}
Future<void> closePort() async {
bool closeResult = await _serialPort.close();
setState(() {
isPortOpened = !closeResult;
});
}
Future<void> openCompass() async {
print("compass open");
_serialPort
.write(Uint8List.fromList(hexToUnits("7E01020100000000000000010D0A")));
}
Future<void> closeCompass() async {
print("compass close");
_serialPort
.write(Uint8List.fromList(hexToUnits("7E01020000000000000000010D0A")));
}
Future<void> openSideLaser() async {
print("side open");
_serialPort
.write(Uint8List.fromList(hexToUnits("7E01010100000000000000010D0A")));
}
Future<void> closeSideLaser() async {
print("side close");
_serialPort
.write(Uint8List.fromList(hexToUnits("7E01010000000000000000010D0A")));
}
Future<void> openUpLaser() async {
_serialPort
.write(Uint8List.fromList(hexToUnits("7e01010300000000000000010d0a")));
}
Future<void> closeUpLaser() async {
_serialPort
.write(Uint8List.fromList(hexToUnits("7e01010200000000000000010d0a")));
}
Future<void> openRange() async {
_serialPort
.write(Uint8List.fromList(hexToUnits("7e01040100000000000000010d0a")));
}
Future<void> raging() async {
if (!isLock) {
switchCompass();
}
_serialPort
.write(Uint8List.fromList(hexToUnits("7e01040200000000000000010d0a")));
}
Future<void> switchCompass() async {
if (isLock) {
await openCompass();
} else {
await closeCompass();
setState(() {
w_x = 0.5;
w_y = 0.5;
});
}
setState(() {
isLock = !isLock;
});
}
loginAction() {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => LoginPage()));
}
parsingRecvCom(str) {
if (str.contains("9E010201") &&
(str.length > (str.indexOf("9E010201") + 50))) {
var roll_l = hexToInt(str.substring(8, 10));
var roll_h = hexToInt(str.substring(10, 12));
var pitch_l = hexToInt(str.substring(12, 14));
var pitch_h = hexToInt(str.substring(14, 16));
// var yaw_l = hexToInt(str.substring(16, 18));
// var yaw_h = hexToInt(str.substring(18, 20));
var pos = str.indexOf("9E010301");
// var mx_h = hexToInt(str.substring(pos+8, pos+10));
// var mx_l = hexToInt(str.substring(pos+10, pos+12));
// var my_h = hexToInt(str.substring(pos+12, pos+14));
var myaw_flag = hexToInt(str.substring(pos+14, pos+16));
var myaw_h = hexToInt(str.substring(pos+16, pos+18));
var myaw_l = hexToInt(str.substring(pos+18, pos+20));
var roll_tmp = (roll_h * 256 + roll_l) * 180 /32768;
var pitch_tmp = (pitch_h * 256 + pitch_l) * 180 /32768;
// var yaw = (yaw_h * 256 + yaw_l) * 180 /32768;
// -180~180
var ff = myaw_flag == 1 ? -1 : 1;
var temp_myaw = (myaw_h *256 + myaw_l) * 0.01 * ff + 180;
if (roll_tmp>180) roll_tmp = roll_tmp -360;
if (pitch_tmp>180) pitch_tmp = pitch_tmp -360;
var w_x_tmp = 0.0;
var w_y_tmp = 0.0;
// 倾角<30度
var w_total = sqrt(roll_tmp.abs()*roll_tmp.abs() + pitch_tmp.abs()*pitch_tmp.abs());
if (w_total <= 30) {
w_y_tmp = 0.5 - 0.07 * roll_tmp / 30.0;
w_x_tmp = 0.5 - 0.07 * pitch_tmp / 30.0;
} else if (w_total > 30) {
//todo
w_y_tmp = 0.5 - 0.07 * w_total /30.0;
w_x_tmp = 0.5 - 0.07 * w_total / 30.0;
}
// todo 其他情况
var meanValue;
if (lista.length < 20) {
lista.add(temp_myaw);
meanValue = null;
} else {
lista.removeAt(0);
lista.add(temp_myaw);
meanValue = lista.map((e) => e).reduce((a, b) => a+b) / lista.length;
}
setState(() {
// print("roll: $roll_tmp pitch: $pitch_tmp");
// print("w_x: $w_x_tmp, w_y: $w_y_tmp");
// if (meanValue != null) {
// myaw = meanValue;
// } else {
// myaw = 0;
// }
myaw = temp_myaw;
w_x = w_x_tmp;
w_y = w_y_tmp;
// 水平仪 0.5+-0.07范围
// x旋转y在动 y旋转x在动 roll改变y坐标pitch改变x坐标
});
} else if (str.contains("9E010401") &&
(str.length >= ((str.indexOf("9E010401") + 26)))) {
var pos = str.indexOf("9E010401");
int rh = hexToInt(str.substring(pos + 16, pos + 18));
int rl = hexToInt(str.substring(pos + 18, pos + 20));
int result = rh * 256 + rl;
print("测距$result");
setState(() {
distance = (result.toDouble() / 1000).toStringAsFixed(2);
});
} else {}
}
@override
Widget build(BuildContext context) {
return Container(
decoration: const BoxDecoration(
image: DecorationImage(
image: AssetImage("assets/images/bg.png"), fit: BoxFit.cover)),
child: Scaffold(
backgroundColor: Colors.transparent,
appBar: AppBar(
backgroundColor: Colors.transparent,
elevation: 0,
centerTitle: true,
title: const Text(
'定盘星',
style: TextStyle(color: Colors.white),
),
leading: IconButton(
color: Colors.amber,
icon: Icon(isLock ? MyIcons.icon_mima : MyIcons.icon_jiesuo),
onPressed: switchCompass,
),
actions: [
//todo
// 更改背景图
IconButton(
color: Colors.amber,
icon: Icon(Icons.person, size: 22,),
onPressed: loginAction,
),
],
),
body: SafeArea(
child: ConstrainedBox(
constraints: const BoxConstraints(minHeight: 600),
child: Stack(
alignment: Alignment.center,
children: [
// 罗盘
Column(
children: [
const Padding(padding: EdgeInsets.only(top: 145)),
Row(
children: [
Spacer(flex: 1),
Container(
width: 700,
height: 700,
child: Stack(
children: [
Transform.rotate(
angle: myaw * pi /360,
child: const Image(
image:
AssetImage("assets/images/compass.png"),
fit: BoxFit.fill),
),
Align(
alignment: FractionalOffset(w_x, w_y),
child: const Image(
image: AssetImage("assets/images/water.png"),
),
)
],
),
),
const Spacer(flex: 1),
],
)
],
),
// 最上面一行, lock azimuth login
Positioned(
top: 5,
child: Column(
children: [
const Image(
width: 15,
height: 15,
image: AssetImage("assets/images/arrow.png"),
fit: BoxFit.contain,
),
Text(
// "${azimuth.toStringAsFixed(2)}",
myaw.toStringAsFixed(2),
style: const TextStyle(
color: Colors.amber, fontSize: 36),
),
],
)),
// 最下面一行ranging value openlaser
Positioned(
bottom: 80,
left: 50,
child: IconButton(
onPressed: raging,
icon: const Icon(
MyIcons.icon_celiang,
size: 34,
),
color: Colors.amber)),
const Positioned(
width: 180,
height: 90,
bottom: 60,
child: Image(
image: AssetImage("assets/images/range_input.png"),
fit: BoxFit.contain,
)),
Positioned(
width: 180,
height: 90,
bottom: 60,
child: Align(
alignment: Alignment.centerRight,
child: Padding(
padding: const EdgeInsets.only(right: 15),
child: Text(
"${distance} m",
style: const TextStyle(
color: Colors.amber, fontSize: 28),
),
),
)),
Positioned(
bottom: 60,
right: 40,
height: 120,
width: 100,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
IconButton(
color: Colors.amber,
onPressed: () {
if (isUpClose) {
openUpLaser();
} else {
closeUpLaser();
}
setState(() {
isUpClose = !isUpClose;
});
},
icon: Icon(
isUpClose
? MyIcons.icon_shangdeng
: MyIcons.icon_shangdnegguanbi,
size: 36)),
IconButton(
color: Colors.amber,
onPressed: () {
if (isSideClose) {
openSideLaser();
} else {
closeSideLaser();
}
setState(() {
isSideClose = !isSideClose;
});
},
icon: Icon(
isSideClose
? MyIcons.icon_zuoyoudneg
: MyIcons.icon_zuoyoudengguanbi,
size: 32,
))
],
),
)
],
),
)),
));
}
}