倪祺婷
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights New
    • Engagement control
    • Make a copy
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Note Insights Versions and GitHub Sync Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Make a copy Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       Owned this note    Owned this note      
    Published Linked with GitHub
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    # 訊號與系統報告 ## 題目 - 光敏電阻或光感應器之應用 * 設計一個轉速計並以之控制馬達轉速 ### Developer: >[name=倪祺婷] [name=林建宏] [name=楊宗凱] ## 實驗器材 RPI3 : ![](https://i.imgur.com/nUasFQ9.jpg) L298N : ![](https://i.imgur.com/ZjBufZt.jpg) 其他器材 : ![](https://i.imgur.com/pT8Cf4D.jpg) | 項目 | 數量 | 項目 | 數量 | | :---: | :---: | :---: | :---: | | 麵包版供電模組|一個| L298N | 一個 | | 18650電池 | 二個 | 電池盒 | 一個 | | 馬達 | 一個 | 測速盤 | 一個 | | RPI3 | 一台 | 7697 | 一個 | | 光柵 | 二個 | 手機 | 一台 | ## 實驗步驟(流程圖) ![](https://i.imgur.com/nRuUZ2r.png) * server利用Rpi來架設(MQTT),並提供wifi熱點,讓手機、7697得以接收及發送訊息 * 手機App連接Terminal 來接收、控制轉速 / 7967連接Terminal 來接收控制、回傳轉速 * 7697輸出pwm訊號來控制馬達轉速 (0-255) * 7697利用測速盤(20格)和光柵回傳的資料來測得實際轉速並反饋 ## 資料處理的方式 - 光閘測轉速 ![](https://i.imgur.com/bsiMTZu.png) ![](https://i.imgur.com/1RP5Qs0.png) * 如圖所示,利用兩個光閘去測轉速,會得出三個數據,分別是 1. 兩個光閘本身的數據, 2. 光閘之間的數據 > [name=Miles]若不易擺放則只使用一個光柵 - 測轉速資料處理方式 1. 利用impulse去測馬達,藉此得到系統的全貌,從光柵得到數位資料及類比資料 2. 將光柵視為開關,利用7697的 Timer 及 外部中斷來測量轉速 3. 再利用7697的wifi傳給手機端 > [name=Miles] 1.轉盤20孔 每18度 Timer每1ms 計數一次 > 2.可以試試BLE > 3. 類比模式只能測量透明度及調整感測器靈敏度 - 控制轉速資料處理方式 1. 若從手機端發出參考速度給7697 2. 7697將速度轉成pwm訊號給l298N模組去控制轉速 3. 對比接收的轉速和實際測得的轉速來處理誤差(反饋) ## 資料處理的方式 - 反饋 ![](https://i.imgur.com/ucGogn5.jpg) ## 預計結果 ![](https://1.bp.blogspot.com/-6-BnAoy7seY/WRmvtLF6hCI/AAAAAAAABF8/GhPOlS6lTlQLNlMWVbPiLmKGQSX7EOIdACLcB/s640/IMG_3800.jpg) * 可利用手機與7697溝通,且7697可將測得的轉速送給手機端來顯示, 手機端也可將所想要的轉速傳給7697去控制馬達轉速 ## 參考資料 1. L298N 介紹 : web.htjh.tp.edu.tw/B4/105-2robot/L298N馬達驅動模組介紹.pdf 2. 光柵 : https://www.openimpulse.com/blog/products-page/product-category/motor-speed-encoder-sensor/ 3. 穩壓模組, 馬達, L298N : https://hackmd.io/s/HJkSu1FoZ 4. Timer : https://docs.labs.mediatek.com/resource/linkit7697-arduino/en/developer-guide/timer -------------------- # 結果呈現 利用 * 一個TT馬達 * 兩個光閘 * arduino * 7697 * 手機APP 完成馬達轉速計 ## 完成圖 ![](https://i.imgur.com/dJqleaw.jpg) ## 流程圖 ![](https://i.imgur.com/gg7V43f.jpg) ## 使用器材 | 項目 | 數量 | 項目 | 數量 | | :---: | :---: | :---: | :---: | | 麵包版供電模組|一個| L298N | 一個 | | 18650電池 | 二個 | 電池盒 | 一個 | | 馬達 | 一個 | 測速盤 | 一個 | | arduino | 一台 | 7697 | 一個 | | 光柵 | 二個 | 手機 | 一台 | ## 系統架構 - 利用arduino mega 來測轉速 (原先是打算由7697來測量) 因 7697 的interrupt 處理速度不夠快,導致光柵無法測量 所以將原本由7697測量的轉速交給arduino - Arduino 利用Rx Tx將量測到的轉速傳給7697 - 7697 利用 BLE 傳現在的轉速給手機端 - 手機端可將想達到的轉速傳給7697,7697利用arduino量到的轉速來調整pwm ## 程式碼 ### 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; } ``` ----------------------- ### Arduino程式碼 ``` #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); } } ``` ---------------------- ### APP程式碼 ``` 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(); } } } ``` ------------- ### APP程式碼 ``` 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); } }; } ``` -------- ## 改進項目 - 更換測速盤格數(4格) - 將TT馬達換成12V直流馬達 - 根據需求的速度去調整容許的誤差範圍 - 在速度的調整上增加誤差容許,以防速度不斷變化 - 獲得資料的方法 ## 遇到的難題 - 網購測速盤未送達 - 光柵訊號問題 - 馬達沒轉arduino卻產生interrupt - interrupt處理問題 - 測速盤格數過多、轉速過快 ## 解決方法 1. 網購測速盤未送達 透過自製轉速盤,在解決該問題下,還可自行設定測速盤格數 (難題3) ![](https://i.imgur.com/g4phWAV.jpg) 2. 光柵訊號問題 礙於使用arduino和7697導致線路有些複雜,經確認後發現是共地的參考點所導致 4. interrupt處理問題 12V直流馬達的轉速比TT馬達還要快許多,所以在使用相同測速盤下,處理速度無法跟上,所以我們調低測速盤的格數,來降低interrupt產生的時間間隔 5. 馬達架設問題 馬達沒地方可以裝支架,只好利用L型支架把它夾住,然後架起來。 ## 改進後的成品 ![](https://i.imgur.com/S1FHRTH.jpg)

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully