Understanding Sphero-provided magnetometer programs for the RVR

For my hardware I’m using a Raspberry Pi 3B properly wired to a RVR.

For the software I’m using the latest version of the RVR python code (August 20 release) with the latest RVR firmware (SoC version 8.3.432 and ST SoC version 8.6.448).

Here is what I’d like to accomplish:

  • I’m basically trying to understand how the two Sphero-provided “getting started” python-based magnetometer programs work. The programs magnetometer_calibrate_to_north.py and get_magnetometer_reading.py are located in /sphero-sdk-raspberrypi-python-master/getting started/asyncio/magnetometer directory.

  • My ultimate goal find or at worst case develop an asynchronous python function that reads the RVR magnetometer and outputs a heading.

Here are my questions:

  1. Where can I find information and/or documentation on how these programs work?

  2. Using my iPhone I orient the RVR with the front (with the blue button) facing North at 0 degrees.
    When I run magnetometer_calibrate_to_north.py, I get the following results:
    ____Begin magnetometer calibration to find North…
    ____RVR spins 360 in the counter clockwise direction
    ____Calibration complete, response: {‘is_successful’: True, ‘yaw_north_direction’: -166}
    Given this setup what does a ‘yaw_north_direction’: -166 mean?

  3. Again, I orient the RVR to face North at 0 degrees.
    When I run get_magnetometer_reading.py, I get the following results:
    ____Magnetometer reading: {‘x_axis’: -35.0, ‘y_axis’: 50.0, ‘z_axis’: -135.0}

    I looked at Sphero RVR Control System Manual and found the following Right hand rule reference:

    Even with this information, and my setup, I still don’t understand what the x_axis and y_axis values mean?

  4. Finally are there any Python functions in the sphero_sdk that provide:
    a. An asynchronous python function that resets the heading to zero?
    b. An asynchronous python function that reads the RVR magnetometer and outputs a heading?
    c. If these functions don’t exist, is there any documentation that would help me develop custom asynchronous python functions that will work with the Sphero RVR sdk?

I’m sorry for the long post. Thanks in advance for any assistance that you can provide.

…Gary White

Hi Gary,

Welcome to our community, and never apologize for a long detailed post! You’ve asked excellent questions, and shown me that we have a glaring documentation hole here. Fortunately, I’m working on some much-needed SDK site updates right now, and I’ve added it to my to-do list.

In the meantime, I’ll try to give some brief but hopefully useful answers to your questions:

  1. TBD.

  2. The yaw_north_direction value is the offset from yaw=0 to magnetic north. If you were to call reset_aim() when RVR is pointing north, the offset would be approximately zero. Magnetometer readings tend to be noisy at floor level due to the prevalence of ferrous metals in some floor structures, and the full rotation allows us to do some extra filtering. The intended usage of the offset is mostly for the Sphero EDU app to synchronize RVR’s yaw orientation with the phone on which it is running. In the case of the EDU app, it never actually requests a magnetometer reading directly. Instead, it simulates the magnetometer heading using the reported north offset and the IMU heading. You can do the same in your own programs, but our examples don’t show how to do that (another to-do list item)

  3. get_magnetometer_reading.py is showing you how to access the raw magnetometer readings. This example should probably have gotten a disclaimer stating that the raw readings are not as useful as you might think. If you’re curious and want to dig into it yourself, the magnetometer datasheet is available here: Magnetometer BMM150 | Bosch Sensortec. Be aware that the z-axis resolution is different from the x and y axes.

4.a. Yes. reset_aim() will reset the IMU yaw and heading angles to zero. So you could perform the magnetometer calibration, turn to the reported yaw_north_direction with drive_with_yaw(0, yaw_north_direction), and then call reset_aim().
4.b. That’s not something we included.
4.c. You could perform the magnetometer calibration, store the yaw_north_direction, and then apply that offset to the yaw angle obtained through the sensor streaming interface. (See multi_sensor_stream.py for an IMU data streaming example) In order to convert to compass headings, you’ll need to switch the polarity accordingly.

I hope this answers most of your questions for now. If not, let me know.

Happy programming!
Jim

Hi JIm,

I am revising my C++ API to work with the new firmware. I saw this question so started with the magnetometer. All three of the APIs are working except for a strange response for magnetometer_calibration_complete_notify. The packet returned is:

20 2 18 51 FF 1 0 9 

The 0xFF is in the sequence position which is unusual. At least I don’t recall seeing it in a notify response message previously. Maybe I’ve missed it. I realize the 1 0 9 are the data.

Is this a change to the protocol?

@gbw48 Using my own code I get XYZ values of -143.0000 11.0000 -86.0000 after calibrating. I’ve noticed that putting my phone compass app near the RVR changes the readings, probably due to the magnets in the RVR’s motors. I’ll read the material @Sphero_JimK provided to see if it explains the readings. My guess is they are reading the direct path through the earth to the magnetic pole or something similar. So depending on your position on the globe you’d see different readings. For example, at the south pole, the Z reading would be close to -180. Again, a guess at what is happeneing.

Hey Rud,

It’s great to hear that you’re digging into the newer features. We use 0xFF as a special null sequence number, sent any time that RVR sends a command without requesting a response (i.e. bit 1 is zero, as described here). This includes all of our notification packets. It’s not strictly necessary to use the null sequence number for a command without response, just more of a polite convention. We’ve done this all along on RVR, so if you do find an exception to the rule I’d be curious to take a look.

I’ve added this to my documentation backlog.

Here is a reference on creating a compass heading: https://cdn-shop.adafruit.com/datasheets/AN203_Compass_Heading_Using_Magnetometers.pdf

Found one from another vendor that says the same: use atan of x and y.

It’s been a while since I worked with my code and the protocol. Got confused about the magnetometer_calibration_complete_notify thinking it is a response to a request, not a notification. As you mentioned it has the not a response flag set.

Need to study my code to see how I’m handling notifications that have data.

Hi Jim,
Thanks for getting back to me… I’m trying to work through your suggestions, especially 4a and 4c. I’m having trouble issuing the reset_aim() command.

With respect to the asyncio version of magnetometer_calibrate_to_north.py program, this is what I did:

  • Edited the magnetometer_calibrate_to_north.py to include “await rvr.wake()” in the following section of code (after the “# Added rvr.reset_aim() command” comment) :

    async def main():
    “”" This program demonstrates the magnetometer calibration to find north.
    “”"
    global calibration_completed
    # Added await rvr.wake() command
    await rvr.wake()

    # Give RVR time to wake up
    await asyncio.sleep(2)

    # Added rvr.reset_aim() command
    await rvr.reset_aim()

    # Register for the async on completion of calibration
    await rvr.on_magnetometer_calibration_complete_notify…
    …(handler=on_calibration_complete_notify_handler)

  • This was the error I received:

    Traceback (most recent call last):
    File “magnetometer_calibrate_to_north.py”, line 60, in
    main()

    File “/usr/lib/python3.7/asyncio/base_events.py”, line 584, in run_until_complete
    return future.result()

    File “magnetometer_calibrate_to_zero.py”, line 40, in main
    await rvr.reset_aim()

    AttributeError: ‘SpheroRvrAsync’ object has no attribute ‘reset_aim’

With respect to the observer version of magnetometer_calibrate_to_north.py program, this is what I did:

  • Edited the magnetometer_calibrate_to_north.py to include “rvr.reset_aim()” in the following section of code (after the “# Added rvr.reset_aim() command” comment) :

    def main():
    “”" This program demonstrates the magnetometer calibration to find north.
    “”"

    try:
    __global calibration_completed

    __rvr.wake()

    __# Give RVR time to wake up
    __time.sleep(2)

    __# Added rvr.reset_aim() command
    __rvr.reset_aim()

    __# Register for the async on completion of calibration

    __rvr.on_magnetometer_calibration_complete_notify(handler=on_calibration_complete_notify_handler)

  • This was the error I received:

    Traceback (most recent call last):

    File “wmagnetometer_calibrate_to_north.py”, line 56, in
    main()

    File “wmagnetometer_calibrate_to_zero.py”, line 34, in main
    rvr.reset_aim()

    AttributeError: ‘SpheroRvrObserver’ object has no attribute ‘reset_aim’

    (program exited with code: 1)
    Press return to continue

Given this here are my questions:

  1. Can you please indicate what I’ doing wrong in adding an reset_aim() command to the asyncio version of magnetometer_calibrate_to_north.py. It would be helpful if you could provide the code as well.

  2. Can you please indicate what I’ doing wrong in adding an reset_aim() command to the observer version of magnetometer_calibrate_to_north.py. It would be helpful if you could provide the code as well.

  3. In following your suggestions for questions 4a and 4c, I’m not entirely sure how to code what you what you suggest (especially when incorporating code from the multi_sensor_stream.py program).

    I’d like some help in creating an asyncio program that does as you suggest. Namely: magnetometer calibration, store the yaw_north_direction, and then apply that offset to the yaw angle obtained through the sensor streaming interface. Again, it would be most helpful if you could provide the code for this.

  4. Lastly, as you can tell I’m somewhat new to python, especially with respect asynchronous code. I’d be very grateful if can you can identify any pertinent asyncio resources on your site.

Thanks in advance for any assistance you can provide. I know it’s a big ask, but any code that you can provide would be most appreciated.

Gary

Hi Gary,

Sorry about that, I confused the naming with something else. The real method is reset_yaw(), not reset_aim().

This seems like a good candidate for some SDK-side improvements in the future, as this should really be easier. I have an improved version of the asyncio magnetometer calibration on GitHub in the feature/magnetometer-improvements branch. You can view the file directly here. In retrospect, the example should always have been something like this.

Thanks for your patience. I hope the new example is more helpful.

Jim

I think @Sphero_JimK misspoke and meant reset_yaw() when the RVR is pointing north. That will set the yaw to zero when pointing north. Then you can use the drive commands to turn in a compass direction using the yaw value.

[With respect to your other question about streaming I see you found a python streaming example: multi_sensor_stream.py.]

@gbw48, I just merged Feature/magnetometer examples by Jim-Konish · Pull Request #15 · sphero-inc/sphero-sdk-raspberrypi-python · GitHub to bring improved observer and asyncio examples into the master branch.

Let me know if you have other questions.

Jim

Hi Jim,

I just tested out the new versions (observer and asyncio) of magnetometer_calibrate_to_north.py. Regardless of initial orientation, the RVR will spin to North, pause and then turn 90 degrees to the East. The final position of the RVR, as measured by my iPhone, was between 87 and 93 degrees.

This is a great and useful improvement over the previous utility. Thanks for upgrading the program.

…Gary

SPHERO Email Marketing -