倪祺婷 林建宏 楊宗凱
RPI3 :
L298N :
其他器材 :
項目 | 數量 | 項目 | 數量 |
---|---|---|---|
麵包版供電模組 | 一個 | L298N | 一個 |
18650電池 | 二個 | 電池盒 | 一個 |
馬達 | 一個 | 測速盤 | 一個 |
RPI3 | 一台 | 7697 | 一個 |
光柵 | 二個 | 手機 | 一台 |
server利用Rpi來架設(MQTT),並提供wifi熱點,讓手機、7697得以接收及發送訊息
手機App連接Terminal 來接收、控制轉速 / 7967連接Terminal 來接收控制、回傳轉速
7697輸出pwm訊號來控制馬達轉速 (0-255)
7697利用測速盤(20格)和光柵回傳的資料來測得實際轉速並反饋
Miles若不易擺放則只使用一個光柵
利用impulse去測馬達,藉此得到系統的全貌,從光柵得到數位資料及類比資料
將光柵視為開關,利用7697的 Timer 及 外部中斷來測量轉速
再利用7697的wifi傳給手機端
Miles 1.轉盤20孔 每18度 Timer每1ms 計數一次
2.可以試試BLE
3. 類比模式只能測量透明度及調整感測器靈敏度
利用
完成馬達轉速計
項目 | 數量 | 項目 | 數量 |
---|---|---|---|
麵包版供電模組 | 一個 | L298N | 一個 |
18650電池 | 二個 | 電池盒 | 一個 |
馬達 | 一個 | 測速盤 | 一個 |
arduino | 一台 | 7697 | 一個 |
光柵 | 二個 | 手機 | 一台 |
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 11); // RX, TX
#include <LBLE.h>
#include <LBLEPeriphral.h>
LBLEService ledService("19B10010-E8F2-537E-4F6C-D104768A1214");
LBLECharacteristicString switchCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", LBLE_READ | LBLE_WRITE);
String text="";
const int motorin1 = 16;
const int motorin2 = 17;
const int mul[4] = {1000,100,10,1};
int count = 3;
bool flag=false;
// speed is rpm
int required_speed = 810;
int now_speed = 0;
bool at_range=false;
int now_pwm = 160;
int boundarylarge = 100;
int boundarymid = 50;
int boundarysmall = 10;
int pwm_count=0;
void setup() {
Serial.begin(9600); //設定baud rate
pinMode(motorin1,OUTPUT);
pinMode(motorin2,OUTPUT);
analogWrite(motorin1,now_pwm);
analogWrite(motorin2,0);
while (!Serial) {
;
}
Serial.println("Goodnight moon!");
mySerial.begin(4800);
LBLE.begin();
while (!LBLE.ready()) {
delay(100);
}
Serial.println("BLE ready");
detect_bound();
Serial.print("Device Address = [");
Serial.print(LBLE.getDeviceAddress());
Serial.println("]");
LBLEAdvertisementData advertisement;
advertisement.configAsConnectableDevice("BLE MOTOR");
LBLEPeripheral.setName("BLE MOTOR");
ledService.addAttribute(switchCharacteristic);
LBLEPeripheral.addService(ledService);
LBLEPeripheral.begin();
LBLEPeripheral.advertise(advertisement);
}
void loop() {
if(mySerial.available() ) { // 有收到數值時,會回傳>0的值
char i = mySerial.read();
if(i=='.')
{
flag=true;
}
else
{
if(flag)
{
if(i<='9'&&i>='0')
{
now_speed += (int)(i-'0')*mul[count] ;
count--;
if(count==-1)
{
pwm_set();
send_data(now_speed);
// 傳送data給手機
count = 3; now_speed = 0;
flag=false;
}
}
}
}
}
LBLEPeripheral.connected();
//Serial.print("conected=");
//Serial.println(LBLEPeripheral.connected());
/*if (digitalRead(6)) // 斷線
{
Serial.println("disconnect all!");
LBLEPeripheral.disconnectAll();
}*/
if (switchCharacteristic.isWritten()) { // 接收到手機資料
text = switchCharacteristic.getValue();
required_speed = text.toInt();
at_range=false;
Serial.println(required_speed);
detect_bound();
}
}
//傳資料
void send_data(int data) {
switchCharacteristic.setValue(String(data));
LBLEPeripheral.notifyAll(switchCharacteristic);
}
void pwm_set() {
if(at_range)
{
if(abs(now_speed-required_speed)>boundarysmall)
{
++pwm_count;
}
else
{
pwm_count=0;
}
if(pwm_count>=3)
{
at_range=false;
}
}
else
{
int x=now_speed-required_speed;
int y = abs(x);
if(x>=0)
{
if(y>=boundarylarge)
{
now_pwm-=5;
}
else if (y>=boundarymid)
{
now_pwm-=2;
}
else if (y>=boundarysmall)
{
now_pwm-=1;
}
else
{
at_range=true;
}
}
else
{
if(y>=boundarylarge)
{
now_pwm+=5;
}
else if (y>=boundarymid)
{
now_pwm+=2;
}
else if (y>=boundarysmall)
{
now_pwm+=1;
}
else
{
at_range=true;
}
}
}
if(now_pwm<100)
now_pwm=100;
if(now_pwm>210)
now_pwm=210;
analogWrite(motorin1,now_pwm);
analogWrite(motorin2,0);
Serial.print("now_pwm : ");
Serial.println(now_pwm);
}
void detect_bound()
{
boundarysmall=(int)(5+(required_speed-700)/28\\\\\\\\
3.20);
boundarylarge=boundarysmall+100;
boundarymid=boundarysmall+50;
}
#include <SoftwareSerial.h>
SoftwareSerial mySerial(15,14);//RX TX
unsigned long count=0;
int counterPin = 2;
unsigned long time2;
unsigned long rpm;
unsigned int grid_num = 16;
void counter() {
count++;
}
void setup() {
Serial.begin(9600);
mySerial.begin(4800);
// pinMode(counterPin, INPUT);
attachInterrupt(0, counter, RISING);
count = 0;
rpm = 0;
time2 = 0;
}
void loop() {
if (millis() - time2 >= 1000){ /* 每秒更新 */
// 計算 rpm 時,停止計時
detachInterrupt(0);
// 偵測的格數count * (60 * 1000 / 一圈網格數20)/ 時間差)
rpm=60000*count/grid_num;
rpm = rpm/ (millis() - time2);
count = 0;
// 輸出至Console
Serial.print("RPM = ");
Serial.println(rpm,DEC);
for(int i=0;i<4;i++) {
int data = rpm%10;
mySerial.print(data);
rpm /= 10;
}
mySerial.print('.');;
//Restart the interrupt processing
time2 = millis();
attachInterrupt(0, counter, RISING);
}
}
package org.hopto.pipe.ble_motor;
import android.Manifest;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothManager;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanRecord;
import android.bluetooth.le.ScanResult;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.os.Build;
import android.os.Handler;
import android.os.ParcelUuid;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import android.widget.ArrayAdapter;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private BluetoothAdapter mBluetoothAdapter;
private static final int REQUEST_ENABLE_BT = 2;
private BluetoothManager mBluetoothManager;
private Handler mHandler;
private ArrayList<String> deviceName;
private ArrayList<BluetoothDevice> mBluetoothDevices=new ArrayList<BluetoothDevice>();
private static final int REQUEST_CODE_ACCESS_COARSE_LOCATION = 1;
private ListAdapter adapter;
private BluetoothLeScanner scanner;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ListView listview = (ListView) findViewById(R.id.list);
if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
final BluetoothManager bluetoothManager =
(BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
mBluetoothAdapter = bluetoothManager.getAdapter();
deviceName=new ArrayList<String>();
adapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_1,deviceName) {
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
TextView text = (TextView) view.findViewById(android.R.id.text1);
text.setTextColor(Color.WHITE);
return view;
}
};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this,
Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(this,
Manifest.permission.ACCESS_COARSE_LOCATION)) {
}
ActivityCompat.requestPermissions(this,
new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},
REQUEST_CODE_ACCESS_COARSE_LOCATION);
}
}
listview.setAdapter(adapter);
listview.setOnItemClickListener(onClickListView);
mHandler=new Handler();
scanner = mBluetoothAdapter.getBluetoothLeScanner();
}
public void startScanning(){
deviceName.clear();
mBluetoothDevices.clear();
((BaseAdapter)adapter).notifyDataSetChanged();
scanner = mBluetoothAdapter.getBluetoothLeScanner();
scanner.startScan(new MyScanCallback());
}
public void stopScanning()
{
scanner = mBluetoothAdapter.getBluetoothLeScanner();
scanner.stopScan(new MyScanCallback());
}
private AdapterView.OnItemClickListener onClickListView = new AdapterView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// Toast 快顯功能 第三個參數 Toast.LENGTH_SHORT 2秒 LENGTH_LONG 5秒
Toast.makeText(MainActivity.this,"點選第 "+(position +1) +" 個 \n內容:"+parent.getAdapter().getItem(position), Toast.LENGTH_SHORT).show();
final BluetoothDevice mBluetoothDevice=mBluetoothDevices.get(position);
Log.d("device choose",mBluetoothDevice.toString());
Intent goControlIntent=new Intent(MainActivity.this,control.class);
//將device Name與address存到ControlActivity的DEVICE_NAME與ADDRESS,以供ControlActivity使用
goControlIntent.putExtra("name",mBluetoothDevice.getName());
goControlIntent.putExtra("address",mBluetoothDevice.getAddress());
stopScanning();
startActivity(goControlIntent);
}
};
public void scan_click(View view){
Toast.makeText(MainActivity.this,"Begin scan", Toast.LENGTH_SHORT).show();
startScanning();
}
public void stop_click(View view){
Toast.makeText(MainActivity.this,"Stop scan", Toast.LENGTH_SHORT).show();
stopScanning();
}
@Override
protected void onResume() {
super.onResume();
if(!mBluetoothAdapter.isEnabled()){
Intent intent=new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(intent,REQUEST_ENABLE_BT);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(REQUEST_ENABLE_BT==2 && resultCode== Activity.RESULT_CANCELED){
finish();
return;
}
super.onActivityResult(requestCode, resultCode, data);
}
public class MyScanCallback extends ScanCallback {
@Override
public void onScanResult(int callbackType, final ScanResult result) {
BluetoothDevice device = result.getDevice();
if(mBluetoothDevices.contains(device))
return;
mBluetoothDevices.add(device);
String deviceInfo = device.getName() + " - " + device.getAddress();
ScanRecord scanRecord = result.getScanRecord();
List<ParcelUuid> uuids = scanRecord.getServiceUuids();
if(uuids != null) {
for(int i = 0; i < uuids.size(); i++) {
deviceInfo += "\n" + uuids.get(i).toString();
}
}
final String text = deviceInfo;
Log.d("res",text );
deviceName.add(text);
((BaseAdapter)adapter).notifyDataSetChanged();
}
@Override
public void onBatchScanResults(List<ScanResult> results) {
//Do something with batch of results
}
@Override
public void onScanFailed(int errorCode) {
Log.d("error","Cannot scan");
Toast.makeText(MainActivity.this,"Cannot scan", Toast.LENGTH_SHORT).show();
}
}
}
package org.hopto.pipe.ble_motor;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.content.Intent;
import android.net.NetworkInfo;
import android.os.Handler;
import android.os.Message;
import android.os.ParcelUuid;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.TextPaint;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListAdapter;
import android.widget.ListView;
import android.widget.Toast;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class control extends AppCompatActivity {
private String name;
private String address;
private BluetoothGatt mGatt = null ;
private BluetoothDevice device;
private BluetoothAdapter adapter;
private ArrayList< BluetoothGattService> service_list=new ArrayList< BluetoothGattService>();
private int state;
private ListAdapter listadapter;
private ArrayList<String> serviceName;
private boolean done;
private Handler mHandler ;
private ListView listview;
private TextInputLayout Input;
private Button returnlist;
private Button send;
private EditText textfield;
private BluetoothGattCharacteristic characteristic=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_control);
listview= (ListView) findViewById(R.id.list1);
Intent intent = getIntent();
name=intent.getStringExtra("name");
address=intent.getStringExtra("address");
Input=( TextInputLayout) findViewById(R.id.motorinput);
returnlist=(Button) findViewById(R.id.re);
send=(Button)findViewById(R.id.send);
textfield=(EditText) findViewById(R.id.text_dis);
Input.setVisibility(View.INVISIBLE);
returnlist.setVisibility(View.INVISIBLE);
send.setVisibility(View.INVISIBLE);
textfield.setVisibility(View.INVISIBLE);
textfield.setKeyListener(null);
Log.d("name",name);
Log.d("address",address);
serviceName=new ArrayList<String>();
final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);
adapter = bluetoothManager.getAdapter();
listadapter = new ArrayAdapter(this,
android.R.layout.simple_list_item_1,serviceName);
device=adapter.getRemoteDevice(address);
listview.setAdapter(listadapter);
listview.setOnItemClickListener(onClickListView);
done=false;
connect_BLE();
mHandler = new Handler(){
@Override
public void handleMessage(Message msg) {
switch(msg.what){
case 1:
((BaseAdapter)listadapter).notifyDataSetChanged();
break;
case 2:
textfield.append(msg.getData().getString("text"));
break;
}
}
};
}
private void connect_BLE() {
ParcelUuid[] uuids = (ParcelUuid[]) device.getUuids();
mGatt = device.connectGatt( this , true , mGattCallback);
textfield.setText("");
Log.d("a",mGatt.toString());
}
private AdapterView.OnItemClickListener onClickListView = new AdapterView.OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// Toast 快顯功能 第三個參數 Toast.LENGTH_SHORT 2秒 LENGTH_LONG 5秒
Toast.makeText(control.this,"點選第 "+(position +1) +" 個 \n內容:"+parent.getAdapter().getItem(position), Toast.LENGTH_SHORT).show();
characteristic=service_list.get(position).getCharacteristics().get(0);
mGatt.setCharacteristicNotification( characteristic,true);
mGatt.readCharacteristic(characteristic);
Input.setVisibility(View.VISIBLE);
returnlist.setVisibility(View.VISIBLE);
send.setVisibility(View.VISIBLE);
textfield.setVisibility(View.VISIBLE);
listview.setVisibility(View.INVISIBLE);
}
};
public void reclick(View view)
{
textfield.setText("");
mGatt.setCharacteristicNotification( characteristic,false);
Input.setVisibility(View.INVISIBLE);
returnlist.setVisibility(View.INVISIBLE);
send.setVisibility(View.INVISIBLE);
textfield.setVisibility(View.INVISIBLE);
listview.setVisibility(View.VISIBLE);
}
public void sendclick(View view) {
byte[] send1=null;
try{
send1 = Input.getEditText().getText().toString().getBytes("UTF-8");
}catch (Exception e)
{
}
if(send1!=null) {
Log.e("dataSend", new String(send1));
characteristic.setValue(send1);
boolean status = mGatt.writeCharacteristic(characteristic);
Log.e("dataSend", status + "");
mGatt.writeCharacteristic(characteristic);
}
}
private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
if (newState == BluetoothProfile.STATE_CONNECTED) {
Log.i("t", "Connected to GATT server.");
// Attempts to discover services after successful connection.
Log.i("t", "Attempting to start service discovery:" + gatt.discoverServices());
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
Log.i("t", "Disconnected from GATT server.");
String address = gatt.getDevice().getAddress();
}
}
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
boolean isGood = true;
for (int i = 0; i < gatt.getServices().size(); i++) {
BluetoothGattService bgs = gatt.getServices().get(i);
Log.w("t", "found service " + bgs.getUuid().toString());
Log.w("t", bgs.getCharacteristics().toString());
service_list.add(bgs);
String text = "found service " + Integer.toString(i + 1) + "\n" + bgs.getUuid().toString();
serviceName.add(text);
if (bgs.getCharacteristics().size() == 0)
isGood = false;
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Message msg = new Message();
msg.what = 1;
mHandler.sendMessage(msg);
} else {
Log.w("t", "onServicesDiscovered received: " + status);
}
if(characteristic!=null)
mGatt.setCharacteristicNotification( characteristic,true);
}
@Override
public void onCharacteristicRead(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {
Log.e("onCharacteristicRead中", "recieve" + new String(characteristic.getValue()));
Message msg = new Message();
msg.what = 2;
Bundle b=new Bundle();
b.putString("text","now speed "+new String(characteristic.getValue())+" (rmp) "+"\n");
msg.setData(b);
mHandler.sendMessage(msg);
}
@Override
public void onCharacteristicWrite(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic, int status) {//发送数据时调用
if (status == BluetoothGatt.GATT_SUCCESS) {//写入成功
Message msg = new Message();
msg.what = 2;
Bundle b=new Bundle();
b.putString("text","寫入成功\n");
msg.setData(b);
mHandler.sendMessage(msg);
} else if (status == BluetoothGatt.GATT_FAILURE) {
Log.e("onCharacteristicWrite中", "fail");
} else if (status == BluetoothGatt.GATT_WRITE_NOT_PERMITTED) {
Log.e("onCharacteristicWrite中", "no permission");
}
}
@Override
public void onCharacteristicChanged(BluetoothGatt gatt,
BluetoothGattCharacteristic characteristic) {// Characteristic 改变,数据接收会调用
Log.e("onCharacteristicChange中", "recieve" + new String(characteristic.getValue()));
Message msg = new Message();
msg.what = 2;
Bundle b=new Bundle();
b.putString("text","now speed "+new String(characteristic.getValue())+" (rmp) "+"\n");
msg.setData(b);
mHandler.sendMessage(msg);
}
};
}