মোশন সেন্সর

Android প্ল্যাটফর্ম একাধিক সেন্সর প্রদান করে যা আপনাকে ডিভাইসের মোশন মনিটর করতে দেয়।

সেন্সরের ধরন অনুযায়ী সেন্সরের সম্ভাব্য আর্কিটেকচার আলাদা হয়:

  • গ্র্যাভিটি, লিনিয়ার অ্যাক্সিলারেশন, রোটেশন ভেক্টর, সিগনিফিক্যান্ট মোশন, স্টেপ কাউন্টার ও স্টেপ ডিটেক্টর সেন্সর হার্ডওয়্যার-ভিত্তিক বা সফ্টওয়্যার-ভিত্তিক হয়।
  • অ্যাকসিলরোমিটার ও জাইরোস্কোপ সেন্সর সবসময় হার্ডওয়্যার-ভিত্তিক হয়।

Android দ্বারা পরিচালিত বেশিরভাগ ডিভাইসে অ্যাকসিলরোমিটার থাকে এবং এখন অনেক ডিভাইসে জাইরোস্কোপও থাকে। সফ্টওয়্যার-ভিত্তিক সেন্সরগুলির উপলভ্যতা আরও বেশি পরিবর্তনশীল কারণ তারা প্রায়শই তাদের ডেটা পেতে এক বা একাধিক হার্ডওয়্যার সেন্সরের উপর নির্ভর করে। ডিভাইসের উপর নির্ভর করে, এই সফ্টওয়্যার-ভিত্তিক সেন্সরগুলি অ্যাকসিলরোমিটার এবং ম্যাগনেটোমিটার বা জাইরোস্কোপ থেকে তাদের ডেটা পেতে পারে।

মোশন সেন্সর ডিভাইসের মুভমেন্ট যেমন কাত করা, ঝাঁকানো, ঘোরানো বা দোলানো মনিটর করার জন্য উপযোগী। এই মুভমেন্ট সাধারণত ব্যবহারকারীর সরাসরি ইনপুটের প্রতিফলন (যেমন, কোনও গেমে ব্যবহারকারীর গাড়ি চালানো বা বল কন্ট্রোল করা), তবে এটি ডিভাইসটি যে ফিজিক্যাল পরিবেশে রয়েছে তার প্রতিফলনও হতে পারে (যেমন, আপনি গাড়ি চালানোর সময় আপনার সাথে মুভ করা)। প্রথম ক্ষেত্রে, আপনি ডিভাইসের ফ্রেম অফ রেফারেন্স বা আপনার অ্যাপ্লিকেশনের ফ্রেম অফ রেফারেন্সের সাপেক্ষে গতিবিধি মনিটর করছেন; দ্বিতীয় ক্ষেত্রে, আপনি পৃথিবীর ফ্রেম অফ রেফারেন্সের সাপেক্ষে গতিবিধি মনিটর করছেন। মোশন সেন্সর সাধারণত ডিভাইসের পজিশন মনিটর করার জন্য ব্যবহার করা হয় না, তবে পৃথিবীর ফ্রেম অফ রেফারেন্সের সাপেক্ষে ডিভাইসের পজিশন নির্ধারণ করার জন্য জিওম্যাগনেটিক ফিল্ড সেন্সরের মতো অন্যান্য সেন্সরের সাথে এটি ব্যবহার করা যেতে পারে (আরও তথ্যের জন্য পজিশন সেন্সর দেখুন)।

সব মোশন সেন্সর প্রতিটি SensorEvent-এর জন্য সেন্সর ভ্যালুর মাল্টি-ডাইমেনশনাল অ্যারে রিটার্ন করে। যেমন, একটি সেন্সর ইভেন্টের সময় অ্যাকসিলরোমিটার তিনটি কোঅর্ডিনেট অক্ষের জন্য অ্যাকসিলারেশন ফোর্স ডেটা এবং জাইরোস্কোপ তিনটি কোঅর্ডিনেট অক্ষের জন্য রেট অফ রোটেশন ডেটা প্রদান করে। এই ডেটা ভ্যালু float অ্যারেতে (values) অন্যান্য SensorEvent প্যারামিটারের সাথে রিটার্ন করা হয়। Android প্ল্যাটফর্মে উপলভ্য মোশন সেন্সরগুলির সারসংক্ষেপ সারণী ১-এ দেওয়া হয়েছে।

টেবিল ১. Android প্ল্যাটফর্মে কাজ করে এমন মোশন সেন্সর।

সেন্সর সেন্সর ইভেন্ট ডেটা বর্ণনা পরিমাপের ইউনিট
TYPE_ACCELEROMETER SensorEvent.values[0] x অক্ষ বরাবর ত্বরণ বল (মাধ্যাকর্ষণ সহ)। মিঃ/সেঃ২
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 অক্ষের চারপাশে ঘূর্ণনের হার। rad/s
SensorEvent.values[1] y অক্ষের চারপাশে ঘূর্ণনের হার।
SensorEvent.values[2] z অক্ষের চারপাশে ঘূর্ণনের হার।
TYPE_GYROSCOPE_UNCALIBRATED SensorEvent.values[0] x অক্ষের চারপাশে ঘূর্ণনের হার (ড্রিফ্ট ক্ষতিপূরণ ছাড়া)। rad/s
SensorEvent.values[1] y অক্ষের চারপাশে ঘূর্ণনের হার (ড্রিফ্ট ক্ষতিপূরণ ছাড়া)।
SensorEvent.values[2] z অক্ষের চারপাশে ঘূর্ণনের হার (ড্রিফ্ট ক্ষতিপূরণ ছাড়া)।
SensorEvent.values[3] x অক্ষের চারপাশে আনুমানিক ড্রিফ্ট।
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))।১
TYPE_SIGNIFICANT_MOTION N/A N/A N/A
TYPE_STEP_COUNTER SensorEvent.values[0] সেন্সর অ্যাক্টিভেট থাকার সময় শেষবার রিবুট করার পর থেকে ব্যবহারকারীর নেওয়া স্টেপের সংখ্যা। ধাপ
TYPE_STEP_DETECTOR N/A N/A N/A

১ স্কেলার কম্পোনেন্ট হল একটি ঐচ্ছিক ভ্যালু।

রোটেশন ভেক্টর সেন্সর এবং গ্র্যাভিটি সেন্সর হল মোশন শনাক্তকরণ এবং পর্যবেক্ষণের জন্য সবচেয়ে বেশি ব্যবহৃত সেন্সর। রোটেশনাল ভেক্টর সেন্সর বিশেষভাবে বহুমুখী এবং এটি গতিবিধি সম্পর্কিত বিভিন্ন ধরনের কাজের জন্য ব্যবহার করা যেতে পারে, যেমন জেসচার শনাক্ত করা, কৌণিক পরিবর্তন মনিটর করা এবং আপেক্ষিক ওরিয়েন্টেশন পরিবর্তন মনিটর করা। যেমন, আপনি যদি কোনও গেম, অগমেন্টেড রিয়েলিটি অ্যাপ্লিকেশন, ২-ডাইমেনশনাল বা ৩-ডাইমেনশনাল কম্পাস বা ক্যামেরা স্টেবিলাইজেশন অ্যাপ ডেভেলপ করেন, তাহলে রোটেশনাল ভেক্টর সেন্সর ব্যবহার করা আদর্শ। বেশিরভাগ ক্ষেত্রে, অ্যাকসিলিরোমিটার ও জিওম্যাগনেটিক ফিল্ড সেন্সর বা ওরিয়েন্টেশন সেন্সর ব্যবহার করার চেয়ে এইসব সেন্সর ব্যবহার করা ভাল।

Android ওপেন সোর্স প্রজেক্ট সেন্সর

Android ওপেন সোর্স প্রজেক্ট (AOSP) তিনটি সফ্টওয়্যার-ভিত্তিক মোশন সেন্সর প্রদান করে: একটি গ্র্যাভিটি সেন্সর, একটি লিনিয়ার অ্যাক্সিলারেশন সেন্সর এবং একটি রোটেশন ভেক্টর সেন্সর। এই সেন্সরগুলি Android 4.0-এ আপডেট করা হয়েছে এবং এখন স্থায়িত্ব ও পারফর্ম্যান্স উন্নত করতে ডিভাইসের জাইরোস্কোপ (অন্যান্য সেন্সর ছাড়াও) ব্যবহার করে। আপনি যদি এই সেন্সরগুলি ব্যবহার করে দেখতে চান, তাহলে আপনি getVendor() পদ্ধতি এবং getVersion() পদ্ধতি ব্যবহার করে সেগুলি শনাক্ত করতে পারেন (ভেন্ডর হল Google LLC; ভার্সন নম্বর হল ৩)। ভেন্ডর ও ভার্সন নম্বর অনুযায়ী এইসব সেন্সর শনাক্ত করা প্রয়োজন, কারণ Android সিস্টেম এই তিনটি সেন্সরকে সেকেন্ডারি সেন্সর হিসেবে বিবেচনা করে। যেমন, কোনও ডিভাইস প্রস্তুতকারক যদি নিজস্ব গ্র্যাভিটি সেন্সর প্রদান করে, তাহলে AOSP গ্র্যাভিটি সেন্সর সেকেন্ডারি গ্র্যাভিটি সেন্সর হিসেবে দেখানো হয়। এই তিনটি সেন্সরই জাইরোস্কোপের উপর নির্ভর করে: কোনও ডিভাইসে জাইরোস্কোপ না থাকলে, এই সেন্সরগুলি দেখা যায় না এবং ব্যবহারের জন্য উপলভ্য হয় না।

গ্র্যাভিটি সেন্সর ব্যবহার করুন

গ্র্যাভিটি সেন্সর একটি ত্রিমাত্রিক ভেক্টর প্রদান করে যা মাধ্যাকর্ষণের দিক ও মাত্রা নির্দেশ করে। সাধারণত, এই সেন্সরটি স্পেসে ডিভাইসের আপেক্ষিক ওরিয়েন্টেশন নির্ধারণ করতে ব্যবহার করা হয়। ডিফল্ট গ্র্যাভিটি সেন্সরের ইনস্ট্যান্স কীভাবে পাবেন তা নিম্নলিখিত কোড থেকে জানতে পারবেন:

Kotlin

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/s2) যে ইউনিট ব্যবহার করে, এটিও একই ইউনিট ব্যবহার করে এবং অ্যাক্সিলারেশন সেন্সর যে কোঅর্ডিনেট সিস্টেম ব্যবহার করে, এটিও একই কোঅর্ডিনেট সিস্টেম ব্যবহার করে।

মনে রাখবেন: ডিভাইস স্থির অবস্থায় থাকলে, গ্র্যাভিটি সেন্সরের আউটপুট অ্যাকসিলরোমিটারের আউটপুটের সাথে অভিন্ন হতে হবে।

লিনিয়ার অ্যাকসিলরোমিটার ব্যবহার করুন

লিনিয়ার অ্যাক্সিলারেশন সেন্সর আপনাকে একটি ত্রিমাত্রিক ভেক্টর প্রদান করে যা মাধ্যাকর্ষণ বাদ দিয়ে প্রতিটি ডিভাইস অক্ষ বরাবর ত্বরণকে উপস্থাপন করে। জেসচার শনাক্তকরণ পারফর্ম করতে আপনি এই ভ্যালু ব্যবহার করতে পারবেন। এছাড়াও, এই ভ্যালু ইনার্শিয়াল নেভিগেশন সিস্টেমে ইনপুট হিসেবে ব্যবহার করা যেতে পারে, যা ডেড রেকনিং ব্যবহার করে। নিচের কোড থেকে আপনি জানতে পারবেন কীভাবে ডিফল্ট লিনিয়ার অ্যাক্সিলারেশন সেন্সরের ইনস্ট্যান্স পাবেন:

Kotlin

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) চারপাশে θ কোণে ঘোরে। নিম্নলিখিত কোড থেকে আপনি জানতে পারবেন যে কীভাবে ডিফল্ট রোটেশন ভেক্টর সেন্সরের ইনস্ট্যান্স পাবেন:

Kotlin

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);

রোটেশন ভেক্টরের তিনটি এলিমেন্ট এইভাবে প্রকাশ করা হয়:

x*sin(θ/২), y*sin(θ/২), z*sin(θ/২)

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

ছবি ১. রোটেশন ভেক্টর সেন্সর দ্বারা ব্যবহৃত কোঅর্ডিনেট সিস্টেম।

রোটেশন ভেক্টরের তিনটি উপাদান ইউনিট কোয়াটার্নিয়নের শেষ তিনটি উপাদানের সমান (cos(θ/2), x*sin(θ/2), y*sin(θ/2), z*sin(θ/2))। রোটেশন ভেক্টরের এলিমেন্টগুলির কোনও ইউনিট নেই। x, y ও z অক্ষ অ্যাকসিলারেশন সেন্সরের মতোই সংজ্ঞায়িত করা হয়। রেফারেন্স কোঅর্ডিনেট সিস্টেমকে ডাইরেক্ট অর্থোনরমাল বেসিস হিসেবে সংজ্ঞায়িত করা হয় (ছবি ১ দেখুন)। এই কোঅর্ডিনেট সিস্টেমের নিম্নলিখিত বৈশিষ্ট্য আছে:

  • X-কে ভেক্টর প্রোডাক্ট Y x Z হিসেবে সংজ্ঞায়িত করা হয়। এটি ডিভাইসের বর্তমান লোকেশনে মাটির সাথে স্পর্শকীয় এবং আনুমানিক পূর্ব দিকে নির্দেশ করে।
  • Y হল ডিভাইসের বর্তমান লোকেশনে মাটির স্পর্শক এবং এটি ভূচৌম্বকীয় উত্তর মেরুর দিকে নির্দেশ করে।
  • Z আকাশের দিকে নির্দেশ করে এবং গ্রাউন্ড প্লেনের সাথে লম্বভাবে থাকে।

রোটেশন ভেক্টর সেন্সর কীভাবে ব্যবহার করতে হয় তা দেখায় এমন একটি স্যাম্পেল অ্যাপ্লিকেশনের জন্য, RotationVectorDemo.java দেখুন।

গুরুত্বপূর্ণ মোশন সেন্সর ব্যবহার করুন

প্রতিবার উল্লেখযোগ্য মোশন শনাক্ত করা হলে উল্লেখযোগ্য মোশন সেন্সর একটি ইভেন্ট ট্রিগার করে এবং তারপর এটি নিজেকে বন্ধ করে দেয়। উল্লেখযোগ্য মোশন হল এমন মোশন যা ব্যবহারকারীর লোকেশনে পরিবর্তন করতে পারে; যেমন হাঁটা, সাইকেল চালানো বা চলন্ত গাড়িতে বসে থাকা। নিম্নলিখিত কোড থেকে আপনি জানতে পারবেন কীভাবে ডিফল্ট উল্লেখযোগ্য মোশন সেন্সরের ইনস্ট্যান্স পাবেন এবং কীভাবে ইভেন্ট লিসেনার রেজিস্টার করবেন:

Kotlin

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 অনুমতি ঘোষণা করতে হবে।

নিচের কোড থেকে আপনি জানতে পারবেন যে কীভাবে ডিফল্ট স্টেপ কাউন্টার সেন্সরের ইনস্ট্যান্স পাবেন:

Kotlin

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 লেভেল ২৯) বা তার পরবর্তী যেকোনও ভার্সনে চলা ডিভাইসে আপনার অ্যাপ যাতে এই সেন্সর ব্যবহার করতে পারে তার জন্য আপনাকে ACTIVITY_RECOGNITION অনুমতি ঘোষণা করতে হবে।

নিচের কোড থেকে আপনি জানতে পারবেন যে কীভাবে ডিফল্ট স্টেপ ডিটেক্টর সেন্সরের ইনস্ট্যান্স পাবেন:

Kotlin

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);

অশোধিত ডেটা নিয়ে কাজ করা

নিম্নলিখিত সেন্সরগুলি আপনার অ্যাপকে ডিভাইসে প্রয়োগ করা লিনিয়ার এবং ঘূর্ণন বল সম্পর্কে কাঁচা ডেটা প্রদান করে। এইসব সেন্সর থেকে পাওয়া ভ্যালু কার্যকরভাবে ব্যবহার করতে, আপনাকে পরিবেশ থেকে ফ্যাক্টর ফিল্টার করতে হবে, যেমন মাধ্যাকর্ষণ। নয়েজ কমানোর জন্য আপনাকে ভ্যালুর ট্রেন্ডে স্মুদিং অ্যালগরিদম প্রয়োগ করতে হতে পারে।

অ্যাকসেলেরোমিটার ব্যবহার করুন

অ্যাক্সিলারেশন সেন্সর ডিভাইসে প্রয়োগ করা অ্যাক্সিলারেশন পরিমাপ করে, যার মধ্যে অভিকর্ষজ বলও অন্তর্ভুক্ত। নিচের কোড থেকে আপনি জানতে পারবেন যে কীভাবে ডিফল্ট অ্যাক্সিলারেশন সেন্সরের ইনস্ট্যান্স পাবেন:

Kotlin

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);

মনে রাখবেন: আপনার অ্যাপ Android 12 (API লেভেল 31) বা তার পরবর্তী যেকোনও ভার্সনকে টার্গেট করলে, এই সেন্সর রেট-সীমিত হয়।

ধারণাগতভাবে, একটি অ্যাক্সিলারেশন সেন্সর ডিভাইসে (Ad) প্রয়োগ করা অ্যাক্সিলারেশন নির্ধারণ করে, যা সেন্সরে (Fs) প্রয়োগ করা বল পরিমাপ করে, নিম্নলিখিত সম্পর্ক ব্যবহার করে:

A_D=-(1/mass)∑F_S

তবে, মাধ্যাকর্ষণ বল সবসময় নিম্নলিখিত সম্পর্ক অনুযায়ী পরিমাপ করা ত্বরণকে প্রভাবিত করে:

A_D=-g-(1/mass)∑F_S

এই কারণে, ডিভাইসটি যখন টেবিলে থাকে (এবং ত্বরান্বিত হয় না), তখন অ্যাকসিলরোমিটার g = ৯.৮১ m/s২-এর মান পড়ে। একইভাবে, ডিভাইসটি যখন মুক্তভাবে পড়ে এবং তাই ৯.৮১ মি/সে২ গতিতে মাটির দিকে দ্রুত ত্বরান্বিত হয়, তখন এর অ্যাক্সিলোমিটার g = ০ মি/সে২-এর মান পড়ে। তাই, ডিভাইসের আসল ত্বরণ পরিমাপ করতে, অ্যাকসিলরোমিটার ডেটা থেকে অভিকর্ষজ বলের অবদান বাদ দিতে হবে। হাই-পাস ফিল্টার প্রয়োগ করে এটি করা যেতে পারে। অন্যদিকে, মাধ্যাকর্ষণ বলকে আলাদা করতে লো-পাস ফিল্টার ব্যবহার করা যেতে পারে। আপনি কীভাবে এটি করতে পারেন তা নিম্নলিখিত উদাহরণ থেকে দেখুন:

Kotlin

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/s2 ত্বরণ সহ ডিভাইসটিকে আকাশের দিকে ঠেলে দেন, তাহলে z ত্বরণের মান A + 9.81-এর সমান হবে, যা ডিভাইসের ত্বরণ (+A m/s2) থেকে অভিকর্ষজ বল (-9.81 m/s2) বিয়োগ করার সমান।
  • স্থির ডিভাইসের ত্বরণের মান হবে +9.81, যা ডিভাইসের ত্বরণের সাথে সামঞ্জস্যপূর্ণ (0 m/s2 মাইনাস অভিকর্ষজ বল, যা হল -9.81 m/s2)।

সাধারণত, ডিভাইসের গতিবিধি মনিটর করার জন্য অ্যাকসিলারোমিটার একটি ভাল সেন্সর। প্রায় প্রতিটি Android-চালিত হ্যান্ডসেট ও ট্যাবলেটে অ্যাকসিলরোমিটার থাকে এবং এটি অন্যান্য মোশন সেন্সরের তুলনায় প্রায় ১০ গুণ কম পাওয়ার ব্যবহার করে। একটি অসুবিধা হল যে আপনাকে মাধ্যাকর্ষণ বল দূর করতে এবং শব্দ কমাতে লো-পাস এবং হাই-পাস ফিল্টার প্রয়োগ করতে হতে পারে।

জাইরোস্কোপ ব্যবহার করুন

জাইরোস্কোপ ডিভাইসের x, y ও z অক্ষের চারপাশে rad/s-এ ঘূর্ণনের হার পরিমাপ করে। ডিফল্ট জাইরোস্কোপের ইনস্ট্যান্স কীভাবে পাবেন তা নিম্নলিখিত কোড থেকে জানতে পারবেন:

Kotlin

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);

মনে রাখবেন: আপনার অ্যাপ Android 12 (API লেভেল 31) বা তার পরবর্তী যেকোনও ভার্সনকে টার্গেট করলে, এই সেন্সর রেট-সীমিত হয়।

সেন্সরের কোঅর্ডিনেট সিস্টেম অ্যাকসিলারেশন সেন্সরের জন্য ব্যবহৃত সিস্টেমের মতোই। ঘড়ির কাঁটার বিপরীত দিকে ঘোরানো হলে তা পজিটিভ হিসেবে ধরা হয়; অর্থাৎ, কোনও পর্যবেক্ষক x, y বা z অক্ষের কোনও পজিটিভ লোকেশন থেকে অরিজিনে থাকা কোনও ডিভাইসের দিকে তাকালে, ডিভাইসটি ঘড়ির কাঁটার বিপরীত দিকে ঘুরছে বলে মনে হলে তিনি পজিটিভ রোটেশন রিপোর্ট করবেন। এটি হল পজিটিভ রোটেশনের স্ট্যান্ডার্ড গাণিতিক সংজ্ঞা এবং এটি রোল-এর সংজ্ঞার মতো নয় যা ওরিয়েন্টেশন সেন্সর ব্যবহার করে।

সাধারণত, সময়ের সাথে সাথে জাইরোস্কোপের আউটপুট ইন্টিগ্রেট করা হয় যাতে টাইমস্টেপ জুড়ে কোণের পরিবর্তন বর্ণনা করে এমন রোটেশন গণনা করা যায়। যেমন:

Kotlin

// 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

মনে রাখবেন: ক্যালিব্রেট না করা সেন্সর আরও বেশি কাঁচা ফলাফল প্রদান করে এবং এতে কিছু পক্ষপাতিত্ব থাকতে পারে, তবে ক্যালিব্রেশনের মাধ্যমে প্রয়োগ করা সংশোধনের ফলে তাদের পরিমাপে কম জাম্প থাকে। কিছু অ্যাপ্লিকেশন এই ক্যালিব্রেট না করা ফলাফলকে আরও মসৃণ এবং আরও নির্ভরযোগ্য হিসেবে পছন্দ করতে পারে। যেমন, কোনও অ্যাপ্লিকেশন যদি নিজস্ব সেন্সর ফিউশন পরিচালনা করার চেষ্টা করে, তাহলে ক্যালিব্রেশন চালু করলে আসলে ফলাফল বিকৃত হতে পারে।

ঘূর্ণনের হার ছাড়াও, ক্যালিব্রেট না করা জাইরোস্কোপ প্রতিটি অক্ষের চারপাশে আনুমানিক ড্রিফ্ট প্রদান করে। নিচের কোড থেকে আপনি জানতে পারবেন যে কীভাবে ডিফল্ট আনক্যালিব্রেটেড জাইরোস্কোপের ইনস্ট্যান্স পাবেন:

Kotlin

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-এর ব্যবহার আরও দেখায়।

এছাড়াও আপনার পড়া উচিত