ภาพรวมการวางแนวโทรศัพท์ Android รวมถึงเข็มทิศ


107

ฉันพยายามเอาหัวจับเซ็นเซอร์การวางแนว Android มาระยะหนึ่งแล้ว ฉันคิดว่าฉันเข้าใจแล้ว จากนั้นฉันก็รู้ว่าฉันไม่ได้ทำ ตอนนี้ฉันคิดว่า (หวังว่า) ฉันจะมีความรู้สึกที่ดีขึ้นอีกครั้ง แต่ฉันก็ยังไม่ 100% ฉันจะพยายามอธิบายความเข้าใจที่ขาด ๆ หาย ๆ ของฉันและหวังว่าผู้คนจะสามารถแก้ไขฉันได้หากฉันทำผิดในบางส่วนหรือเติมช่องว่างใด ๆ

ฉันจินตนาการว่าฉันยืนอยู่ที่ 0 องศาลองจิจูด (เส้นเมริเดียนที่สำคัญ) และละติจูด 0 องศา (เส้นศูนย์สูตร) สถานที่นี้อยู่ในทะเลนอกชายฝั่งแอฟริกา แต่อดทนกับฉัน ฉันถือโทรศัพท์ไว้ข้างหน้าเพื่อให้ด้านล่างของโทรศัพท์ชี้ไปที่เท้าของฉัน ฉันหันหน้าไปทางทิศเหนือ (มองไปทางกรีนิช) ดังนั้นด้านขวามือของโทรศัพท์จึงชี้ไปทางตะวันออกไปทางแอฟริกา ในแนวนี้ (อ้างอิงจากแผนภาพด้านล่าง) ฉันมีแกน X ชี้ไปทางตะวันออกแกน Z ชี้ไปทางทิศใต้และแกน Y ชี้ไปที่ท้องฟ้า

ตอนนี้เซ็นเซอร์บนโทรศัพท์ช่วยให้คุณสามารถกำหนดทิศทาง (ไม่ใช่ตำแหน่ง) ของอุปกรณ์ในสถานการณ์นี้ ส่วนนี้ทำให้ฉันสับสนมาตลอดอาจเป็นเพราะฉันต้องการเข้าใจว่าบางอย่างทำงานอย่างไรก่อนที่ฉันจะยอมรับว่ามันได้ผล ดูเหมือนว่าโทรศัพท์จะวางแนวโดยใช้เทคนิคสองอย่างร่วมกัน

ก่อนที่ฉันจะไปถึงจุดนั้นลองนึกภาพว่ากำลังกลับมายืนบนผืนดินในจินตนาการที่ละติจูด 0 องศาและลองจิจูดในทิศทางที่กล่าวมาข้างต้น ลองนึกภาพว่าคุณถูกปิดตาและรองเท้าของคุณติดอยู่กับวงเวียนสนามเด็กเล่น หากมีคนผลักคุณไปด้านหลังคุณจะตกลงไปข้างหน้า (ไปทางทิศเหนือ) และยื่นมือทั้งสองข้างออกเพื่อหักการล้มของคุณ ในทำนองเดียวกันถ้ามีใครผลักคุณไหล่ซ้ายคุณจะล้มทับด้วยมือขวา หูชั้นในของคุณมี "เซ็นเซอร์ความโน้มถ่วง" (คลิป youtube)ซึ่งช่วยให้คุณตรวจจับได้ว่าคุณล้มไปข้างหน้า / ข้างหลังหรือล้มซ้าย / ขวาหรือล้มลง (หรือขึ้น !!) ดังนั้นมนุษย์จึงสามารถตรวจจับการจัดตำแหน่งและการหมุนรอบแกน X และ Z เดียวกันกับโทรศัพท์ได้

ลองนึกภาพตอนนี้มีคนหมุนคุณ 90 องศาบนวงเวียนเพื่อให้คุณหันหน้าไปทางทิศตะวันออก คุณกำลังหมุนรอบแกน Y แกนนี้แตกต่างกันเนื่องจากเราไม่สามารถตรวจจับได้ทางชีวภาพ เรารู้ว่าเราทำมุมด้วยจำนวนหนึ่ง แต่เราไม่รู้ทิศทางที่สัมพันธ์กับขั้วเหนือแม่เหล็กของดาวเคราะห์ แต่เราต้องใช้เครื่องมือภายนอก ... เข็มทิศแม่เหล็ก สิ่งนี้ช่วยให้เราตรวจสอบได้ว่าเรากำลังหันหน้าไปทางใด เช่นเดียวกับโทรศัพท์ของเรา

ตอนนี้โทรศัพท์ยังมีมาตรความเร่ง 3 แกน ฉันไม่มีความคิดว่ามันใช้งานได้จริง แต่วิธีที่ฉันนึกภาพคือการจินตนาการว่าแรงโน้มถ่วงเป็น 'ฝน' ที่ตกลงมาจากท้องฟ้าคงที่และสม่ำเสมอและจินตนาการถึงแกนในรูปด้านบนเป็นท่อซึ่งสามารถตรวจจับปริมาณฝนที่ไหลผ่านได้ เมื่อวางโทรศัพท์ในแนวตั้งฝนจะไหลผ่านท่อ Y หากโทรศัพท์ค่อยๆหมุนเพื่อให้หน้าจอหันไปทางท้องฟ้าปริมาณฝนที่ไหลผ่าน Y จะลดลงเป็นศูนย์ในขณะที่ระดับเสียงผ่าน Z จะเพิ่มขึ้นเรื่อย ๆ จนกว่าปริมาณฝนสูงสุดจะไหลผ่าน ในทำนองเดียวกันถ้าตอนนี้เราวางโทรศัพท์ไว้ที่ด้านข้างท่อ X จะเก็บฝนได้มากที่สุด ดังนั้นขึ้นอยู่กับการวางแนวของโทรศัพท์โดยการวัดปริมาณน้ำฝนที่ไหลผ่านท่อ 3 ท่อคุณสามารถคำนวณการวางแนวได้

โทรศัพท์ยังมีเข็มทิศอิเล็กทรอนิกส์ซึ่งทำหน้าที่เหมือนเข็มทิศปกติโดย "เข็มเสมือน" จะชี้ไปที่ทิศเหนือแม่เหล็ก ผสาน Android ข้อมูลจากทั้งสองเซ็นเซอร์เพื่อที่เมื่อใดก็ตามที่SensorEventการTYPE_ORIENTATIONจะสร้างvalues[3]อาร์เรย์มี
ค่า [0]: Azimuth - (เข็มทิศแบริ่งทางตะวันออกเฉียงเหนือของแม่เหล็ก)
ค่า [1]: ทางลาด, การหมุนรอบแกน x (เป็นโทรศัพท์ เอนไปข้างหน้าหรือข้างหลัง)
ค่า [2]: หมุน, หมุนรอบแกน y (โทรศัพท์เอนไปทางซ้ายหรือขวา)

ดังนั้นฉันจึงคิดว่า (เช่นฉันไม่รู้) เหตุผลที่ Android ให้แอซิมัท (แบริ่งเข็มทิศ) มากกว่าการอ่านมาตรความเร่งตัวที่สามคือแบริ่งของเข็มทิศมีประโยชน์มากกว่า ผมไม่แน่ใจว่าทำไมพวกเขาเลิกใช้ชนิดของเซ็นเซอร์นี้เป็นตอนนี้ดูเหมือนว่าคุณจำเป็นต้องลงทะเบียนผู้ฟังที่มีระบบสำหรับของประเภทSensorEvent อาร์เรย์TYPE_MAGNETIC_FIELDของเหตุการณ์จะvalue[]ต้องSensorManger.getRotationMatrix(..)ถูกส่งผ่านไปยังSensorManager.getOrientation(..)วิธีการเพื่อให้ได้เมทริกซ์การหมุน (ดูด้านล่าง) ซึ่งจะถูกส่งผ่านไปยังเมธอด มีใครรู้บ้างว่าทำไมทีม Android ถึงเลิกใช้งานSensor.TYPE_ORIENTATION? มันเป็นสิ่งที่มีประสิทธิภาพหรือไม่? นั่นคือสิ่งที่บอกเป็นนัยในความคิดเห็นหนึ่งของคำถามที่คล้ายกันแต่คุณยังต้องลงทะเบียนผู้ฟังประเภทอื่นในการพัฒนา / ตัวอย่าง / เข็มทิศ / src / com / ตัวอย่าง / android / เข็มทิศ / CompassActivity.javaตัวอย่าง

ตอนนี้ฉันต้องการพูดคุยเกี่ยวกับเมทริกซ์การหมุน (นี่คือจุดที่ฉันไม่แน่ใจที่สุด) ดังนั้นข้างบนเรามีตัวเลขสามตัวจากเอกสาร Android เราจะเรียกมันว่า A, B และ C

A = SensorManger.getRotationMatrix (.. ) รูปเมธอดและแสดงถึงระบบพิกัดของโลก

B = ระบบพิกัดที่ใช้โดย SensorEvent API

C = SensorManager.getOrientation (.. ) รูปวิธีการ

ดังนั้นความเข้าใจของฉันก็คือ A หมายถึง "ระบบพิกัดของโลก" ซึ่งฉันคิดว่าหมายถึงวิธีที่ตำแหน่งบนโลกถูกกำหนดให้เป็นคู่ (ละติจูดลองจิจูด) โดยมีตัวเลือก (ระดับความสูง) X คือ"อีส"ประสาน, Y เป็น"Northing"ประสาน Z ชี้ไปที่ท้องฟ้าและแสดงถึงระดับความสูง

ระบบประสานงานโทรศัพท์แสดงในรูป B ได้รับการแก้ไข แกน Y ชี้ไปที่ด้านบนเสมอ เมทริกซ์การหมุนกำลังคำนวณอย่างต่อเนื่องโดยโทรศัพท์และอนุญาตให้มีการทำแผนที่ระหว่างทั้งสอง ฉันคิดถูกหรือเปล่าว่าเมทริกซ์การหมุนเปลี่ยนระบบพิกัดของ B เป็น C ดังนั้นเมื่อคุณเรียกSensorManager.getOrientation(..)เมธอดคุณจะใช้values[]อาร์เรย์ที่มีค่าตรงกับรูป C เมื่อโทรศัพท์ชี้ไปที่ท้องฟ้าเมทริกซ์การหมุนคือเมทริกซ์เอกลักษณ์ (เมทริกซ์เทียบเท่าทางคณิตศาสตร์ของ 1) ซึ่งหมายความว่าไม่จำเป็นต้องมีการแมปเนื่องจากอุปกรณ์ถูกจัดตำแหน่ง กับระบบพิกัดของโลก

ตกลง. ฉันคิดว่าฉันหยุดตอนนี้ดีกว่า อย่างที่ฉันเคยพูดไปก่อนหน้านี้ฉันหวังว่าผู้คนจะบอกฉันว่าฉันทำอะไรผิดพลาดหรือช่วยเหลือผู้คน (หรือทำให้คนสับสนยิ่งกว่านั้น!)


25
ฉันชอบคำถามนี้มาก ฉันตอบไม่ได้ แต่ชอบ
Octavian A. Damiean

4
ทิมคุณเคยได้รับคำตอบหรือไม่? ฉันเกาหัวอยู่เหมือนกัน นี่เป็นหนึ่งใน API ที่มีเอกสารไม่ดีที่สุดเท่าที่ฉันเคยเห็นมา
Pierre-Luc Paour

ไม่จริงฉันกลัว ฉันต้องก้าวต่อไป สักวันฉันจะกลับมาที่ปัญหานี้
ทิม

1
ที่นี่ฉันมีคำถามเดียวกันเกือบ? และการตอบสนองการแก้ปัญหาด้วย ทำให้ประชาชนรหัสของฉันที่ Github

สิ่งเดียวกับที่ฉันสงสัยคือฉันใช้เข็มทิศบนอุปกรณ์ Android และทำงานได้อย่างถูกต้องหากฉันได้รับความช่วยเหลือจากอินเทอร์เน็ตมันใช้งานได้ดี แต่สิ่งที่ทำให้สับสนคือ ... สมมติว่าอุปกรณ์ของฉันวางอยู่บนพื้น มาทางฉันและมันชี้ไปทางทิศเหนือตอนนี้ฉันหยิบมือถือขึ้นมาแล้ววางไว้เหนือหัวในแนวตั้งโดยที่หน้ายังหันมาทางฉัน ประการแรกเข็มควรเปลี่ยนทิศทางและทำไม ตามที่ฉันคิดว่ามันไม่ควรเพราะฉันไม่ได้เปลี่ยนทิศทางของฉัน แต่มันกำลังเปลี่ยนไปในแอพของฉันและแอพอื่น ๆ ทั้งหมดที่ฉันดาวน์โหลด ใครช่วยอธิบายว่าทำไม?
Syed Raza Mehdi

คำตอบ:


26

คุณอาจต้องการตรวจสอบOne Screen Turn สมควรได้รับบทความอื่น อธิบายว่าเหตุใดคุณจึงต้องการเมทริกซ์การหมุน

โดยสรุปเซ็นเซอร์ของโทรศัพท์จะใช้ระบบพิกัดเดียวกันเสมอแม้ว่าจะหมุนอุปกรณ์ก็ตาม

ในแอพพลิเคชั่นที่ไม่ได้ล็อคให้อยู่ในแนวเดียวระบบพิกัดหน้าจอจะเปลี่ยนไปเมื่อคุณหมุนอุปกรณ์ ดังนั้นเมื่ออุปกรณ์ถูกหมุนจากโหมดมุมมองเริ่มต้นระบบพิกัดเซ็นเซอร์จะไม่เหมือนกับระบบพิกัดหน้าจออีกต่อไป เมทริกซ์การหมุนในกรณีนี้ใช้เพื่อแปลง A เป็น C (B จะคงที่เสมอ)

นี่คือข้อมูลโค้ดเพื่อแสดงวิธีการใช้งาน

SensorManager sm = (SensorManager) getSystemService(SENSOR_SERVICE);

// Register this class as a listener for the accelerometer sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_ACCELEROMETER),
                    SensorManager.SENSOR_DELAY_NORMAL);
// ...and the orientation sensor
sm.registerListener(this, sm.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD),
                    SensorManager.SENSOR_DELAY_NORMAL);

//...
// The following code inside a class implementing a SensorEventListener
// ...

float[] inR = new float[16];
float[] I = new float[16];
float[] gravity = new float[3];
float[] geomag = new float[3];
float[] orientVals = new float[3];

double azimuth = 0;
double pitch = 0;
double roll = 0;

public void onSensorChanged(SensorEvent sensorEvent) {
    // If the sensor data is unreliable return
    if (sensorEvent.accuracy == SensorManager.SENSOR_STATUS_UNRELIABLE)
        return;

    // Gets the value of the sensor that has been changed
    switch (sensorEvent.sensor.getType()) {  
        case Sensor.TYPE_ACCELEROMETER:
            gravity = sensorEvent.values.clone();
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            geomag = sensorEvent.values.clone();
            break;
    }

    // If gravity and geomag have values then find rotation matrix
    if (gravity != null && geomag != null) {

        // checks that the rotation matrix is found
        boolean success = SensorManager.getRotationMatrix(inR, I,
                                                          gravity, geomag);
        if (success) {
            SensorManager.getOrientation(inR, orientVals);
            azimuth = Math.toDegrees(orientVals[0]);
            pitch = Math.toDegrees(orientVals[1]);
            roll = Math.toDegrees(orientVals[2]);
        }
    }
}

4
เพียงแค่พูดถึงว่า azimuth, pitch และ roll ไม่เหมือนกับที่ออกมาจาก OrientationSensor ที่เลิกใช้แล้ว orientation[0] = orientation[0] >= 0 ? orientation[0]: orientation[0] + 360;จะทำให้ราบเรียบเป็นปกติและif (orientation[1] <= -90) { orientation[1] += (-2*(90+orientation[1])); } else if(orientation[1] >= 90){ orientation[1] += (2*(90 - orientation[1])); }จะทำให้สนามเป็นปกติ
ราฟาเอล T

@RafaelT และเพื่อทำให้ม้วนเป็นปกติ? หรือว่าไม่สมเหตุสมผล?
Matthias

@RafaelT: การทำให้ azimuth เป็นมาตรฐานของคุณดูเหมือนว่าจะมีผล: ค่าต่างๆเริ่มจาก [-180,180] ถึง [0, 360] แต่ค่าระดับเสียงที่ฉันได้รับนั้นอยู่ที่ [-90,90] แล้วดังนั้นการปรับมาตรฐานที่คุณเสนอจึงไม่มีผล
Matthias

หมายความว่าอย่างไรถ้าหลังจากตรวจสอบ (แรงโน้มถ่วง! = null && geomag! = null) ค่าของ geomag จะเป็น 0 เสมอไม่ว่าฉันจะย้ายแท็บเล็ตอย่างไร อาจเป็นแท็บเล็ตที่ไม่มีเซ็นเซอร์ geomag?
ขั้นสูง

3

ม้วนเป็นฟังก์ชันของแรงโน้มถ่วงม้วน 90 องศาใส่แรงโน้มถ่วงทั้งหมดลงในทะเบียน x

ระยะพิทช์ก็เช่นเดียวกันระยะพิทช์ 90 องศาทำให้ส่วนประกอบของแรงโน้มถ่วงทั้งหมดลงในทะเบียน y

Yaw / Heading / azimuth ไม่มีผลต่อแรงโน้มถ่วงโดยจะต้องทำมุมฉากกับแรงโน้มถ่วงเสมอดังนั้นไม่ว่าคุณจะเผชิญกับแรงโน้มถ่วงไปทางใดก็จะไม่สามารถระบุได้

นี่คือเหตุผลที่คุณต้องมีเข็มทิศเพื่อประเมินนั่นอาจจะสมเหตุสมผลหรือไม่?



0

ฉันประสบปัญหานี้ดังนั้นฉันจึงทำแผนที่สิ่งที่เกิดขึ้นในทิศทางต่างๆ หากติดตั้งอุปกรณ์ในแนวนอนเช่นในรถที่ยึด 'องศา' จากเข็มทิศดูเหมือนว่าจะวิ่งจาก 0-275 (ตามเข็มนาฬิกา) เหนือ 269 (ระหว่างทิศตะวันตกและทิศเหนือ) จะนับถอยหลังจาก -90 ถึง 0 แล้ว ส่งต่อจาก 0 ถึง 269 270 กลายเป็น -90

ยังอยู่ในแนวนอน แต่เมื่ออุปกรณ์นอนหงายเซ็นเซอร์ของฉันจะให้ 0-360 และในโหมดแนวตั้งจะวิ่ง 0-360 ทั้งนอนหงายและยืนในแนวตั้ง

หวังว่าจะช่วยใครบางคน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.