অ্যান্ড্রয়েড প্ল্যাটফর্মে এমন অনেক সেন্সর রয়েছে, যা দিয়ে কোনো ডিভাইসের গতিবিধি পর্যবেক্ষণ করা যায়।
সেন্সরের প্রকারভেদে এর সম্ভাব্য গঠনশৈলী ভিন্ন হয়:
- অভিকর্ষ, রৈখিক ত্বরণ, ঘূর্ণন ভেক্টর, উল্লেখযোগ্য গতি, পদক্ষেপ গণনাকারী এবং পদক্ষেপ শনাক্তকারী সেন্সরগুলো হয় হার্ডওয়্যার-ভিত্তিক অথবা সফটওয়্যার-ভিত্তিক।
- অ্যাক্সেলেরোমিটার এবং জাইরোস্কোপ সেন্সরগুলো সর্বদা হার্ডওয়্যার-ভিত্তিক হয়।
বেশিরভাগ অ্যান্ড্রয়েড-চালিত ডিভাইসে অ্যাক্সেলেরোমিটার থাকে এবং এখন অনেক ডিভাইসে জাইরোস্কোপও অন্তর্ভুক্ত থাকে। সফটওয়্যার-ভিত্তিক সেন্সরগুলোর প্রাপ্যতা তুলনামূলকভাবে কম, কারণ ডেটা সংগ্রহের জন্য এগুলো প্রায়শই এক বা একাধিক হার্ডওয়্যার সেন্সরের উপর নির্ভর করে। ডিভাইসের উপর নির্ভর করে, এই সফটওয়্যার-ভিত্তিক সেন্সরগুলো অ্যাক্সেলেরোমিটার ও ম্যাগনেটোমিটার অথবা জাইরোস্কোপ থেকে তাদের ডেটা সংগ্রহ করতে পারে।
মোশন সেন্সর ডিভাইসের নড়াচড়া, যেমন—হেলান দেওয়া, ঝাঁকুনি, ঘূর্ণন বা দোল পর্যবেক্ষণ করার জন্য উপযোগী। এই নড়াচড়া সাধারণত ব্যবহারকারীর সরাসরি ইনপুটের প্রতিফলন (উদাহরণস্বরূপ, কোনো গেমে ব্যবহারকারীর গাড়ি চালানো বা বল নিয়ন্ত্রণ করা), তবে এটি ডিভাইসটি যে ভৌত পরিবেশে রয়েছে তারও প্রতিফলন হতে পারে (উদাহরণস্বরূপ, আপনি যখন গাড়ি চালান তখন আপনার সাথে সাথে নড়াচড়া করা)। প্রথম ক্ষেত্রে, আপনি ডিভাইসের নিজস্ব প্রসঙ্গ কাঠামো বা আপনার অ্যাপ্লিকেশনের প্রসঙ্গ কাঠামোর সাপেক্ষে গতি পর্যবেক্ষণ করছেন; দ্বিতীয় ক্ষেত্রে, আপনি পৃথিবীর প্রসঙ্গ কাঠামোর সাপেক্ষে গতি পর্যবেক্ষণ করছেন। মোশন সেন্সর সাধারণত ডিভাইসের অবস্থান পর্যবেক্ষণের জন্য ব্যবহৃত হয় না, তবে পৃথিবীর প্রসঙ্গ কাঠামোর সাপেক্ষে কোনো ডিভাইসের অবস্থান নির্ণয় করতে এগুলোকে অন্যান্য সেন্সরের (যেমন—ভূ-চৌম্বকীয় ক্ষেত্র সেন্সর) সাথে ব্যবহার করা যেতে পারে (আরও তথ্যের জন্য ‘পজিশন সেন্সর ’ দেখুন)।
সমস্ত মোশন সেন্সর প্রতিটি SensorEvent জন্য সেন্সর মানের বহুমাত্রিক অ্যারে ফেরত দেয়। উদাহরণস্বরূপ, একটি একক সেন্সর ইভেন্টের সময় অ্যাক্সেলেরোমিটার তিনটি স্থানাঙ্ক অক্ষের জন্য ত্বরণ বলের ডেটা ফেরত দেয় এবং জাইরোস্কোপ তিনটি স্থানাঙ্ক অক্ষের জন্য ঘূর্ণন হারের ডেটা ফেরত দেয়। এই ডেটা মানগুলি অন্যান্য SensorEvent প্যারামিটারগুলির সাথে একটি float অ্যারে ( values ) হিসাবে ফেরত দেওয়া হয়। সারণি ১-এ অ্যান্ড্রয়েড প্ল্যাটফর্মে উপলব্ধ মোশন সেন্সরগুলির একটি সংক্ষিপ্ত বিবরণ দেওয়া হয়েছে।
সারণি ১. অ্যান্ড্রয়েড প্ল্যাটফর্মে সমর্থিত মোশন সেন্সরসমূহ।
| সেন্সর | সেন্সর ইভেন্ট ডেটা | বর্ণনা | পরিমাপের একক |
|---|---|---|---|
TYPE_ACCELEROMETER | SensorEvent.values[0] | এক্স-অক্ষ বরাবর ত্বরণ বল (মহাকর্ষ সহ)। | মি/সে ২ |
SensorEvent.values[1] | y অক্ষ বরাবর ত্বরণ বল (মহাকর্ষ সহ)। | ||
SensorEvent.values[2] | z অক্ষ বরাবর ত্বরণ বল (মহাকর্ষ সহ)। | ||
TYPE_ACCELEROMETER_UNCALIBRATED | SensorEvent.values[0] | কোনো বায়াস ক্ষতিপূরণ ছাড়াই X অক্ষ বরাবর ত্বরণ পরিমাপ করা হয়েছে। | মি/সে ২ |
SensorEvent.values[1] | কোনো বায়াস ক্ষতিপূরণ ছাড়াই Y অক্ষ বরাবর পরিমাপকৃত ত্বরণ। | ||
SensorEvent.values[2] | কোনো বায়াস ক্ষতিপূরণ ছাড়াই Z অক্ষ বরাবর পরিমাপকৃত ত্বরণ। | ||
SensorEvent.values[3] | আনুমানিক বায়াস ক্ষতিপূরণ সহ X অক্ষ বরাবর পরিমাপকৃত ত্বরণ। | ||
SensorEvent.values[4] | আনুমানিক বায়াস ক্ষতিপূরণ সহ Y অক্ষ বরাবর পরিমাপকৃত ত্বরণ। | ||
SensorEvent.values[5] | আনুমানিক বায়াস ক্ষতিপূরণ সহ Z অক্ষ বরাবর পরিমাপকৃত ত্বরণ। | ||
TYPE_GRAVITY | SensorEvent.values[0] | x অক্ষ বরাবর মহাকর্ষ বল। | মি/সে ২ |
SensorEvent.values[1] | y অক্ষ বরাবর মহাকর্ষ বল। | ||
SensorEvent.values[2] | z অক্ষ বরাবর মহাকর্ষ বল। | ||
TYPE_GYROSCOPE | SensorEvent.values[0] | x অক্ষের সাপেক্ষে ঘূর্ণনের হার। | রেডিয়ান/সেকেন্ড |
SensorEvent.values[1] | y অক্ষের সাপেক্ষে ঘূর্ণনের হার। | ||
SensorEvent.values[2] | z অক্ষের সাপেক্ষে ঘূর্ণনের হার। | ||
TYPE_GYROSCOPE_UNCALIBRATED | SensorEvent.values[0] | এক্স-অক্ষ বরাবর ঘূর্ণনের হার (ড্রিফট ক্ষতিপূরণ ছাড়া)। | রেডিয়ান/সেকেন্ড |
SensorEvent.values[1] | y অক্ষের সাপেক্ষে ঘূর্ণনের হার (ড্রিফট ক্ষতিপূরণ ছাড়া)। | ||
SensorEvent.values[2] | z অক্ষের সাপেক্ষে ঘূর্ণনের হার (ড্রিফট ক্ষতিপূরণ ছাড়া)। | ||
SensorEvent.values[3] | এক্স-অক্ষ বরাবর আনুমানিক সরণ। | ||
SensorEvent.values[4] | y অক্ষের সাপেক্ষে আনুমানিক সরণ। | ||
SensorEvent.values[5] | z অক্ষের সাপেক্ষে আনুমানিক সরণ। | ||
TYPE_LINEAR_ACCELERATION | SensorEvent.values[0] | x অক্ষ বরাবর ত্বরণ বল (মহাকর্ষ ব্যতীত)। | মি/সে ২ |
SensorEvent.values[1] | y অক্ষ বরাবর ত্বরণ বল (মহাকর্ষ ব্যতীত)। | ||
SensorEvent.values[2] | z অক্ষ বরাবর ত্বরণ বল (মহাকর্ষ ব্যতীত)। | ||
TYPE_ROTATION_VECTOR | SensorEvent.values[0] | x অক্ষ বরাবর ঘূর্ণন ভেক্টর উপাংশ (x * sin(θ/2))। | এককবিহীন |
SensorEvent.values[1] | y অক্ষ বরাবর ঘূর্ণন ভেক্টর উপাংশ (y * sin(θ/2))। | ||
SensorEvent.values[2] | z অক্ষ বরাবর ঘূর্ণন ভেক্টর উপাংশ (z * sin(θ/2))। | ||
SensorEvent.values[3] | ঘূর্ণন ভেক্টরের স্কেলার উপাদান ((cos(θ/2)). 1 | ||
TYPE_SIGNIFICANT_MOTION | প্রযোজ্য নয় | প্রযোজ্য নয় | প্রযোজ্য নয় |
TYPE_STEP_COUNTER | SensorEvent.values[0] | শেষ রিবুটের পর থেকে সেন্সরটি সক্রিয় থাকা অবস্থায় ব্যবহারকারীর নেওয়া পদক্ষেপের সংখ্যা। | পদক্ষেপ |
TYPE_STEP_DETECTOR | প্রযোজ্য নয় | প্রযোজ্য নয় | প্রযোজ্য নয় |
১ স্কেলার উপাদানটি একটি ঐচ্ছিক মান।
গতি শনাক্তকরণ এবং পর্যবেক্ষণের জন্য রোটেশন ভেক্টর সেন্সর এবং গ্র্যাভিটি সেন্সর হলো সবচেয়ে বেশি ব্যবহৃত সেন্সর। রোটেশন ভেক্টর সেন্সরটি বিশেষভাবে বহুমুখী এবং এটি গতি-সম্পর্কিত বিভিন্ন কাজে ব্যবহার করা যেতে পারে, যেমন অঙ্গভঙ্গি শনাক্ত করা, কৌণিক পরিবর্তন পর্যবেক্ষণ করা এবং আপেক্ষিক দিকবিন্যাস পরিবর্তন পর্যবেক্ষণ করা। উদাহরণস্বরূপ, আপনি যদি কোনো গেম, অগমেন্টেড রিয়েলিটি অ্যাপ্লিকেশন, একটি দ্বি-মাত্রিক বা ত্রি-মাত্রিক কম্পাস, বা একটি ক্যামেরা স্ট্যাবিলাইজেশন অ্যাপ তৈরি করেন, তবে রোটেশন ভেক্টর সেন্সরটি আদর্শ। বেশিরভাগ ক্ষেত্রে, অ্যাক্সেলেরোমিটার ও ভূ-চৌম্বকীয় ক্ষেত্র সেন্সর বা ওরিয়েন্টেশন সেন্সর ব্যবহার করার চেয়ে এই সেন্সরগুলো ব্যবহার করা একটি ভালো বিকল্প।
অ্যান্ড্রয়েড ওপেন সোর্স প্রজেক্ট সেন্সর
অ্যান্ড্রয়েড ওপেন সোর্স প্রজেক্ট (AOSP) তিনটি সফটওয়্যার-ভিত্তিক মোশন সেন্সর সরবরাহ করে: একটি গ্র্যাভিটি সেন্সর, একটি লিনিয়ার অ্যাক্সিলারেশন সেন্সর এবং একটি রোটেশন ভেক্টর সেন্সর। অ্যান্ড্রয়েড ৪.০-তে এই সেন্সরগুলো আপডেট করা হয়েছিল এবং এখন স্থিতিশীলতা ও পারফরম্যান্স উন্নত করার জন্য এগুলো (অন্যান্য সেন্সরের পাশাপাশি) ডিভাইসের জাইরোস্কোপ ব্যবহার করে। আপনি যদি এই সেন্সরগুলো ব্যবহার করে দেখতে চান, তবে getVendor() এবং getVersion() মেথড ব্যবহার করে এগুলোকে শনাক্ত করতে পারেন (ভেন্ডর হলো Google LLC; ভার্সন নম্বর হলো ৩)। ভেন্ডর এবং ভার্সন নম্বর দ্বারা এই সেন্সরগুলোকে শনাক্ত করা প্রয়োজন, কারণ অ্যান্ড্রয়েড সিস্টেম এই তিনটি সেন্সরকে সেকেন্ডারি সেন্সর হিসেবে বিবেচনা করে। উদাহরণস্বরূপ, যদি কোনো ডিভাইস নির্মাতা তাদের নিজস্ব গ্র্যাভিটি সেন্সর সরবরাহ করে, তাহলে AOSP গ্র্যাভিটি সেন্সরটি একটি সেকেন্ডারি গ্র্যাভিটি সেন্সর হিসেবে প্রদর্শিত হয়। এই তিনটি সেন্সরই জাইরোস্কোপের উপর নির্ভরশীল: যদি কোনো ডিভাইসে জাইরোস্কোপ না থাকে, তবে এই সেন্সরগুলো প্রদর্শিত হয় না এবং ব্যবহারের জন্য উপলব্ধ থাকে না।
মাধ্যাকর্ষণ সেন্সর ব্যবহার করুন
গ্র্যাভিটি সেন্সরটি অভিকর্ষের দিক এবং মাত্রা নির্দেশ করে একটি ত্রিমাত্রিক ভেক্টর প্রদান করে। সাধারণত, এই সেন্সরটি মহাকাশে ডিভাইসটির আপেক্ষিক অবস্থান নির্ধারণ করতে ব্যবহৃত হয়। নিম্নলিখিত কোডটি দেখায় কিভাবে ডিফল্ট গ্র্যাভিটি সেন্সরের একটি ইনস্ট্যান্স পাওয়া যায়:
কোটলিন
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY)
জাভা
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GRAVITY);
এককগুলো ত্বরণ সেন্সরে ব্যবহৃত এককের (m/ s² ) সমান, এবং স্থানাঙ্ক ব্যবস্থাটিও ত্বরণ সেন্সরে ব্যবহৃত স্থানাঙ্ক ব্যবস্থার সমান।
দ্রষ্টব্য: যখন কোনো ডিভাইস স্থির থাকে, তখন গ্র্যাভিটি সেন্সরের আউটপুট অ্যাক্সেলেরোমিটারের আউটপুটের সমান হওয়া উচিত।
লিনিয়ার অ্যাক্সেলেরোমিটার ব্যবহার করুন
লিনিয়ার অ্যাক্সিলারেশন সেন্সরটি আপনাকে একটি ত্রিমাত্রিক ভেক্টর প্রদান করে, যা মাধ্যাকর্ষণ ব্যতীত ডিভাইসের প্রতিটি অক্ষ বরাবর ত্বরণকে নির্দেশ করে। আপনি এই মানটি জেসচার ডিটেকশন (gesture detection) করার জন্য ব্যবহার করতে পারেন। এই মানটি একটি ইনার্শিয়াল নেভিগেশন সিস্টেমের ইনপুট হিসেবেও কাজ করতে পারে, যা ডেড রেকনিং (dead reckoning) পদ্ধতি ব্যবহার করে। নিচের কোডটি দেখায় কিভাবে ডিফল্ট লিনিয়ার অ্যাক্সিলারেশন সেন্সরের একটি ইনস্ট্যান্স পাওয়া যায়:
কোটলিন
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION)
জাভা
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_LINEAR_ACCELERATION);
ধারণাগতভাবে, এই সেন্সরটি আপনাকে নিম্নলিখিত সম্পর্ক অনুসারে ত্বরণের ডেটা প্রদান করে:
linear acceleration = acceleration - acceleration due to gravity
সাধারণত মাধ্যাকর্ষণের প্রভাব ছাড়া ত্বরণের ডেটা পেতে এই সেন্সরটি ব্যবহার করা হয়। উদাহরণস্বরূপ, আপনার গাড়িটি কত দ্রুত চলছে তা দেখতে আপনি এই সেন্সরটি ব্যবহার করতে পারেন। লিনিয়ার অ্যাক্সিলারেশন সেন্সরের সর্বদা একটি অফসেট থাকে, যা আপনাকে অপসারণ করতে হবে। এটি করার সবচেয়ে সহজ উপায় হলো আপনার অ্যাপ্লিকেশনে একটি ক্যালিব্রেশন ধাপ যুক্ত করা। ক্যালিব্রেশনের সময় আপনি ব্যবহারকারীকে ডিভাইসটি একটি টেবিলের উপর রাখতে বলতে পারেন এবং তারপর তিনটি অক্ষের অফসেটগুলো পড়তে পারেন। এরপর আপনি অ্যাক্সিলারেশন সেন্সরের সরাসরি রিডিং থেকে সেই অফসেটটি বিয়োগ করে প্রকৃত লিনিয়ার অ্যাক্সিলারেশন পেতে পারেন।
সেন্সরের স্থানাঙ্ক ব্যবস্থাটি ত্বরণ সেন্সরের ব্যবহৃত স্থানাঙ্ক ব্যবস্থার মতোই, এবং পরিমাপের এককও (m/ s² ) একই।
ঘূর্ণন ভেক্টর সেন্সর ব্যবহার করুন
ঘূর্ণন ভেক্টরটি একটি কোণ এবং একটি অক্ষের সমন্বয়ে ডিভাইসটির অভিমুখ প্রকাশ করে, যেখানে ডিভাইসটি একটি অক্ষের (x, y, বা z) চারপাশে θ কোণে ঘুরেছে। নিম্নলিখিত কোডটি আপনাকে দেখাবে কীভাবে ডিফল্ট ঘূর্ণন ভেক্টর সেন্সরের একটি ইনস্ট্যান্স পেতে হয়:
কোটলিন
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR)
জাভা
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ROTATION_VECTOR);
ঘূর্ণন ভেক্টরের তিনটি উপাদান নিম্নরূপে প্রকাশ করা হয়:

যেখানে ঘূর্ণন ভেক্টরের মান sin(θ/2)-এর সমান এবং ঘূর্ণন ভেক্টরের দিক ঘূর্ণন অক্ষের দিকের সমান।

চিত্র ১. ঘূর্ণন ভেক্টর সেন্সর দ্বারা ব্যবহৃত স্থানাঙ্ক ব্যবস্থা।
ঘূর্ণন ভেক্টরের তিনটি উপাদান একটি একক কোয়াটারনিয়নের (cos(θ/2), x*sin(θ/2), y*sin(θ/2), z*sin(θ/2)) শেষ তিনটি উপাংশের সমান। ঘূর্ণন ভেক্টরের উপাদানগুলোর কোনো একক নেই। x, y, এবং z অক্ষগুলোকে ত্বরণ সেন্সরের মতোই সংজ্ঞায়িত করা হয়। রেফারেন্স স্থানাঙ্ক ব্যবস্থাটিকে একটি সরাসরি অর্থোনরমাল ভিত্তি হিসাবে সংজ্ঞায়িত করা হয় (চিত্র ১ দেখুন)। এই স্থানাঙ্ক ব্যবস্থাটির নিম্নলিখিত বৈশিষ্ট্য রয়েছে:
- X-কে Y x Z ভেক্টর গুণফল হিসেবে সংজ্ঞায়িত করা হয়। এটি ডিভাইসটির বর্তমান অবস্থানে ভূমির স্পর্শক এবং আনুমানিক পূর্ব দিকে নির্দেশ করে।
- ডিভাইসটির বর্তমান অবস্থানে Y অক্ষ ভূমির সাথে স্পর্শকীয় এবং এটি ভূ-চৌম্বকীয় উত্তর মেরুর দিকে নির্দেশ করে।
- Z আকাশের দিকে নির্দেশ করে এবং ভূমির সমতলের সাথে লম্ব।
রোটেশন ভেক্টর সেন্সর কীভাবে ব্যবহার করতে হয় তা দেখানোর জন্য একটি নমুনা অ্যাপ্লিকেশন দেখতে RotationVectorDemo.java দেখুন।
গুরুত্বপূর্ণ গতি সেন্সর ব্যবহার করুন
সিগনিফিক্যান্ট মোশন সেন্সরটি প্রতিবার উল্লেখযোগ্য গতি শনাক্ত হলে একটি ইভেন্ট ট্রিগার করে এবং তারপর নিজে থেকেই নিষ্ক্রিয় হয়ে যায়। উল্লেখযোগ্য গতি হলো এমন একটি গতি যা ব্যবহারকারীর অবস্থানের পরিবর্তন ঘটাতে পারে; যেমন হাঁটা, সাইকেল চালানো বা চলন্ত গাড়িতে বসা। নিচের কোডটিতে দেখানো হয়েছে কীভাবে ডিফল্ট সিগনিফিক্যান্ট মোশন সেন্সরের একটি ইনস্ট্যান্স পেতে হয় এবং কীভাবে একটি ইভেন্ট লিসেনার রেজিস্টার করতে হয়:
কোটলিন
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val mSensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION) val triggerEventListener = object : TriggerEventListener() { override fun onTrigger(event: TriggerEvent?) { // Do work } } mSensor?.also { sensor -> sensorManager.requestTriggerSensor(triggerEventListener, sensor) }
জাভা
private SensorManager sensorManager; private Sensor sensor; private TriggerEventListener triggerEventListener; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_SIGNIFICANT_MOTION); triggerEventListener = new TriggerEventListener() { @Override public void onTrigger(TriggerEvent event) { // Do work } }; sensorManager.requestTriggerSensor(triggerEventListener, mSensor);
আরও তথ্যের জন্য, TriggerEventListener দেখুন।
স্টেপ কাউন্টার সেন্সর ব্যবহার করুন
স্টেপ কাউন্টার সেন্সরটি শেষ রিবুটের পর থেকে ব্যবহারকারীর নেওয়া পদক্ষেপের সংখ্যা দেখায়, যখন সেন্সরটি সক্রিয় ছিল। স্টেপ কাউন্টারের ল্যাটেন্সি বেশি (১০ সেকেন্ড পর্যন্ত), কিন্তু স্টেপ ডিটেক্টর সেন্সরের চেয়ে এর নির্ভুলতা বেশি।
দ্রষ্টব্য: Android 10 (API লেভেল 29) বা তার উচ্চতর সংস্করণে চালিত ডিভাইসগুলিতে আপনার অ্যাপ এই সেন্সরটি ব্যবহার করার জন্য আপনাকে অবশ্যই ACTIVITY_RECOGNITION পারমিশনটি ঘোষণা করতে হবে।
নিম্নলিখিত কোডটি দেখায় কিভাবে ডিফল্ট স্টেপ কাউন্টার সেন্সরের একটি ইনস্ট্যান্স পাওয়া যায়:
কোটলিন
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER)
জাভা
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_COUNTER);
আপনার অ্যাপ চালিত ডিভাইসগুলির ব্যাটারি সাশ্রয় করতে, একটি নির্দিষ্ট বিরতিতে স্টেপ কাউন্টার সেন্সর থেকে বর্তমান মান সংগ্রহ করার জন্য আপনার JobScheduler ক্লাস ব্যবহার করা উচিত। যদিও বিভিন্ন ধরণের অ্যাপের জন্য ভিন্ন ভিন্ন সেন্সর-রিডিং বিরতির প্রয়োজন হয়, আপনার অ্যাপের যদি সেন্সর থেকে রিয়েল-টাইম ডেটার প্রয়োজন না হয়, তবে এই বিরতিটি যতটা সম্ভব দীর্ঘ রাখা উচিত।
ধাপ শনাক্তকারী সেন্সর ব্যবহার করুন
ব্যবহারকারী প্রতিবার পা ফেললে স্টেপ ডিটেক্টর সেন্সরটি একটি ইভেন্ট ট্রিগার করে। এর ল্যাটেন্সি ২ সেকেন্ডের কম হবে বলে আশা করা হচ্ছে।
দ্রষ্টব্য: Android 10 (API লেভেল 29) বা তার উচ্চতর সংস্করণে চালিত ডিভাইসগুলিতে আপনার অ্যাপ এই সেন্সরটি ব্যবহার করার জন্য আপনাকে অবশ্যই ACTIVITY_RECOGNITION পারমিশনটি ঘোষণা করতে হবে।
নিম্নলিখিত কোডটি দেখায় কিভাবে ডিফল্ট স্টেপ ডিটেক্টর সেন্সরের একটি ইনস্ট্যান্স পাওয়া যায়:
কোটলিন
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR)
জাভা
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_STEP_DETECTOR);
কাঁচা ডেটা নিয়ে কাজ করুন
নিম্নলিখিত সেন্সরগুলো ডিভাইসের উপর প্রযুক্ত রৈখিক এবং ঘূর্ণন বল সম্পর্কে আপনার অ্যাপকে কাঁচা ডেটা সরবরাহ করে। এই সেন্সরগুলো থেকে প্রাপ্ত মানগুলো কার্যকরভাবে ব্যবহার করার জন্য, আপনাকে পরিবেশগত উপাদান, যেমন মাধ্যাকর্ষণ, ফিল্টার করে বাদ দিতে হবে। নয়েজ কমানোর জন্য মানগুলোর প্রবণতার উপর একটি স্মুদিং অ্যালগরিদম প্রয়োগ করারও প্রয়োজন হতে পারে।
অ্যাক্সেলেরোমিটার ব্যবহার করুন
একটি অ্যাক্সিলারেশন সেন্সর ডিভাইসের উপর প্রযুক্ত ত্বরণ পরিমাপ করে, যার মধ্যে অভিকর্ষ বলও অন্তর্ভুক্ত। নিম্নলিখিত কোডটি দেখায় কিভাবে ডিফল্ট অ্যাক্সিলারেশন সেন্সরের একটি ইনস্ট্যান্স পাওয়া যায়:
কোটলিন
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER)
জাভা
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_ACCELEROMETER);
দ্রষ্টব্য: আপনার অ্যাপটি যদি অ্যান্ড্রয়েড ১২ (এপিআই লেভেল ৩১) বা তার উচ্চতর সংস্করণকে টার্গেট করে, তাহলে এই সেন্সরটি রেট-লিমিটেড হবে ।
ধারণাগতভাবে, একটি ত্বরণ সেন্সর নিম্নলিখিত সম্পর্কটি ব্যবহার করে সেন্সরটির নিজের উপর প্রযুক্ত বল ( Fs ) পরিমাপের মাধ্যমে কোনো ডিভাইসের উপর প্রযুক্ত ত্বরণ ( Ad ) নির্ণয় করে:

তবে, অভিকর্ষ বল সর্বদা নিম্নলিখিত সম্পর্ক অনুসারে পরিমাপকৃত ত্বরণকে প্রভাবিত করে:

এই কারণে, যখন ডিভাইসটি একটি টেবিলের উপর রাখা থাকে (এবং এর কোনো ত্বরণ হয় না), তখন অ্যাক্সেলেরোমিটার g = 9.81 m/ s² মান দেখায়। একইভাবে, যখন ডিভাইসটি মুক্তভাবে পড়তে থাকে এবং ফলস্বরূপ 9.81 m/ s² ত্বরণে ভূমির দিকে দ্রুত অগ্রসর হতে থাকে, তখন এর অ্যাক্সেলেরোমিটার g = 0 m/ s² মান দেখায়। সুতরাং, ডিভাইসটির প্রকৃত ত্বরণ পরিমাপ করার জন্য, অ্যাক্সেলেরোমিটারের ডেটা থেকে অভিকর্ষ বলের প্রভাব অবশ্যই বাদ দিতে হবে। এটি একটি হাই-পাস ফিল্টার প্রয়োগ করে করা যেতে পারে। বিপরীতভাবে, অভিকর্ষ বলকে আলাদা করার জন্য একটি লো-পাস ফিল্টার ব্যবহার করা যেতে পারে। নিচের উদাহরণটি দেখায় যে আপনি কীভাবে এটি করতে পারেন:
কোটলিন
override fun onSensorChanged(event: SensorEvent) { // 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. val alpha: Float = 0.8f // 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] }
জাভা
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]; }
দ্রষ্টব্য: সেন্সর ডেটা ফিল্টার করার জন্য আপনি বিভিন্ন কৌশল ব্যবহার করতে পারেন। উপরের কোড নমুনাটি একটি লো-পাস ফিল্টার তৈরি করতে একটি সাধারণ ফিল্টার ধ্রুবক (আলফা) ব্যবহার করে। এই ফিল্টার ধ্রুবকটি একটি সময় ধ্রুবক (t) এবং সেন্সরের ইভেন্ট ডেলিভারি হার (dt) থেকে নেওয়া হয়। সময় ধ্রুবকটি হলো সেন্সর ইভেন্টগুলিতে ফিল্টারের দ্বারা যুক্ত হওয়া লেটেন্সির একটি মোটামুটি উপস্থাপনা। কোড নমুনাটি প্রদর্শনের উদ্দেশ্যে আলফার মান ০.৮ ব্যবহার করেছে। আপনি যদি এই ফিল্টারিং পদ্ধতিটি ব্যবহার করেন, তবে আপনাকে একটি ভিন্ন আলফার মান বেছে নিতে হতে পারে।
অ্যাক্সেলেরোমিটার স্ট্যান্ডার্ড সেন্সর স্থানাঙ্ক ব্যবস্থা ব্যবহার করে। বাস্তবে, এর অর্থ হলো, যখন কোনো ডিভাইস তার স্বাভাবিক অবস্থানে একটি টেবিলের উপর সমতলভাবে রাখা থাকে, তখন নিম্নলিখিত শর্তগুলো প্রযোজ্য হয়:
- যদি আপনি ডিভাইসটির বাম দিকে ধাক্কা দেন (ফলে এটি ডানদিকে সরে যায়), তাহলে x ত্বরণের মান ধনাত্মক হবে।
- যদি আপনি ডিভাইসটির নিচের অংশে ধাক্কা দেন (যাতে এটি আপনার থেকে দূরে সরে যায়), তাহলে y ত্বরণের মান ধনাত্মক হবে।
- যদি আপনি যন্ত্রটিকে A m/ s² ত্বরণে আকাশের দিকে ঠেলে দেন, তাহলে z-অক্ষের ত্বরণের মান হবে A + 9.81, যা যন্ত্রটির ত্বরণ (+A m/ s² ) থেকে অভিকর্ষ বল (-9.81 m/ s² ) বিয়োগফলের সমান।
- স্থির ডিভাইসটির ত্বরণের মান হবে +৯.৮১, যা ডিভাইসটির ত্বরণের (০ মি/ সে² থেকে অভিকর্ষ বল, যা -৯.৮১ মি/ সে² , বিয়োগফল) সমান।
সাধারণভাবে, ডিভাইসের গতিবিধি পর্যবেক্ষণের জন্য অ্যাক্সেলেরোমিটার একটি ভালো সেন্সর। প্রায় প্রতিটি অ্যান্ড্রয়েড-চালিত হ্যান্ডসেট এবং ট্যাবলেটে অ্যাক্সেলেরোমিটার থাকে এবং এটি অন্যান্য মোশন সেন্সরের তুলনায় প্রায় ১০ গুণ কম শক্তি ব্যবহার করে। এর একটি অসুবিধা হলো, মহাকর্ষীয় শক্তি দূর করতে এবং নয়েজ কমাতে আপনাকে লো-পাস ও হাই-পাস ফিল্টার প্রয়োগ করতে হতে পারে।
জাইরোস্কোপ ব্যবহার করুন
জাইরোস্কোপ একটি ডিভাইসের x, y, এবং z অক্ষের চারপাশে ঘূর্ণনের হার রেডিয়ান/সেকেন্ড (rad/s) এককে পরিমাপ করে। নিম্নলিখিত কোডটি দেখায় কিভাবে ডিফল্ট জাইরোস্কোপের একটি ইনস্ট্যান্স পাওয়া যায়:
কোটলিন
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE)
জাভা
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE);
দ্রষ্টব্য: আপনার অ্যাপটি যদি অ্যান্ড্রয়েড ১২ (এপিআই লেভেল ৩১) বা তার উচ্চতর সংস্করণকে টার্গেট করে, তাহলে এই সেন্সরটি রেট-লিমিটেড হবে ।
সেন্সরটির স্থানাঙ্ক ব্যবস্থা ত্বরণ সেন্সরের জন্য ব্যবহৃত স্থানাঙ্ক ব্যবস্থার অনুরূপ। ঘড়ির কাঁটার বিপরীত দিকে ঘূর্ণন ধনাত্মক; অর্থাৎ, x, y বা z অক্ষের কোনো ধনাত্মক অবস্থান থেকে মূলবিন্দুতে অবস্থিত একটি ডিভাইসের দিকে তাকানো কোনো পর্যবেক্ষক ধনাত্মক ঘূর্ণন হিসেবে রিপোর্ট করবে, যদি ডিভাইসটিকে ঘড়ির কাঁটার বিপরীত দিকে ঘুরতে দেখা যায়। এটিই ধনাত্মক ঘূর্ণনের প্রমিত গাণিতিক সংজ্ঞা এবং এটি ওরিয়েন্টেশন সেন্সর দ্বারা ব্যবহৃত রোলের সংজ্ঞার মতো নয়।
সাধারণত, টাইমস্টেপ জুড়ে কোণের পরিবর্তন বর্ণনা করে এমন একটি ঘূর্ণন গণনা করার জন্য জাইরোস্কোপের আউটপুটকে সময়ের সাপেক্ষে ইন্টিগ্রেট করা হয়। উদাহরণস্বরূপ:
কোটলিন
// Create a constant to convert nanoseconds to seconds. private val NS2S = 1.0f / 1000000000.0f private val deltaRotationVector = FloatArray(4) { 0f } private var timestamp: Float = 0f override fun onSensorChanged(event: SensorEvent?) { // This timestep's delta rotation to be multiplied by the current rotation // after computing it from the gyro sample data. if (timestamp != 0f && event != null) { val dT = (event.timestamp - timestamp) * NS2S // Axis of the rotation sample, not normalized yet. var axisX: Float = event.values[0] var axisY: Float = event.values[1] var axisZ: Float = event.values[2] // Calculate the angular speed of the sample val omegaMagnitude: Float = sqrt(axisX * axisX + axisY * axisY + axisZ * axisZ) // Normalize the rotation vector if it's big enough to get the axis // (that is, EPSILON should represent your maximum allowable margin of error) if (omegaMagnitude > EPSILON) { axisX /= omegaMagnitude axisY /= omegaMagnitude axisZ /= omegaMagnitude } // Integrate around this axis with the angular speed by the timestep // in order to get a delta rotation from this sample over the timestep // We will convert this axis-angle representation of the delta rotation // into a quaternion before turning it into the rotation matrix. val thetaOverTwo: Float = omegaMagnitude * dT / 2.0f val sinThetaOverTwo: Float = sin(thetaOverTwo) val cosThetaOverTwo: Float = cos(thetaOverTwo) deltaRotationVector[0] = sinThetaOverTwo * axisX deltaRotationVector[1] = sinThetaOverTwo * axisY deltaRotationVector[2] = sinThetaOverTwo * axisZ deltaRotationVector[3] = cosThetaOverTwo } timestamp = event?.timestamp?.toFloat() ?: 0f val deltaRotationMatrix = FloatArray(9) { 0f } SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector); // User code should concatenate the delta rotation we computed with the current rotation // in order to get the updated rotation. // rotationCurrent = rotationCurrent * deltaRotationMatrix; }
জাভা
// Create a constant to convert nanoseconds to seconds. private static final float NS2S = 1.0f / 1000000000.0f; private final float[] deltaRotationVector = new float[4](); private float timestamp; public void onSensorChanged(SensorEvent event) { // This timestep's delta rotation to be multiplied by the current rotation // after computing it from the gyro sample data. if (timestamp != 0) { final float dT = (event.timestamp - timestamp) * NS2S; // Axis of the rotation sample, not normalized yet. float axisX = event.values[0]; float axisY = event.values[1]; float axisZ = event.values[2]; // Calculate the angular speed of the sample float omegaMagnitude = sqrt(axisX*axisX + axisY*axisY + axisZ*axisZ); // Normalize the rotation vector if it's big enough to get the axis // (that is, EPSILON should represent your maximum allowable margin of error) if (omegaMagnitude > EPSILON) { axisX /= omegaMagnitude; axisY /= omegaMagnitude; axisZ /= omegaMagnitude; } // Integrate around this axis with the angular speed by the timestep // in order to get a delta rotation from this sample over the timestep // We will convert this axis-angle representation of the delta rotation // into a quaternion before turning it into the rotation matrix. float thetaOverTwo = omegaMagnitude * dT / 2.0f; float sinThetaOverTwo = sin(thetaOverTwo); float cosThetaOverTwo = cos(thetaOverTwo); deltaRotationVector[0] = sinThetaOverTwo * axisX; deltaRotationVector[1] = sinThetaOverTwo * axisY; deltaRotationVector[2] = sinThetaOverTwo * axisZ; deltaRotationVector[3] = cosThetaOverTwo; } timestamp = event.timestamp; float[] deltaRotationMatrix = new float[9]; SensorManager.getRotationMatrixFromVector(deltaRotationMatrix, deltaRotationVector); // User code should concatenate the delta rotation we computed with the current rotation // in order to get the updated rotation. // rotationCurrent = rotationCurrent * deltaRotationMatrix; }
সাধারণ জাইরোস্কোপগুলো নয়েজ এবং ড্রিফট (বায়াস)-এর জন্য কোনো ফিল্টারিং বা সংশোধন ছাড়াই সরাসরি ঘূর্ণন ডেটা প্রদান করে। বাস্তবে, জাইরোস্কোপের নয়েজ এবং ড্রিফট এমন ত্রুটি তৈরি করে যার ক্ষতিপূরণ করা প্রয়োজন। সাধারণত গ্র্যাভিটি সেন্সর বা অ্যাক্সেলেরোমিটারের মতো অন্যান্য সেন্সর পর্যবেক্ষণ করে ড্রিফট (বায়াস) এবং নয়েজ নির্ণয় করা হয়।
অ-ক্যালিব্রেটেড জাইরোস্কোপ ব্যবহার করুন
আনক্যালিব্রেটেড জাইরোস্কোপটি জাইরোস্কোপের মতোই, তবে এর ঘূর্ণন হারের উপর কোনো জাইরো-ড্রিফট ক্ষতিপূরণ প্রয়োগ করা হয় না। ঘূর্ণন হারের উপর ফ্যাক্টরি ক্যালিব্রেশন এবং তাপমাত্রা ক্ষতিপূরণ এখনও প্রয়োগ করা হয়। আনক্যালিব্রেটেড জাইরোস্কোপ পোস্ট-প্রসেসিং এবং ওরিয়েন্টেশন ডেটা মেল্ডিং-এর জন্য উপযোগী। সাধারণত, gyroscope_event.values[0] uncalibrated_gyroscope_event.values[0] - uncalibrated_gyroscope_event.values[3] এর কাছাকাছি হবে। অর্থাৎ,
calibrated_x ~= uncalibrated_x - bias_estimate_x
দ্রষ্টব্য: আনক্যালিব্রেটেড সেন্সরগুলো আরও বেশি অপরিশোধিত ফলাফল প্রদান করে এবং এতে কিছু পক্ষপাত থাকতে পারে, কিন্তু ক্যালিব্রেশনের মাধ্যমে প্রয়োগ করা সংশোধনের ফলে এদের পরিমাপে তারতম্য কম থাকে। কিছু অ্যাপ্লিকেশন এই আনক্যালিব্রেটেড ফলাফলগুলোকে মসৃণ এবং অধিক নির্ভরযোগ্য হিসেবে পছন্দ করতে পারে। উদাহরণস্বরূপ, যদি কোনো অ্যাপ্লিকেশন নিজস্ব সেন্সর ফিউশন পরিচালনা করার চেষ্টা করে, তবে ক্যালিব্রেশন যুক্ত করলে তা ফলাফলকে বিকৃত করতে পারে।
ঘূর্ণন হারের পাশাপাশি, আনক্যালিব্রেটেড জাইরোস্কোপ প্রতিটি অক্ষের সাপেক্ষে আনুমানিক ড্রিফটও প্রদান করে। নিম্নলিখিত কোডটি দেখায় কিভাবে ডিফল্ট আনক্যালিব্রেটেড জাইরোস্কোপের একটি ইনস্ট্যান্স পাওয়া যায়:
কোটলিন
val sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager val sensor: Sensor? = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED)
জাভা
private SensorManager sensorManager; private Sensor sensor; ... sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE); sensor = sensorManager.getDefaultSensor(Sensor.TYPE_GYROSCOPE_UNCALIBRATED);
অতিরিক্ত কোডের নমুনা
BatchStepSensor স্যাম্পলটি এই পৃষ্ঠায় আলোচিত API-গুলোর ব্যবহার আরও বিশদভাবে প্রদর্শন করে।