Module Connector - Raspberry Pi 1.4.2

SW used to communicate with all XeThru modules on a host computer

  1. Christian Rødli Amble

    Christian Rødli Amble New Member Staff Member

  2. Christian Rødli Amble

    Christian Rødli Amble New Member Staff Member

  3. Øystein Bjørndal

    Øystein Bjørndal New Member

    Two points: (1) the Makefile has a typo, the 'D_GLIBCXX_USE_CXX11_ABI' option should be '-D_GLIBCXX_USE_CXX11_ABI=0' to be effective.

    (2)
    I am getting a weird "bus error' when calling xep.x4driver_get_fps only when running on raspberry-pi. Code segment:

    Code:
          // set fps so that we can get_ it below                                                                                                                                                                                                                                     
          if (xep.x4driver_set_fps(fps)) {                                                                                                                                                                                                                                            
            return handle_error("unable to set fps");                                                                                                                                                                                                                                
          }                                                                                                                                                                                                                                                                          
          std::cout << "fps set to " << fps << std::endl;                                                                                                                                                                                                                            
                                                                                                                                                                                                                                                                                    
          int status = 0;                                                                                                                                                                                                                                                             
          float fps_get = 0;                                                                                                                                                                                                                                                          
          status += xep.x4driver_get_fps(&fps_get); // offending line
    
    The above code works fine on osx, but fails, as seen below on raspberry-pi:

    Hopefully relevant system info:
    Code:
    > uname -a
    Linux raspberrypi 4.4.13-v7+ #894 SMP Mon Jun 13 13:13:27 BST 2016 armv7l GNU/Linux
    > ./record /dev/serial/by-id/usb-03eb_XeThru_Serial-if00
    0.000329 : RadarInterface - base -- begin
    0.000895 : log_trace -- begin
    0.001009 : log_trace -- end
    0.001061 : git sha: 51cb921866bb
    0.001102 : build date: 2017-09-15 13:20:35
    ....
    0.003575 : open -- begin
    0.003858 : LinuxModuleIo::open /dev/serial/by-id/usb-03eb_XeThru_Serial-if00 -- begin
    0.004321 : LinuxModuleIo::open /dev/serial/by-id/usb-03eb_XeThru_Serial-if00 -- end
    0.004400 : open -- end
    0.004439 : open -- end
    0.004491 : get_system_info -- begin
    0.004537 : dispatching packet: 
    0.004602 : sending: 
    0.004651 : 5: {0x30, 0x10, 0x0, 0x0, 0x0, }
    0.004698 : 6: {0x7d, 0x90, 0x58, 0x2, 0xb7, 0x7e, }
    0.004744 : dispatching packet: 
    0.004787 : sent
    0.004830 : 5: {0x30, 0x11, 0x0, 0x0, 0x0, }
    0.004923 : dispatching packet: 
    0.004979 : 18: {0x11, 0x13, 0x58, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x58, 0x45, 0x50, 0x1, }
    0.005083 : get_system_info -- end
    system_info = XEP
    ...
    0.039678 : x4driver_set_fps -- end
    fps set to 50
    0.039815 : x4driver_get_fps -- begin
    0.039951 : sending: 
    0.040046 : 9: {0x7d, 0x50, 0x11, 0x10, 0x0, 0x0, 0x0, 0x2c, 0x7e, }
    0.040147 : sent
    0.040288 : dispatching packet: 
    0.040402 : 19: {0x11, 0x12, 0x10, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x48, 0x42, 0x4, }
    0.045496 : dispatching packet: 
    0.045649 : 1422: {0xa0, 0x12, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x60, 0x1, 0x0, 0x0, 0x2d, 0xb3, 0x84, 0x3b, 0x64, 0xb2, ..., 0x97, 0x33, 0xb6}
    Bus error
    >
    
     
  4. Lovexethru

    Lovexethru New Member

    Any plans to release the x4m200 breathing pattern for Raspberry Pi Module Connector?
     
  5. Christian Rødli Amble

    Christian Rødli Amble New Member Staff Member

    Øystein,

    Thank you for your reports.

    1) That is correct, it should not be enabled for the Raspberry Pi version.
    2) The problem is that Raspberry Pi doesn't like unaligned float access. We fixed this a few places during the porting to Raspberry Pi, but it looks like one or two slipped through the cracks. We'll try to get it fixed and release an update soon.

    Lovexethru,

    The breathing pattern is available on Raspberry Pi. To get it, do x4m200.set_output_control(XTS_ID_RESP_STATUS, XTID_OUTPUT_CONTROL_ENABLE) and read the messages with x4m200.read_message_respiration_legacy. The breathing pattern is available in the movement field.
     
    Øystein Bjørndal likes this.
  6. Lovexethru

    Lovexethru New Member

    Thank you, Christian. I got a step further, thanks to you! Now execution stops at

    while True:
    rdata = x4m200.read_message_respiration_legacy()
    #...stops

    with:

    ** (X4M200_breath.py:14536): WARNING **: Error retrieving accessibility bus address: org.freedesktop.DBus.Error.ServiceUnknown: The name org.a11y.Bus was not provided by any .service files

    I get the same error on the new ...sleep API but it does not stop/freeze there. Any way to debug this further?

    BTW: my above code looks like this

    Code:
    mc = ModuleConnector(device)
    x4m200 = mc.get_x4m200()
    #x4m200.set_led_control(0,0)
    
    #Stop running application and set module in manual mode.
    try:
        x4m200.set_sensor_mode(0x01, 0) #Make sure no profile is running
    except RuntimeError:
        #Profile not running, OK
        pass
    
    #Load x4m200 respiration detection profile
    x4m200.load_profile(XTS_ID_APP_RESPIRATION_2)
    #x4m200.load_profile(XTS_ID_APP_RESP)
    
    Is it XTS_ID_APP_RESP? How can I find out the correct value of that? The 0x1423a2d6 from xtid.h resulted in a profile error. It was 0x1423a2d6.
     
    Last edited: Oct 30, 2017
  7. Christian Rødli Amble

    Christian Rødli Amble New Member Staff Member

    Lovexethru,

    The warning you see is probably GUI-related. ModuleConnector does nothing related to dbus. The attached script seems a bit confused. First, it starts the module at the beginning (sensor mode 1 is run, stop is 0x13). That's not a problem with recent firmware versions, as loading a profile stops it first anyway, but it must be started again for the module to begin sending messages. With no messages being sent from the module, the read_message_* calls will block forever, waiting for incoming data. Second, the respiration legacy message comes from the normal respiration profile. It is not a separate profile, but an output that must be enabled. Third, the various controls (LED, output, noisemap) are profile-specific, meaning they modify a loaded profile. A profile must be loaded first for the setting to properly take effect, or it may modify whatever was already loaded. Failing to properly set the output control of XTS_ID_RESP_STATUS will lead to the above problem with forever hanging read_message_respiration_legacy(), even with a running sensor, as messages of that type are never sent. Find below a minimal example for reading breathing pattern:

    Code:
    import pymoduleconnector
    from pymoduleconnector.ids import *
    
    mc = pymoduleconnector.ModuleConnector(device)
    x4m200 = mc.get_x4m200()
    x4m200.load_profile(XTS_ID_APP_RESPIRATION_2)
    
    # Do other setup, like led control, noisemap control, etc., here, between load
    # profile and sensor mode run.
    x4m200.set_output_control(XTS_ID_RESP_STATUS, XTID_OUTPUT_CONTROL_ENABLE)
    
    x4m200.set_sensor_mode(XTS_SM_RUN, 0)
    while True:
        rdata = x4m200.read_message_respiration_legacy()
        print("State: {}, chest movement: {:.2f} mm".format(rdata.sensor_state, rdata.movement))
    
     
  8. Lovexethru

    Lovexethru New Member

    What is XTS_SUM_RUN? I only find XTID_SM_RUN on the xtid.h but that seemed to work :) Thanks for your help!

    Here's my full code:

    Code:
    zstart = 0.5
    zend = 5.0
    XTS_ID_APP_RESPIRATION_2 = int("0x47fabeba",16)
    XTS_ID_APP_RESP = int("0x1423a2d6",16)
    
    XTS_ID_RESP_STATUS = int("0x2375fe26",16)
    XTS_ID_RESPIRATION_DETECTIONLIST = int("0x064e57ad", 16)
    XTID_SM_RUN = int("0x01",16)
    XTID_SM_MANUAL = int("0x12",16)
    XTID_SM_STOP = int("0x13",16)
    XTID_OUTPUT_CONTROL_ENABLE = int(1)
    FPS = 10
    
    XTS_VAL_RESP_STATE_BREATHING = int("0x00",16)
    XTS_VAL_RESP_STATE_MOVEMENT = int("0x01",16)
    XTS_VAL_RESP_STATE_MOVEMENT_TRACKING = int("0x02",16)
    XTS_VAL_RESP_STATE_NO_MOVEMENT = int("0x03",16)
    XTS_VAL_RESP_STATE_INITIALIZING = int("0x04",16)
    XTS_VAL_RESP_STATE_ERROR = int("0x05",16)
    XTS_VAL_RESP_STATE_UNKNOWN = int("0x06",16)
    
    presence_state_text = []
    presence_state_text.append('BREATHING')
    presence_state_text.append('MOVEMENT')
    presence_state_text.append('MOVEMENT_TRACKING')
    presence_state_text.append('NO_MOVEMENT')
    presence_state_text.append('INITIALIZING ')
    presence_state_text.append('ERROR')
    presence_state_text.append('UNKOWN') 
    
    device = "/dev/ttyACM2"
    mc = ModuleConnector(device)
    x4m200 = mc.get_x4m200()
    x4m200.load_profile(XTS_ID_APP_RESPIRATION_2)
    
    x4m200.set_output_control(XTS_ID_RESP_STATUS, XTID_OUTPUT_CONTROL_ENABLE)
    x4m200.set_sensor_mode(XTID_SM_RUN, 0)
    
    while True:
        #rdata = x4m200.read_message_respiration_sleep()
        rdata = x4m200.read_message_respiration_legacy()
       
        state = rdata.sensor_state
        breath = rdata.movement
        rpm = rdata.respiration_rate
        distance = rdata.distance
       
        print ("Frame: {} sensor_state: {} Breath: {} RPM: {} Distance: {}" .format(
                            rdata.frame_counter,
                            presence_state_text[state],
                            breath,
                            rpm,
                            distance))
        sleep(0.2)
     
    It takes a couple of min until it's initialized. Then mostly stays in movement and movement tracking state or breathing but without any breath (movement) and rpm values. Also the breath (movement) values didn't feel like they listen to my breadth. They appeared for a very short time so it was also hard to tell. Is there any way to make them longer. What do I need to do listen to my breath for as long and as precise as possible?
     
  9. benbair

    benbair New Member

    Hello,

    I am trying to get the X4M03 module working with a raspberry pi 3 (running stretch distro). I am able to install the moduleconnector (v 1.4.2) and python setup completes successfully. When attempting to run xep_example.py I get the following output:

    Code:
    0.000445 : RadarInterface - base -- begin
    0.000881 : log_trace -- begin
    0.000965 : log_trace -- end
    0.001009 : git sha: 51cb921866bb
    0.001047 : build date: 2017-09-15 13:18:58
    0.001082 : subscribe_to_presence_single -- begin
    0.001144 : subscribe_to_presence_single -- end
    0.001183 : subscribe_to_presence_movinglist -- begin
    0.001238 : subscribe_to_presence_movinglist -- end
    0.001277 : subscribe_to_data_float -- begin
    0.001328 : subscribe_to_data_float -- end
    0.001364 : subscribe_to_data_string -- begin
    0.001415 : subscribe_to_data_string -- end
    0.001453 : subscribe_to_data_byte -- begin
    0.001505 : subscribe_to_data_byte -- end
    0.001543 : subscribe_to_baseband_iq -- begin
    0.001595 : subscribe_to_baseband_iq -- end
    0.001631 : subscribe_to_baseband_ap -- begin
    0.001684 : subscribe_to_baseband_ap -- end
    0.001720 : subscribe_to_pulsedoppler_float -- begin
    0.001770 : subscribe_to_pulsedoppler_float -- end
    0.001806 : subscribe_to_noisemap_float -- begin
    0.001858 : subscribe_to_noisemap_float -- end
    0.001895 : subscribe_to_pulsedoppler_byte -- begin
    0.001947 : subscribe_to_pulsedoppler_byte -- end
    0.001983 : subscribe_to_noisemap_byte -- begin
    0.002034 : subscribe_to_noisemap_byte -- end
    0.002070 : subscribe_to_system_status -- begin
    0.002120 : subscribe_to_system_status -- end
    0.002157 : subscribe_to_resp_status -- begin
    0.002207 : subscribe_to_resp_status -- end
    0.002243 : subscribe_to_sleep_status -- begin
    0.002296 : subscribe_to_sleep_status -- end
    0.002332 : subscribe_to_respiration_movinglist -- begin
    0.002385 : subscribe_to_respiration_movinglist -- end
    0.002420 : subscribe_to_respiration_detectionlist -- begin
    0.002472 : subscribe_to_respiration_detectionlist -- end
    0.002508 : open -- begin
    0.002945 : LinuxModuleIo::open /dev/ttyACM0 -- begin
    0.003303 : LinuxModuleIo::open /dev/ttyACM0 -- end
    0.003355 : open -- end
    0.003395 : RadarInterface - base -- end
    0.003433 : subscribe_to_presence_single -- begin
    0.003501 : subscribe_to_presence_single -- end
    0.003540 : subscribe_to_presence_movinglist -- begin
    0.003593 : subscribe_to_presence_movinglist -- end
    0.003751 : subscribe_to_radar_settings -- begin
    0.003814 : subscribe_to_radar_settings -- end
    0.004207 : set_sensor_mode_and_submode -- begin
    0.004289 : sending:
    0.004342 : 5: {0x7d, 0x20, 0x13, 0x4e, 0x7e, }
    0.004419 : sent
    0.004574 : dispatching packet:
    0.004640 : 5: {0x20, 0x1, 0x0, 0x0, 0x0, }
    0.004996 : set_sensor_mode_and_submode -- end
    Traceback (most recent call last):
      File "xep_example.py", line 120, in <module>
        main()
      File "xep_example.py", line 117, in main
        try_xep(options.device_name)
      File "xep_example.py", line 24, in try_xep
        x4m300.set_sensor_mode(XTS_SM_STOP, 0)
      File "/usr/local/lib/python2.7/dist-packages/pymoduleconnector-1.4.2-py2.7.egg/pymoduleconnector/moduleconnectorwrapper/__init__.py", line 6752, in set_sensor_mode
        return _moduleconnectorwrapper.PyX4M300_set_sensor_mode(self, mode, param)
    RuntimeError: set sensor mode failed
    0.021584 : unsubscribe -- begin
    0.021884 : unsubscribe -- end
    0.022298 : ~RadarInterface -- begin
    0.022339 : ~RadarInterface -- end
    0.022378 : ~RadarCommunicator -- begin
    0.035124 : Closing: /dev/ttyACM0
    0.035308 : ~RadarCommunicator -- end
    0.035395 : ~PacketDispatcher -- begin
    0.035524 : ~PacketDispatcher -- end
    
    Any idea what could be causing this issue? I confirmed my X4M03 works on a Windows system, but I really need it to work on the pi as well. The device still has factory firmware.
     
  10. Charlie Shao

    Charlie Shao Moderator Staff Member

    Hi Lovexethru, the X4M200 sensor does have some limitations. Please start from this application not to learn how to use the sensor: https://www.xethru.com/community/resources/x4m200-sleep-monitoring-introduction.110/.
     
  11. Charlie Shao

    Charlie Shao Moderator Staff Member

    Hi Benbair,

    Sorry for confusing, this example are only used for X4M200 and X4M300 sensor information output, since X4M03 is only a development platform, it does not have this kind of information.
    so running the x4m300.set_sensor_mode and xep.get_system_info will cause x4m03 feedback error. Please try XEP_plot_record_playback.py for X4M03 test.
     
  12. Sheng Chong

    Sheng Chong New Member

    Hello,

    I'm facing error when I try to do the linking as in tutorial:

    ping.o: In function `ping(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)':
    ping_x4m300.cpp: (.text+0x60): undefined reference to `XeThru::ModuleConnector::ModuleConnector(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, int)'
    collect2: error: ld returned 1 exit status

    My gcc version is 6.3.0
     
  13. Christian Rødli Amble

    Christian Rødli Amble New Member Staff Member

    Sheng Chong,

    On Raspberry Pi, in order to support GCC 4.9, Module Connector does not use the C++11 ABI. There is currently a bug in the examples that does not take this into account. As mentioned by Øystein earlier in this thread, you need to replace "-D_GLIBCXX_USE_CXX11_ABI" with "-D_GLIBCXX_USE_CXX11_ABI=0".
     
    Charlie Shao likes this.
  14. Sheng Chong

    Sheng Chong New Member

    Does the module connector support Raspbian Stretch? I use Raspberry Pi 3, when I run lsusb I cannot see my device.
    Looks like when I run ping() there is a device file needed, how do I locate the device file when I'm connecting via USB? What will the command look like if I run ping program in terminal? Sorry if the question looks too simple, honestly I'm a beginner of embedded systems. Thanks.
     
    Last edited: Nov 9, 2017
  15. Charlie Shao

    Charlie Shao Moderator Staff Member

    Hi Sheng Chong, you can use "dmseg|grep tty" to check the device name, and run like "./ping /dev/ttyACM0" to test device.
     
  16. Sheng Chong

    Sheng Chong New Member

    I connect X4M300 with Raspberry Pi using UART. When running following code, I keep getting "presence_state: 2" and other parameters are all zero.
    Code:
    #include "ModuleConnector.hpp"
    #include "X4M300.hpp"
    #include "xtid.h"
    #include <iostream>
    
    /** \example presence_single.cpp
     * this is a small ModuleConnector usage example
     */
    
    using namespace XeThru;
    
    
    int handle_error(std::string message)
    {
        std::cerr << "ERROR: " << message << std::endl;
        return 1;
    }
    
    int presence_single(const std::string & device_name)
    {
        const unsigned int log_level = 3;
        ModuleConnector mc(device_name, log_level);
        X4M300 & x4m300 = mc.get_x4m300();
        //set baud rate
        x4m300.set_baudrate(XTID_BAUDRATE_115200);
        //ping the module
        unsigned int pong = 0;
        int status = x4m300.ping(&pong);
        if(status != 0) {
            std::cout << "Something went wrong - error code: " << status << std::endl;
            return status;
        }
        std::cout << "pong: " << std::hex << pong << std::endl;
    
        // ignore status. This might fail and that is ok.
        std::cout << "Stop the module" << std::endl;
        x4m300.set_sensor_mode(XTID_SM_STOP, 0);
    
    
        std::cout << "Load presence profile" << std::endl;
        const unsigned int ProfileID = 0x014d4ab8;
        if (x4m300.load_profile(ProfileID)) {
            return handle_error("load_profile failed");
        }
    
        std::cout << "Turn on presence single packages" << std::endl;
        if (x4m300.set_output_control(XTS_ID_PRESENCE_SINGLE, XTID_OUTPUT_CONTROL_ENABLE)) {
            return handle_error("set output controll failed");
        }
    
        // start the module and profile
        std::cout << "Set the module in RUN state" << std::endl;
        if (x4m300.set_sensor_mode(XTID_SM_RUN, 0)) {
            return handle_error("Set sensor mode to running failed");
        }
    
        std::cout << "Block until first package of presence arrives" << std::endl;
        std::cout << "This may take some time..." << std::endl;
        XeThru::PresenceSingleData presence_single;
       
        for (int i=0; i<100; i++){
            if (x4m300.read_message_presence_single(&presence_single)) {
                return handle_error("set output controll failed");
            }
    
            std::cout << "frame_counter:  " << presence_single.frame_counter << std::endl;
            std::cout << "presence_state: " << presence_single.presence_state << std::endl;
            std::cout << "distance:       " << presence_single.distance << std::endl;
            std::cout << "direction:      " << static_cast<unsigned int>(presence_single.direction) << std::endl;
            std::cout << "signal_quality: " << presence_single.signal_quality << std::endl;
        }
       
        std::cout << "Set the module in IDLE state" << std::endl;
        if (x4m300.set_sensor_mode(XTID_SM_IDLE, 0)) {
            return handle_error("set output controll failed");
        }
    
        return 0;
    }
    
    
    int main()
    {
    
        const std::string device_name = "/dev/ttyS0";
    
        return presence_single(device_name);
    }
    
     
  17. Charlie Shao

    Charlie Shao Moderator Staff Member

    Hi Sheng Chong, sorry for confusing. This is just a very simple example show you the procedure to initialize, read data package and stop X4M300. If you want to see the change of state, you probably need to consecutively read data for a while, probably adding this read and printout functions to a loop. I believe the python examples can show you what you want directly.
     
  18. Sheng Chong

    Sheng Chong New Member

    Thanks, that really helped a lot. Now my X4M300 is working fine through uart. I have another question if you don't mind, I don't know if I'm right, that it seems that when switching the presence state from presence to non-presence, it took quite long time even people are away. Is there anything I could do to avoid this?
     
  19. Charlie Shao

    Charlie Shao Moderator Staff Member

    According to the X4M300 datasheet page15, consecutive 49 seconds of 50 seconds no movement detection will result in presence to no presence switch. This mechanism will make sure the result highly reliable. So I believe you could not avoid this from the sensor presence state output. :)

    But there are some other options you can choose benefit from the XeThru module's comprehensive radar data output support. You can get the raw baseband data, it is powerful but almost useless to the customer without DSP knowledge. It also supports movement list data output, which precisely shows the movement state of every range bin. The first value of movement list is the global average of range bins. I guess it would be helpful if you want to implement your own algorithm for presence state output. But there should be some experiments to be done to test its reliability.
     
    Last edited: Nov 15, 2017 at 8:56 AM