加速度センサの利用
今回はsensor_plusを使用して端末のセンサを使用してみます。まず、加速度の方向に合わせて線を描画するコードを書きました。
import 'package:flutter/material.dart';
import 'package:sensors_plus/sensors_plus.dart';
import 'dart:math';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(home: MainView());
}
}
class MainView extends StatefulWidget {
const MainView({super.key});
@override
MainViewState createState() => MainViewState();
}
class MainViewState extends State<MainView> {
var x = 0.0, y = 0.0, z = 0.0;
@override
void initState() {
super.initState();
// 加速度センサからの情報が来たら再描画する
accelerometerEventStream(samplingPeriod: SensorInterval.uiInterval)
.listen((event) {
setState(() {
x = event.x;
y = event.y;
z = event.z;
});
});
}
@override
Widget build(BuildContext context) {
final size = MediaQuery.of(context).size;
return Scaffold(
body: SizedBox(
width: size.width,
height: size.height,
child: CustomPaint(painter: MyPainter(x, y, z))));
}
}
class MyPainter extends CustomPainter {
final double x, y, z;
MyPainter(this.x, this.y, this.z);
@override
void paint(Canvas canvas, Size size) {
final center = size.center(Offset.zero);
final len = size.shortestSide * 0.4 * sqrt(x * x + y * y) / 9.8;
final color = Color.lerp(
Colors.black, z.isNegative ? Colors.red : Colors.blue, z.abs() / 9.8)!;
// xy平面における加速度の方向に合わせてキャンバスを回転する
canvas.translate(center.dx, center.dy);
canvas.rotate(atan2(x, y));
canvas.translate(-center.dx, -center.dy);
canvas.drawLine(
center,
center + Offset(0.0, len),
Paint()
..style = PaintingStyle.stroke
..color = color
..strokeWidth = 5.0
..strokeCap = StrokeCap.round);
}
@override
bool shouldRepaint(covariant CustomPainter oldDelegate) {
return true;
}
}
このコードを実行すると下記のようになります。PCだと加速度センサの情報を取得することができず動かないかもしれませんが、スマートフォンで見ていただくと動くと思います。
端末にもよるかもしれませんが、私の端末だと加速度センサが多少ノイズを拾っているのか線が小刻みにぶれています。そこで、加速度を最新のものに置き換えてしまうのではなく、直近のいくつかの加速度を加味しながら更新していくようにしてみます。
まず、元のコードの26行目を下記のように書き換えて過去5回分の加速度を保持できるようにしました。
var xs = List<double>.filled(5, 0.0),
ys = List<double>.filled(5, 0.0),
zs = List<double>.filled(5, 0.0);
次に元のコードの36〜38行目を書き換えて、古いデータを削除して新しいデータを保持するように修正しました。
xs = [...xs.sublist(1), event.x];
ys = [...ys.sublist(1), event.y];
zs = [...zs.sublist(1), event.z];
最後に元のコードの46行目でMyPainter
に与えるx, y, zを計算するようにしました。その際、直近のデータの重みが大きくなるように計算するようにしました。
final x = xs[0] * 0.05 +
xs[1] * 0.1 +
xs[2] * 0.15 +
xs[3] * 0.2 +
xs[4] * 0.5,
y = ys[0] * 0.05 +
ys[1] * 0.1 +
ys[2] * 0.15 +
ys[3] * 0.2 +
ys[4] * 0.5,
z = zs[0] * 0.05 +
zs[1] * 0.1 +
zs[2] * 0.15 +
zs[3] * 0.2 +
zs[4] * 0.5;
この修正を行った後の動作は下記のようになります。
このコードでは直近5回の加速度をもとに線を描画しているため最初の例よりは安定しているかと思います。
重力を除いた加速度の利用
accelerometerEventStream
のかわりにuserAccelerometerEventStream
を使うと、重力加速度を除いた加速度を取得することが出来ます。実際に置き換えてみたものがこちらになります。
私の端末では残念ながら動作していないように見えています。Androidアプリとしてビルドした場合には動いていたので、ブラウザの問題か設定の問題なのかもしれません。分かり次第、追記したいと思います。
まとめ
この記事ではsensors_plusを使用して加速度を取得しました。sensors_plusで取得できる他のデータについてもいずれ別の記事で触れられたらと思います。
コメント