Closed samkhan2050 closed 3 years ago
Hi! Flutter is on the roadmap - but currently I never tested dart_periphery with flutter. Do you use flutter-pi for your test?
Hi, Oh, i dont know why i assumed that everything which works on dart would also work on flutter. Yes, i am using flutter-pi. Your package is pretty good as it covers all the peripherals in one package. I would love to see it working on flutter if possible. Since, i have experience working with flutter only, i dont know how to run only dart on RPI. Can you point me in the right direction so i can try. Thanks
Hi! I installed flutter-pi on my rasperry pi - I will try to nail down the problem. Peter
Hi!
There is a workaround for your problem - please use the setCustomLibrary() method to set the absolute path to the native library https://github.com/pezi/dart_periphery/blob/main/lib/src/native/dart_periphery_static_32.1.0.0.so Version 0.8.7-beta - please run pub get to update dart_periphery
setCustomLibrary('/home/pi/test/test/dart_periphery_static_32.1.0.0.so');
I2C i2c = I2C(1);
info = i2c.getI2Cinfo();
Reason for this problem - the mechanism for resolving the absolute path of a file inside a package is a little weired in Dart . I used following code from this project. But this code fails inside the flutter-pi environment.
Please, do not close this issue - I will investigate which is the best fix for this problem - documentation, or a code fix.
@pezi HI, thanks, your solution worked, Now i can access the I2C port. Really appreciate your support. I will be doing some more tests related to the functionality, i will keep you posted if you want for further improvement.
Hi, Sorry to bother you again, but i was just wondering how to add additional libraries to the package. For example, i am going to use an MPU6050 Accelerometer on I2C bus. There is a standard C library available for this at this link: https://github.com/Harinadha/STM32_MPU6050lib.
Can i simply add it to the folder C:\flutter.pub-cache\hosted\pub.dartlang.org\dart_periphery-0.8.8-beta\lib\src\hardware or to C:\flutter.pub-cache\hosted\pub.dartlang.org\dart_periphery-0.8.8-beta\lib\src\native, or do i have to carry out some additional steps. I am sorry if its a stupid question, but i am just a beginner in this field. Thanks.
You can not directly add a C library. You must write a Dart<->C library binding using dart:ffi to be able to call native methods.
dart_periphery uses this mechanism to bind the c-periphery library. dart_periphery was developed to be able access the I2C bus from Dart. This is fine, but if a sensor implementation is missing, you must port code from C or Java to Dart.
I started the porting of some popular environment sensors. BMP280 using this project diozero as a template.
I found a simple MPU6050 implementation for the arduino. https://elektro.turanis.de/html/prj075/index.html#h8
But porting sensor code is a puzzling job.
If you are little patient - I can write code for this sensor - using this source https://elektro.turanis.de/html/prj075/index.html#h8.
You can not directly add a C library. You must write a Dart<->C library binding using dart:ffi to be able to call native methods.
dart_periphery uses this mechanism to bind the c-periphery library. dart_periphery was developed to be able access the I2C bus from Dart. This is fine, but if a sensor implementation is missing, you must port code from C or Java to Dart.
I started the porting of some popular environment sensors. BMP280 using this project diozero as a template.
I found a simple MPU6050 implementation for the arduino. https://elektro.turanis.de/html/prj075/index.html#h8
But porting sensor code is a puzzling job.
Oh, i understand. Thanks for the explanation
If you are little patient - I can write code for this sensor - using this source https://elektro.turanis.de/html/prj075/index.html#h8.
That would be awesome. I look forward to it. In the meantime, if you know any online tutorial which i can follow to learn how to use Dart FFi to port an external C Library. Please advise, so that i can also add some libraries to your package if possible. Thanks
My first version of the MPU6550 sensor code written in Dart is ready. I ordered a MPU6550 sensor over Amazon - the sensor will be delivered tomorrow - so I can test new code.
Thanks a lot! Really appreciate your help
Please update to 0.8.9-beta - First version of MPU6050 sensor support is available https://github.com/pezi/dart_periphery/blob/main/example/MPU6050_test.dart
Please, do not forget to upate also the https://github.com/pezi/dart_periphery/blob/main/lib/src/native/dart_periphery_static_32.1.0.0.so binary inside the flutter environment.
Please be aware this MPU6050 sensor code is out-of-the box from https://elektro.turanis.de/html/prj075/index.html#h8
The better way would be to port this code https://github.com/Raspoid/raspoid/blob/master/src/main/com/raspoid/additionalcomponents/MPU6050.java Seems to be more complete than the snippet code.
Also this Java code can be used to verifying the ported Dart code - but this task would be more time consuming. If you need this code for a commerical project, you can contact me for developing a professional dart version of this sensor.
I closed this issue - docu update for flutter-pi is available and a correct exception is available for the flutter-pi environment.
Thanks @pezi. Really appreciate it. I may contact you in a few days for a commercial development separately.
Hi, I made the changes and tried using the MPU 6050, but i am getting only a set value of Acc and Gyro. Its not changing at all. When i tried printing the various intermittent values, i figured that the buffer is getting only zeros. Here is my minor modifications with just extra print commands and the output i am getting. I double checked the MPU 6050 wiring connections as well.
import 'package:dart_periphery/dart_periphery.dart';
import 'package:dart_periphery/src/hardware/util.dart';
import 'dart:io';
const int MPU6050_ADRESS = 0x68;
const int ACCEL_OFFSET = 200;
const int GYRO_OFFSET = 151; // 151
const int GYRO_SENSITITY = 131; // 131 is sensivity of gyro from data sheet
const double GYRO_SCALE = 0.2; // 0.02 by default - tweak as required
const double LOOP_TIME = 0.15; // 0.
int map(int x, int inMin, int inMax, int outMin, int outMax) =>
(x - inMin) * (outMax - outMin) ~/ (inMax - inMin) + outMin;
int constrain(int amt, int low, int high) =>
((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)));
class MPU6050 {
final I2C i2c;
MPU6050(this.i2c) {
i2c.writeByte(MPU6050_ADRESS, 0x6B);
print('I2C ID: ${i2c.getI2Cfd()}');
print('I2C INFO: ${i2c.getI2Cinfo()}');
print('I2C READBYTE: ${i2c.readByte(MPU6050_ADRESS)}');
i2c.writeByte(MPU6050_ADRESS, 0);
}
void getValues() {
i2c.writeByte(MPU6050_ADRESS, 0x3B);
var buf = ByteBuffer(i2c.readBytes(MPU6050_ADRESS, 14), ByteBufferSrc.I2C,
BitOrder.MSB_LAST);
print('Buffer: ${buf.data}');
var accAngle = <int>[];
var gyroAngle = <double>[];
double temperature;
for (var i = 0; i < 3; ++i) {
var accCorr = buf.getInt16() - ACCEL_OFFSET;
print('Initial AccCorr: $accCorr');
accCorr = map(accCorr, -16800, 16800, -90, 90);
print('Mapped AccCorr: $accCorr');
accAngle.add(constrain(accCorr, -90, 90));
print('AccAngle: $accAngle');
}
temperature = (buf.getInt16() + 12412.0) / 340.0;
for (var i = 0; i < 3; ++i) {
var gyroCorr = ((buf.getInt16() / GYRO_SENSITITY) - GYRO_OFFSET);
gyroAngle.add((gyroCorr * GYRO_SCALE) * -LOOP_TIME);
}
print(
'ACCEL_X: ${accAngle[0]} ACCEL_Y: ${accAngle[1]} ACCEL_Z: ${accAngle[2]}');
print('Temperature: ${temperature.toStringAsFixed(2)}');
print(
'GYRO_XOUT: ${gyroAngle[0]} GYRO_YOUT: ${gyroAngle[1]} GYRO_ZOUT: ${gyroAngle[2]}');
}
}
void main() {
setCustomLibrary('/home/pi/test8/dart_periphery_static_32.1.0.0.so');
var i2c = I2C(1);
print('I2C Path: ${i2c.path}');
print('I2C Path: ${i2c.busNum}');
try {
var mpu = MPU6050(i2c);
while (true) {
mpu.getValues();
sleep(Duration(milliseconds: (LOOP_TIME * 1000).toInt()));
}
} finally {
i2c.dispose();
}
}
OUTPUT:
lutter: I2C Path: /dev/i2c-1 flutter: I2C Path: 1 flutter: I2C ID: 25 flutter: I2C INFO: I2C (fd=25) flutter: I2C READBYTE: 64 flutter: Buffer: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2, -2] flutter: ACCEL_X: -2 ACCEL_Y: -2 ACCEL_Z: -2 flutter: Temperature: 36.51 flutter: GYRO_XOUT: 4.53 GYRO_YOUT: 4.53 GYRO_ZOUT: 4.53 flutter: Buffer: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2, -2] flutter: ACCEL_X: -2 ACCEL_Y: -2 ACCEL_Z: -2 flutter: Temperature: 36.51 flutter: GYRO_XOUT: 4.53 GYRO_YOUT: 4.53 GYRO_ZOUT: 4.53 flutter: Buffer: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2, -2] flutter: ACCEL_X: -2 ACCEL_Y: -2 ACCEL_Z: -2 flutter: Temperature: 36.51 flutter: GYRO_XOUT: 4.53 GYRO_YOUT: 4.53 GYRO_ZOUT: 4.53 flutter: Buffer: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2, -2] flutter: ACCEL_X: -2 ACCEL_Y: -2 ACCEL_Z: -2 flutter: Temperature: 36.51 flutter: GYRO_XOUT: 4.53 GYRO_YOUT: 4.53 GYRO_ZOUT: 4.53 flutter: Buffer: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2, -2] flutter: ACCEL_X: -2 ACCEL_Y: -2 ACCEL_Z: -2 flutter: Temperature: 36.51 flutter: GYRO_XOUT: 4.53 GYRO_YOUT: 4.53 GYRO_ZOUT: 4.53 flutter: Buffer: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2, -2] flutter: ACCEL_X: -2 ACCEL_Y: -2 ACCEL_Z: -2 flutter: Temperature: 36.51 flutter: GYRO_XOUT: 4.53 GYRO_YOUT: 4.53 GYRO_ZOUT: 4.53 flutter: Buffer: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2] flutter: Initial AccCorr: -200 flutter: Mapped AccCorr: -2 flutter: AccAngle: [-2, -2, -2] flutter: ACCEL_X: -2 ACCEL_Y: -2 ACCEL_Z: -2 flutter: Temperature: 36.51 flutter: GYRO_XOUT: 4.53 GYRO_YOUT: 4.53 GYRO_ZOUT: 4.53
Sorry for this mess - I released this code too fast.
I think the problem is caused by
var buf = ByteBuffer(i2c.readBytesReg(MPU6050_ADRESS, 0x3B, 14),
ByteBufferSrc.I2C, BitOrder.MSB_FIRST);
as a replacment for the arduino
Wire.requestFrom(MPU6050_ADRESS, 7*2, true)
which waits until 14 bytes are available.
If you take a look at https://github.com/Harinadha/STM32_MPU6050lib/blob/master/MPU6050.c
void MPU6050_I2C_BufferRead(u8 slaveAddr, u8* pBuffer, u8 readAddr, u16 NumByteToRead)
the way of reading data is more complicated.
Ups - i found an error - the byte order was wrong - now the temperature seems to be correct - currently I can not test the sensor - the pins header isn't soldered, only trapped by a weight. I must solder the pin in the company.
import 'package:dart_periphery/dart_periphery.dart';
import 'package:dart_periphery/src/hardware/util.dart';
import 'dart:io';
const int MPU6050_ADRESS = 0x68;
const int ACCEL_OFFSET = 200;
const int GYRO_OFFSET = 151; // 151
const int GYRO_SENSITITY = 131; // 131 is sensivity of gyro from data sheet
const double GYRO_SCALE = 0.2; // 0.02 by default - tweak as required
const double LOOP_TIME = 0.15; // 0.
int map(int x, int inMin, int inMax, int outMin, int outMax) =>
(x - inMin) * (outMax - outMin) ~/ (inMax - inMin) + outMin;
int constrain(int amt, int low, int high) =>
((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)));
class MPU6050 {
final I2C i2c;
MPU6050(this.i2c) {
i2c.writeByteReg(MPU6050_ADRESS, 0x6B, 0);
print('I2C ID: ${i2c.getI2Cfd()}');
print('I2C INFO: ${i2c.getI2Cinfo()}');
}
void getValues() {
var buf = ByteBuffer(i2c.readBytesReg(MPU6050_ADRESS, 0x3b, 14),
ByteBufferSrc.I2C, BitOrder.MSB_FIRST);
print('Buffer: ${buf.data}');
var accAngle = [];
var gyroAngle = [];
double temperature;
for (var i = 0; i < 3; ++i) {
var accCorr = buf.getInt16() - ACCEL_OFFSET;
print('Initial AccCorr: $accCorr');
accCorr = map(accCorr, -16800, 16800, -90, 90);
print('Mapped AccCorr: $accCorr');
accAngle.add(constrain(accCorr, -90, 90));
print('AccAngle: $accAngle');
}
temperature = buf.getInt16() / 340.0 + 36.53;
for (var i = 0; i < 3; ++i) {
var gyroCorr = ((buf.getInt16() / GYRO_SENSITITY) - GYRO_OFFSET);
gyroAngle.add((gyroCorr * GYRO_SCALE) * -LOOP_TIME);
}
print(
'ACCEL_X: ${accAngle[0]} ACCEL_Y: ${accAngle[1]} ACCEL_Z: ${accAngle[2]}');
print('Temperature: ${temperature.toStringAsFixed(2)}');
print(
'GYRO_XOUT: ${gyroAngle[0]} GYRO_YOUT: ${gyroAngle[1]} GYRO_ZOUT: ${gyroAngle[2]}');
}
}
void main() {
var i2c = I2C(1);
print('I2C Path: ${i2c.path}');
print('I2C Path: ${i2c.busNum}');
try {
var mpu = MPU6050(i2c);
while (true) {
mpu.getValues();
sleep(Duration(milliseconds: (LOOP_TIME * 1000).toInt()));
}
} finally {
i2c.dispose();
}
}
Thanks a lot. Your solution worked. I created a small code just to get the data in a stream and display it in a small widget so that the whole screen doesn't rebuild on every value change from the sensor. Below is the code for anyone who may need it. your just have to call Homepage() from your main.dart file. Added are some tripping levels for the angles, temp and gyro values with a basic UI of change in the background color with the tripping values. Also, there is a small error in the code which goes off once the sensor start streaming values, so it wont be a testing problem. I will remove it later. Hope it helps someone.
import 'package:flutter/material.dart';
import 'package:dart_periphery/dart_periphery.dart';
// ignore: implementation_imports
import 'package:dart_periphery/src/hardware/util.dart';
const int MPU6050_ADRESS = 0x68;
const int ACCEL_OFFSET = 200;
const int GYRO_OFFSET = 151; // 151
const int GYRO_SENSITITY = 131; // 131 is sensivity of gyro from data sheet
const double GYRO_SCALE = 0.2; // 0.02 by default - tweak as required
const double LOOP_TIME = 0.15; // 0.
int map(int x, int inMin, int inMax, int outMin, int outMax) =>
(x - inMin) * (outMax - outMin) ~/ (inMax - inMin) + outMin;
int constrain(int amt, int low, int high) =>
((amt) < (low) ? (low) : ((amt) > (high) ? (high) : (amt)));
class MPU6050 {
final I2C i2c;
MPU6050(this.i2c) {
i2c.writeByteReg(MPU6050_ADRESS, 0x6B, 0);
print('I2C ID: ${i2c.getI2Cfd()}');
print('I2C INFO: ${i2c.getI2Cinfo()}');
}
Map<String, double> getValues() {
Map<String, double> dataMap = {};
var buf = ByteBuffer(i2c.readBytesReg(MPU6050_ADRESS, 0x3b, 14),
ByteBufferSrc.I2C, BitOrder.MSB_FIRST);
print('Buffer: ${buf.data}');
List<int> accAngle = [];
var gyroAngle = [];
double temperature;
for (var i = 0; i < 3; ++i) {
var accCorr = buf.getInt16() - ACCEL_OFFSET;
print('Initial AccCorr: $accCorr');
accCorr = map(accCorr, -16800, 16800, -90, 90);
print('Mapped AccCorr: $accCorr');
accAngle.add(constrain(accCorr, -90, 90));
print('AccAngle: $accAngle');
}
temperature = buf.getInt16() / 340.0 + 36.53;
for (var i = 0; i < 3; ++i) {
var gyroCorr = ((buf.getInt16() / GYRO_SENSITITY) - GYRO_OFFSET);
gyroAngle.add((gyroCorr * GYRO_SCALE) * -LOOP_TIME);
}
print(
'ACCEL_X: ${accAngle[0]} ACCEL_Y: ${accAngle[1]} ACCEL_Z: ${accAngle[2]}');
print('Temperature: ${temperature.toStringAsFixed(2)}');
print(
'GYRO_XOUT: ${gyroAngle[0]} GYRO_YOUT: ${gyroAngle[1]} GYRO_ZOUT: ${gyroAngle[2]}');
dataMap = {
'AngleX': accAngle[0].toDouble(),
'AngleY': accAngle[1].toDouble(),
'AngleZ': accAngle[2].toDouble(),
'Temp': temperature.toDouble(),
'GyroX': gyroAngle[0].toDouble(),
'GyroY': gyroAngle[1].toDouble(),
'GyroZ': gyroAngle[2].toDouble()
};
return dataMap;
}
}
class AngleWidget extends StatefulWidget {
final Map<String, double> dataMap;
AngleWidget(this.dataMap);
@override
_AngleWidgetState createState() => _AngleWidgetState();
}
class _AngleWidgetState extends State<AngleWidget> {
@override
Widget build(BuildContext context) {
final data = widget.dataMap;
return Container(
child: ListView(
children: [
ListTile(
title: Text('Angle X'),
trailing: Text(data['AngleX'].toStringAsFixed(0)),
tileColor: data['AngleX'] > 20 || data['AngleX'] < -20
? Colors.red
: Colors.grey[50],
),
ListTile(
title: Text('Angle Y'),
trailing: Text(data['AngleY'].toStringAsFixed(0)),
tileColor: data['AngleY'] > 20 || data['AngleY'] < -20
? Colors.red
: Colors.grey[50],
),
ListTile(
title: Text('Angle Z'),
trailing: Text(data['AngleZ'].toStringAsFixed(0)),
tileColor: data['AngleZ'] > 20 || data['AngleZ'] < -20
? Colors.red
: Colors.grey[50],
),
ListTile(
title: Text('Gyro X'),
trailing: Text(data['GyroX'].toStringAsFixed(2)),
tileColor: data['GyroX'] > 5 || data['GyroX'] < -5
? Colors.red
: Colors.grey[50],
),
ListTile(
title: Text('Gyro Y'),
trailing: Text(data['GyroY'].toStringAsFixed(2)),
tileColor: data['GyroY'] > 5 || data['GyroY'] < -5
? Colors.red
: Colors.grey[50],
),
ListTile(
title: Text('Gyro Z'),
trailing: Text(data['GyroZ'].toStringAsFixed(2)),
tileColor: data['GyroZ'] > 5 || data['GyroZ'] < -5
? Colors.red
: Colors.grey[50],
),
ListTile(
title: Text('Temperature'),
trailing: Text(data['Temp'].toStringAsFixed(2)),
tileColor: data['Temp'] > 30 || data['Temp'] < 20
? Colors.red
: Colors.grey[50],
),
],
),
);
}
}
class HomePage extends StatefulWidget {
@override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
Map<String, double> anglesMap = {};
Stream<Map<String, double>> angleStream() async* {
var mpu = MPU6050(I2C(1));
while (true) {
await Future.delayed(Duration(milliseconds: (LOOP_TIME * 1000).toInt()));
anglesMap = mpu.getValues();
yield anglesMap;
}
}
@override
void initState() {
setCustomLibrary('/home/pi/test8/dart_periphery_static_32.1.0.0.so');
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('RPI MPU6050 Demo'),
),
body: Center(
child: Container(
padding: EdgeInsets.all(20),
child: StreamBuilder(
builder: (ctx, snapshot) {
return AngleWidget(snapshot.data);
},
stream: angleStream(),
),
),
),
);
}
}
The main problem of the first approach was the wrong combination of the I2C write commands.
i2c.writeByte(MPU6050_ADRESS, 0x6B);
i2c.writeByte(MPU6050_ADRESS, 0);
must be translated from the Ardiono Code as
i2c.writeByteReg(MPU6050_ADRESS, 0x6B, 0);
The Arduino I2C command can to be translated 1:1 is some cases.
FYI: Flutter 2.0 is out - flutter pi has released binaries for this new release and I updated also my package to dart 2.12.0 including null-saftey
Hi, I am running flutter pi on an RPI 3B. When i use the flutter_gpiod package, it works well and i can access the GPIOs but when i try using dart_periphery and test a basic I2C function, i get an error as below. I dont know what is the issue or what to check.
Code: var i2c = I2C(1); try { print('I2C info:' + i2c.getI2Cinfo()); } finally { i2c.dispose(); }
Error: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════ flutter: The following ArgumentError was thrown building MyHomePage(dirty, state: _MyHomePageState#9daba): flutter: Invalid argument(s): join(null, "src", "native", "dart_periphery_32.1.0.0.so"): part 0 was null, but flutter: part 1 was not.