發布日期:2022-10-09 點擊率:53
package sina.CreAmazing.angle_view;
import android.app.Activity;
import android.content.Context;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.View;
public class AngleViewActivity extends Activity {
//聲明一個SensorManager管理傳感器,一個自定義的類MyView,在myView中繪制自己想要的圖像
private SensorManager sensorManager;
private MyView myView;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//實例化SensorManager
sensorManager=(SensorManager) this.getSystemService(SENSOR_SERVICE);
//DisplayMetrics用于獲取屏幕大小,再傳遞給myView方便繪制圖形界面;
DisplayMetrics display=new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(display);
//構造一個MyView,display.widthPixels是當前屏幕的寬度,display.heightPixels是當前屏幕的高度
myView=new MyView(this, display.widthPixels, display.heightPixels);
//這里就不是在layout文件夾里面的布局文件了,直接就是我們的myView。
setContentView(myView);
}
//在onResume(),onPause()中注冊和解除監聽器
@Override
protected void onResume() {
super.onResume();
sensorManager.registerListener(myView,
sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onPause() {
sensorManager.unregisterListener(myView);
Log.i("unregister", "ok");
super.onStop();
}
}
//自定義的類MyView 因為要感應傳感器所以實現SensorEventListener。
class MyView extends View implements SensorEventListener {
//float x=0;
//float y=0;
//z軸上的值是我們所需要的,z軸就是垂直于水平面的方向,當你水平放置手機是它的數值為10,當你垂直放置時它就為0.
float z=0;
private float width;
private float height;
Paint p ;
public MyView(Context context) {
super(context);
// TODO Auto-generated constructor stub
}
public MyView(Context context, float width, float height) {
super(context);
this.width= width;
this.height= height;
//得到一支畫筆,設置基本屬性
p=new Paint();
p.setStyle(Paint.Style.STROKE);
}
//在onDraw()方法中才是我們真正要畫的東西,也就是真正顯示在屏幕上的圖像
@Override
protected void onDraw(Canvas canvas) {
//首先繪制一張背景圖片,圖片是事先PS好的一張背景圖。canvas就是畫布的意思,我們需要用畫筆 p 在畫布canvas上畫畫。
canvas.drawBitmap(
BitmapFactory.decodeResource(getResources(), R.drawable.circle),
0, 0, p);
//畫背景后還要畫文字,再對畫筆進行設置。
p.setTextSize(50);
//所畫的文字就是實際測得的角度,在這之前需要對z值進行轉化也就是todegree()方法。
canvas.drawText(todegree(z) + "°", width / 2 - 20, height / 2, p);
//畫完后再畫一個圓圈,這個圓圈隨著角度變化而變大變小。
p.setColor(Color.RED);
p.setStrokeWidth(2);
canvas.drawCircle(width / 2, height / 2, 20 * z, p);
}
//如何把當前加速度的值轉化為當前角度值呢?這需要一定的硬件基礎才能明白其中的原理,不懂得同學可以看一些加速度傳感器方面的書,關于加速度
//傳感器還有很多應用,比如速度的測量,位移的測量,這就需要更加復雜的算法了,這里就不再介紹
private String todegree(float zz) {
//首先判斷加速度的值是否大于10,小于-10,這是因為在運動過程中加速是不穩定的,而我們要測的是在靜止狀態下的穩定值。
if (zz > 10) {
zz =10;
} else if (zz < -10) {
zz =-10;
}
//acos(zz / 10)就能求出傾斜角度的弧度值。
double r=Math.acos(zz / 10);
//然后將弧度值轉化為角度值
int degree=(int) (r * 180 / Math.PI);
//最后返回一個String
return String.valueOf(degree);
}
@Override
public void onSensorChanged(SensorEvent event) {
// TODO Auto-generated method stub
// x=event.values[0];
// y=event.values[1];
if(event.sensor.getType()== Sensor.TYPE_ACCELEROMETER){
//獲得z軸的加速度值
z=event.values[2];
}
//調用此方法進行重繪
invalidate();
}
@Override
public void onAccuracyChanged(Sensor sensor, int accuracy) {
// TODO Auto-generated method stub
}
}
MainActivity:
package com.example.sensoreventlistenertest;
import com.example.sensoreventlistenertest.ShakeListener.OnShakeListener;
import android.media.MediaPlayer;
import android.os.Bundle;
import android.os.Handler;
import android.os.Vibrator;
import android.app.Activity;
import android.content.Intent;
import android.view.Gravity;
import android.view.View;
import android.view.Window;
import android.view.animation.Animation;
import android.view.animation.AnimationSet;
import android.view.animation.TranslateAnimation;
import android.widget.Button;
import android.widget.RelativeLayout;
import android.widget.SlidingDrawer;
import android.widget.Toast;
import android.widget.SlidingDrawer.OnDrawerCloseListener;
import android.widget.SlidingDrawer.OnDrawerOpenListener;
public class MainActivity extends Activity{
}
public void startAnim () { //定義搖一搖動畫動畫
AnimationSet animup = new AnimationSet(true);
TranslateAnimation mytranslateanimup0 = new TranslateAnimation(Animation.RELATIVE_TO_SELF,0f,Animation.RELATIVE_TO_SELF,0f,Animation.RELATIVE_TO_SELF,0f,Animation.RELATIVE_TO_SELF,-0.5f);
mytranslateanimup0.setDuration(1000);
TranslateAnimation mytranslateanimup1 = new TranslateAnimation(Animation.RELATIVE_TO_SELF,0f,Animation.RELATIVE_TO_SELF,0f,Animation.RELATIVE_TO_SELF,0f,Animation.RELATIVE_TO_SELF,+0.5f);
mytranslateanimup1.setDuration(1000);
mytranslateanimup1.setStartOffset(1000);
animup.addAnimation(mytranslateanimup0);
animup.addAnimation(mytranslateanimup1);
mImgUp.startAnimation(animup);
}
晃動監聽activity:
package com.example.sensoreventlistenertest;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.util.Log;
public class ShakeListener implements SensorEventListener {
// 速度閾值,當搖晃速度達到這值后產生作用
private static final int SPEED_SHRESHOLD = 1000;
// 兩次檢測的時間間隔
private static final int UPTATE_INTERVAL_TIME = 50;
// 傳感器管理器
private SensorManager sensorManager;
// 傳感器
private Sensor sensor;
// 重力感應監聽器
private onShakeListener onShakeListener;
// 上下文
private Context mContext;
// 手機上一個位置時重力感應坐標
private float lastX;
private float lastY;
private float lastZ;
// 上次檢測時間
private long lastUpdateTime;
}
原文摘錄如下:
Conceptually, an acceleration sensor determines the acceleration that is applied to a device (Ad) by measuring the forces that are applied to the sensor itself (Fs) using the following relationship:
Ad = - ∑Fs / mass
However, the force of gravity is always influencing the measured acceleration according to the following relationship:
Ad = -g - ∑F / mass
For this reason, when the device is sitting on a table (and not accelerating), the accelerometer reads a magnitude of g = 9.81 m/s2. Similarly, when the device is in free fall and therefore rapidly accelerating toward the ground at 9.81 m/s2, its accelerometer reads a magnitude of g = 0 m/s2. Therefore, to measure the real acceleration of the device, the contribution of the force of gravity must be removed from the accelerometer data. This can be achieved by applying a high-pass filter. Conversely, a low-pass filter can be used to isolate the force of gravity. The following example shows how you can do this:
public void onSensorChanged(SensorEvent event){
// In this example, alpha is calculated as t / (t + dT),
// where t is the low-pass filter's time-constant and
// dT is the event delivery rate.
final float alpha = 0.8;
// Isolate the force of gravity with the low-pass filter.
gravity[0] = alpha * gravity[0] + (1 - alpha) * event.values[0];
gravity[1] = alpha * gravity[1] + (1 - alpha) * event.values[1];
gravity[2] = alpha * gravity[2] + (1 - alpha) * event.values[2];
// Remove the gravity contribution with the high-pass filter.
linear_acceleration[0] = event.values[0] - gravity[0];
linear_acceleration[1] = event.values[1] - gravity[1];
linear_acceleration[2] = event.values[2] - gravity[2];
}
首先說下哈,我物理真心不太行,高中都是很低分的,以下我說下對這段代碼的理解:
1,因為傳感器返回的三個值都受到重力加速度的影響,所以代碼主要是使用低通濾波器(low-pass filter),從傳感器返回的值中,求出重力加速度。
2,實用高通濾波器( high-pass filter)從傳感器返回值中,去除掉重力加速度的影響,求出實際的線性加速度。
我的問題如下:
1,為什么重力加速度會對前后(y軸),左右(x軸)有影響呢?重力垂直與平面xy,理應不對xy產生影響啊!
2, alpha =t / (t + dT),t是低通濾波器的時間常數,dT是時間傳遞頻率(不知道我有沒有理解錯?),請問這是從何處而來?
3,實現低通濾波的代碼,應該怎么去理解?
PS:我有一定的數模電基礎,雖然很爛,如果這里有關于這方面的知識,望請高手指教。感激不盡!
Android系統帶的傳感器有很多種,最常見的莫過于微信的搖一搖了,那么今天我們就來看看Anroid中傳感器的使用,做一個類似于微信搖一搖的效果。
OK ,廢話不多說,我們就先來看看效果圖吧:
當我搖動手機的時候這里的動畫效果基本和微信上的動畫效果一致,這里請大家自行腦補微信搖一搖畫面。
那我們就動手吧。
1.布局文件
好,那我們先來看看布局文件吧,在布局文件的正中央是一個花的圖片,上圖大家看到的手機圖片實際上是兩張圖片拼接在一起,將花的那張圖片遮住了,當搖一搖的時候,這兩張圖片分別向上或者向下移動,然后花的圖片就可以顯示出來。OK,基本原理就是這樣,我們來看看代碼:
[java]
view plain
copy print?
2.傳感器監聽手機晃動
既然要監聽手機加速度的變化,那我首先需要獲取系統的傳感器:
[java]
view plain
copy print?
//獲取到一個傳感器管理器sensorManager?=?(SensorManager)?getSystemService(SENSOR_SERVICE);//獲得一個加速度傳感器Sensor?sensor?=?sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
這兩行代碼首先是獲取一個傳感器管理器,然后獲取加速度傳感器,因為關于傳感器的API 有很多,這里你需要指明自己要獲取的是哪一個傳感器。拿到傳感器之后,需要注冊監聽,如下:
[java]
view plain
copy print?
sensorManager.registerListener(listener,?sensor,?SensorManager.SENSOR_DELAY_GAME);
注冊傳感器的監聽一共需要三個參數,第一個是監聽器,第二個是加速度傳感器,第三個是傳感器的靈敏度,傳感器的靈敏度一共分為四級,如下,從上往下靈敏度依次降低:
1. SENSOR_DELAY_FASTEST
2. SENSOR_DELAY_GAME
3. SENSOR_DELAY_UI
4. SENSOR_DELAY_NORMAL
OK ,注冊完之后,我們還是來看看這個監聽器是什么吧:
[java]
view plain
copy print?
private?SensorEventListener?listener?=?new?SensorEventListener()?{//當手機的加速度發生變化時調用@Overridepublic?void?onSensorChanged(SensorEvent?event)?{//獲取手機在不同方向上加速度的變化float?valuesX?=?Math.abs(event.values[0]);float?valuesY?=?Math.abs(event.values[1]);float?valuesZ?=?Math.abs(event.values[2]);if?(valuesX?>?17?||?valuesY?>?17?||?valuesZ?>?17)?{startAnimation();playSound();}}@Overridepublic?void?onAccuracyChanged(Sensor?sensor,?int?accuracy)?{}};
這個listener中一共就兩個方法,一個是當手機的加速度發生改變的時候調用,還有一個是當傳感器的靈敏度發生改變的時候調用,當手機的加速度發生改變的時候,我們可以獲取到手機在X 、Y、Z 三個維度上的變化值,拿到這個值之后,我們只需要進行簡單的比較即可,如果有任意一個方向的值大于17,則認為有人在晃動手機,這個時候開啟動畫和聲音的播放。
3.開啟動畫和聲音
動畫實際上就是兩個平移動畫,我們來看看:
[java]
view plain
copy print?
private?void?startAnimation()?{//如果兩次晃動手機的時間小于1秒,則只執行一次動畫long?currentTimeMillis?=?System.currentTimeMillis();if?(currentTimeMillis?-?lastTime??20)?{SoundPool.Builder?builder?=?new?SoundPool.Builder();//1.最大并發流數builder.setMaxStreams(3);AudioAttributes.Builder?aaBuilder?=?new?AudioAttributes.Builder();aaBuilder.setLegacyStreamType(AudioManager.STREAM_MUSIC);builder.setAudioAttributes(aaBuilder.build());soundPool?=?builder.build();}?else?{soundPool?=?new?SoundPool(3,?AudioManager.STREAM_MUSIC,?0);}//加載一個音頻文件sound1?=?soundPool.load(this,?R.raw.awe,?1);}
在創建一個聲音池的時候我采取了兩種不同的方案,如果系統的版本大于20,則是用第一種方式獲取聲音池,否則使用第二種方式獲取聲音池。獲取聲音池之后,再通過聲音池加載一個音頻文件。加載完成之后,我就可以對這個音頻文件進行播放了,如下:
[java]
view plain
copy print?
//1.聲音的id//2.3.表示左右聲道的音量//4.優先級//5.是否循環//6.聲音播放速率soundPool.play(sound1,?1,?1,?0,?0,?1);
每個參數的含義都寫的很清楚了,大家又不清楚的地方可以直接看源碼,這里的源碼注釋很好懂。
?
最后一步就是開啟手機震動了,開啟手機震動,我需要首先獲取震動服務,如下:
[java]
view plain
copy print?
//獲取手機震動服務?vibrator?=?(Vibrator)?getSystemService(VIBRATOR_SERVICE);
然后調用Vibrator類中的vibrator方法執行震動,如下:
[java]
view plain
copy print?
//1.表示震動的節奏off/on/off/on/off/on......//2.表示是否重復震動,-1表示不重復vibrator.vibrate(new?long[]{100,?200,?100,?200,?100,?200},?-1);
手機震動一定要記得添加震動權限哦,如下:
[java]
view plain
copy print?
OK ,最后,在銷毀Activity的時候要解除對傳感器的監聽,同時釋放聲音池資源,如下:
[java]
view plain
copy print?
@Overrideprotected?void?onDestroy()?{super.onDestroy();//解除對加速度傳感器的監聽sensorManager.unregisterListener(listener);if?(soundPool?!=?null)?{//聲音池釋放資源soundPool.release();}}
完整的Activity 代碼如下:
[java]
view plain
copy print?
public?class?MainActivity?extends?AppCompatActivity?{private?ImageView?up;private?ImageView?down;//上一次晃動手機的時間private?long?lastTime;private?SoundPool?soundPool;private?int?sound1;private?Vibrator?vibrator;private?SensorEventListener?listener?=?new?SensorEventListener()?{//當手機的加速度發生變化時調用@Overridepublic?void?onSensorChanged(SensorEvent?event)?{//獲取手機在不同方向上加速度的變化float?valuesX?=?Math.abs(event.values[0]);float?valuesY?=?Math.abs(event.values[1]);float?valuesZ?=?Math.abs(event.values[2]);if?(valuesX?>?17?||?valuesY?>?17?||?valuesZ?>?17)?{startAnimation();playSound();}}@Overridepublic?void?onAccuracyChanged(Sensor?sensor,?int?accuracy)?{}};private?SensorManager?sensorManager;private?void?playSound()?{//1.聲音的id//2.3.表示左右聲道的音量//4.優先級//5.是否循環//6.聲音播放速率soundPool.play(sound1,?1,?1,?0,?0,?1);//手機震動//1.表示震動的節奏off/on/off/on/off/on......//2.表示是否重復震動,-1表示不重復vibrator.vibrate(new?long[]{100,?200,?100,?200,?100,?200},?-1);}private?void?startAnimation()?{//如果兩次晃動手機的時間小于1秒,則只執行一次動畫long?currentTimeMillis?=?System.currentTimeMillis();if?(currentTimeMillis?-?lastTime??20)?{SoundPool.Builder?builder?=?new?SoundPool.Builder();//1.最大并發流數builder.setMaxStreams(3);AudioAttributes.Builder?aaBuilder?=?new?AudioAttributes.Builder();aaBuilder.setLegacyStreamType(AudioManager.STREAM_MUSIC);builder.setAudioAttributes(aaBuilder.build());soundPool?=?builder.build();}?else?{soundPool?=?new?SoundPool(3,?AudioManager.STREAM_MUSIC,?0);}//加載一個音頻文件sound1?=?soundPool.load(this,?R.raw.awe,?1);}private?void?initSensor()?{//獲取到一個傳感器管理器sensorManager?=?(SensorManager)?getSystemService(SENSOR_SERVICE);//獲得一個加速度傳感器Sensor?sensor?=?sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);//注冊傳感器監聽,//1.監聽器//2.加速度傳感器//3.傳感器靈敏度//傳感器靈敏度分為四級,從上往下靈敏度依次降低//SENSOR_DELAY_FASTEST//SENSOR_DELAY_GAME//SENSOR_DELAY_UI//SENSOR_DELAY_NORMALsensorManager.registerListener(listener,?sensor,?SensorManager.SENSOR_DELAY_GAME);}@Overrideprotected?void?onDestroy()?{super.onDestroy();//解除對加速度傳感器的監聽sensorManager.unregisterListener(listener);if?(soundPool?!=?null)?{//聲音池釋放資源soundPool.release();}}}
以上。
?
下一篇: PLC、DCS、FCS三大控
上一篇: 電氣控制線路圖控制原