0

I would really appreciate if anyone could give an advice or directions on how to start and stop data logging for accelerometer MPU6050 with a button press. So far I have a script that I start manually through raspberry pi os. So when I test the script it's working and collecting data in the csv file with no problems. The only thing that I need, if I use accelerometer outside for testing, is to start data logging on a button press and to stop data logging when the button is pressed again. The code that I currently use is below.

thank you,

M

"""
Read Gyro and Accelerometer by Interfacing Raspberry Pi with MPU6050 using Python
    http://www.electronicwings.com
"""

import os
import argparse
import datetime
from csv import DictWriter
# SMBus module of I2C
from time import sleep, time

import smbus

# MPU6050 Registers and their Address
DEVICE_ADDRESS = 0x68
# 0 for older version boards
BUS_NO = 1
PWR_MGMT_1 = 0x6B
SMPLRT_DIV = 0x19
CONFIG = 0x1A
GYRO_CONFIG = 0x1B
INT_ENABLE = 0x38
ADDRESS_MAP = {'gx': 0x43, 'gy': 0x45, 'gz': 0x47, 'ax': 0x3B, 'ay': 0x3D, 'az': 0x3F}
VALUE_NORMS = {'gx': 131., 'gy': 131., 'gz': 131., 'ax': 16384., 'ay': 16384., 'az': 16384.}
OUT_DIR = 'output'


def mpu_init():
    # write to sample rate register
    bus.write_byte_data(DEVICE_ADDRESS, SMPLRT_DIV, 7)

    # write to power management register
    bus.write_byte_data(DEVICE_ADDRESS, PWR_MGMT_1, 1)

    # write to Configuration register
    bus.write_byte_data(DEVICE_ADDRESS, CONFIG, 0)

    # write to Gyro configuration register
    bus.write_byte_data(DEVICE_ADDRESS, GYRO_CONFIG, 24)

    # write to interrupt enable register
    bus.write_byte_data(DEVICE_ADDRESS, INT_ENABLE, 1)


def read_raw_data(addr):
    # accelerometer and gyro value are 16-bit
    high = bus.read_byte_data(DEVICE_ADDRESS, addr)
    low = bus.read_byte_data(DEVICE_ADDRESS, addr+1)

    # concatenate higher and lower value
    value = ((high << 8) | low)
    # to get signed value from mpu6050
    if value > 32768:
        value = value - 65536
    return value


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--filename', type=str, help='Name of the file to write data to')
    parser.add_argument(
        '--log', default=list(ADDRESS_MAP.keys()), nargs='+', choices=list(ADDRESS_MAP.keys()),
        help='What parameters you would like to log from the MPU'
    )
    parser.add_argument('--hertz', type=int, default=100, help='Sampling rate from the MPU')
    args = vars(parser.parse_args())

    bus = smbus.SMBus(BUS_NO)
    mpu_init()

    if not os.path.isdir(OUT_DIR):
        os.makedirs(OUT_DIR)

    sleep_time = 1 / args['hertz']
    if args['filename'] is not None:
        output_path = os.path.join(OUT_DIR, f'{args["filename"]}.csv')
    else:
        output_path = os.path.join(OUT_DIR, f'{datetime.datetime.now().strftime("%Y%m%d_%H%M%S")}.csv')
    log_keys = sorted(args['log'])

    print(f'Outputting data to {output_path:s}')
    print(f'Logging at a sampling rate of {args["hertz"]:d} Hz')
    print(f'Logging: {log_keys}')

    start = time()
    with open(output_path, 'w', newline='') as fp:
        csv_writer = DictWriter(fp, delimiter=',', fieldnames=log_keys + ['time(ms)'])
        csv_writer.writeheader()
        while True:
            csv_writer.writerow({
                **{key: f'{read_raw_data(ADDRESS_MAP[key]) / VALUE_NORMS[key]:.3f}' for key in log_keys},
                **{'time(ms)': f'{(time() - start) * 1000:.1f}'}
            })
            sleep(sleep_time)
8
  • 1
    Hi @Maksym Kepskyy, Welcome and nice to meet you. Ah, let me see. Can I "simplify" your specific question to a bit generic, like this? Suppose I have a "printing" program that repeatedly prints "Hello World" every second. Now I want to have another "master" "button" program which reads a button and starts or stops a "slave" program, perhaps the printing program. Now say, if I press button once, the printing starts, and if I press button again, printing stops. If you think my simplified, generic question solves your complicated, "accelero + csv" question, I can try to answer. Cheers.
    – tlfong01
    May 12 '20 at 4:24
  • 2
    This seems to be a general programming question, i.e. not specific to the Pi.
    – joan
    May 12 '20 at 7:59
  • 1
    Thanks for replying @tlfong01. Yes, if you could write your answer, it would be great. I am new to it and look into any answer as a resource I can learn from. May 13 '20 at 4:40
  • Hi @Maksym Kepskyy, thank you for your confirmation and invitation. So I am going to write a newbie friendly answer which can also be used as a learning resource. I would try to write my answer (1) "as simple as possible", at the same time (2) "live", (3) "flexible", and (4) "complete".
    – tlfong01
    May 13 '20 at 5:32
  • A note on "flexibility": You question asks for "Advice and Direction" on the specific task of how to write a button program to control another accelerometer datalogging program. Though my answer is also on a specific case of Rpi button and printing, but the problem solving, programming knowledge and skills used should be flexible enough to apply to many more Rpi "control" applications. In a way, I am using "Problem Based Learning" and "Case Study Research " approaches at the same time.
    – tlfong01
    May 13 '20 at 6:03
1

You may need a few changes first.

Run a groups command on the Pi and make sure your current user (most likely: pi) is a part of gpio group. If you're not, run the following: usermod -a -G gpio pi (the general syntax: usermod -a -G <group> <user>, command is *nix specific, not just Pi, read more here: https://www.raspberrypi.org/forums/viewtopic.php?t=74453)

When you add the user, check again with groups command and if all looks hunky-dory, reboot the Pi: sudo reboot now (required for the group changes to take effect; logout-login may be enough, but I reboot)

Then you'll need to read a digital input. Here is some sample python code:

#!/usr/bin/python

from gpiozero import Button
import json

# class gpiozero.Button(pin, *, pull_up=True, active_state=None, bounce_time=None, 
hold_time=1, hold_repeat=False, pin_factor$
pin16 = Button(23, False)
pin18 = Button(24, False)

my_data = {"pin16":1 if pin16.is_pressed else 0, "pin18":1 if pin18.is_pressed else 0}

print(json.dumps(my_data))

In my case, the script prints a JSON object like: {"pin16": 1, "pin18": 0}; you may not need JSON, but I hope it is clear in the code how JSON is generated, change at will.

In order to wire a button, here is one of many tutorials https://raspberrypihq.com/use-a-push-button-with-raspberry-pi-gpio/

Just make sure that you DO NOT connect a GPIO pin to a 5V source, make sure it is 3.3V, otherwise you will damage that pin or possibly the whole board. You've been warned :)

Look up the Pi docs for reading GPIO. The class is called Button (which conveniently matches with what you need, but in my case, it is actually a generic digital input, not a button...). Also note that my sample code is for Pi Zero, depending on which Pi you use, this may be a tad bit different (but the overall idea should still be the same).

Once that's understood, you'll need to create a script (or a compiled binary) that runs in the background and monitors an input for status change, you can look up how to create a background process in Linux. For all you care, it could be a python script in the startup, just make sure to run it with & at the end (i.e. python /path/to/monitor_button.py&). That puts the command in background and moves on with the script that launched it (check if it's running with jobs command).

1
  • 1
    Thanks for detailed explanation. I tried to play around with the button events so i start to get an idea of needed steps. Next thing is to look up how create a background process in Linux. May 13 '20 at 4:21
1

Question

The OP already has a working python program which logs the readings of an accelerometer MPU6050 and write to a CSV file.

Now he wishes to have advice and direction on how to write another python program which reads a button and starts and stops the above accelero data logging program.


Answer

Short Answer

I read the OP's data logging program and found it well structured and documented. A quick and short answer would be something like below.

(1) Google a simple, newbie friendly Rpi python button reading program.

(2) Modify the button program to do the following:

(a) import the data logging program as a module,

(b) add a loop to detect button presses and starts and stops the imported data logging program.
  1. There are minor modification/editing needed to make the original program "importable", "startable" and "stoppable", as will be explained in detail later, in the long answer below. I will also briefly describe the minor editing here, after I have completed the long answer.

Long answer

(1) I read the OP's original accelerometer and data logging program which includes too many tedious details which are irrelevant to the main trick suggested here to control one program by another program. Therefore I am simplifying the OP's situation and requirement to a simple "read button" and "write Hello World" program. In other words, the very short Hello World program will replace/simulate the OP's big program in this demonstrative answer.

(2) One subtle but critical python trick/idiom "if name == “main” might confuse the OP and most python newbies. I think all newbies need to know this trick well, before they can develop even slightly more complex program beyond simple Blink LED and Read Button programs.

I will start writing the Hello World program, which I said earlier, is a minimal version of the OP' big program.

Update 2020may14hgkt1900

(4) Now I have written a python program to do the following:

(a) Define only two functions:

(i) Greeting(...) repeatedly saying Hello World,

(2) SendCommandList(...) repeatedly send commands to a 'queue'

(b) Setup the greeting function as a concurrent/multiprocess process, running in the background.

(c) Setup a 'Queue' which is used to communicate between the Greeting( ) process and the SendCommandList() function/process.

(5) Start the Greeting process (called amyProcess),which starts repeatedly saying Hello World in the background, until she received the command to stop.

(6) Run the SendCommandList() as a process in the foreground. Now the background and the foreground processes are running in parallel.

(7) The SendCommandList() process sends commands to the Queue (called amyQueue) 'Non Stop', 'Non Stop' ... and finally 'Stop Process 0'. Concurrently the Greeting process gets the messages from the queue when saying Hello World. When the 'Stop Process 0' comes, Greeting process stops.

The Minimal, Complete, Verifiable, Example (MCVE) is only 40 lines of python, as fully listed in Appendix H below, to gether with a sample output. The Thonny IDE screen capture is also pasted in the same Appendix.

The demo program can just copy, paste and run in Thonny. So even newbies without any knowledge can try it, to get a taste of python concurrent/parallel/multiprocessing/ programming.


/ to continue, ...


References

(1) Python multiprocessing

(2) What does if __name__ == '__main__' do? - StackOverflow

(3) How to create a Minimal, Reproducible Example - StackOverflow Help Center

(4) Rpi Essentials - GPIO Zero [LED/Button] Electronics - MagPi Free eBook

(5) Multiprocessing in Python | Set 1 (Introduction) - GeeksForGeeks

(6) Multiprocessing in Python | Set 2 (Communication between processes) - GeeksForGeeks

(7) GpioZero 1.5.1 Documentation

(8) GpioZero Source/Values (Led/Button, Declarative Programming, Background Thread Example - Warning: not for newbies)

/ to continue, ...


Appendices

Contents

A - The OP's Original accelerometer datalogging program listing

B - First Simplification

C - Second Simplification

*D - What does if _name_ == '_main_' do?*

E - Multiprocessing Program

F - How to create a Minimal, Complete, Reproducible/Verifiable Example (MCVE)

G - MagPi Rpi gpioZero Blink LED and Read Button Free eBook

H - Twp concurrent processes demo program

I - Three concurrent process demo program


Appendix A - Original Accelerometer Data Logging Program

"""
Read Gyro and Accelerometer by Interfacing Raspberry Pi with MPU6050 using Python
    http://www.electronicwings.com
"""

import os
import argparse
import datetime
from csv import DictWriter
# SMBus module of I2C
from time import sleep, time

import smbus

# MPU6050 Registers and their Address
DEVICE_ADDRESS = 0x68
# 0 for older version boards
BUS_NO = 1
PWR_MGMT_1 = 0x6B
SMPLRT_DIV = 0x19
CONFIG = 0x1A
GYRO_CONFIG = 0x1B
INT_ENABLE = 0x38
ADDRESS_MAP = {'gx': 0x43, 'gy': 0x45, 'gz': 0x47, 'ax': 0x3B, 'ay': 0x3D, 'az': 0x3F}
VALUE_NORMS = {'gx': 131., 'gy': 131., 'gz': 131., 'ax': 16384., 'ay': 16384., 'az': 16384.}
OUT_DIR = 'output'


def mpu_init():
    # write to sample rate register
    bus.write_byte_data(DEVICE_ADDRESS, SMPLRT_DIV, 7)

    # write to power management register
    bus.write_byte_data(DEVICE_ADDRESS, PWR_MGMT_1, 1)

    # write to Configuration register
    bus.write_byte_data(DEVICE_ADDRESS, CONFIG, 0)

    # write to Gyro configuration register
    bus.write_byte_data(DEVICE_ADDRESS, GYRO_CONFIG, 24)

    # write to interrupt enable register
    bus.write_byte_data(DEVICE_ADDRESS, INT_ENABLE, 1)


def read_raw_data(addr):
    # accelerometer and gyro value are 16-bit
    high = bus.read_byte_data(DEVICE_ADDRESS, addr)
    low = bus.read_byte_data(DEVICE_ADDRESS, addr+1)

    # concatenate higher and lower value
    value = ((high << 8) | low)
    # to get signed value from mpu6050
    if value > 32768:
        value = value - 65536
    return value


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--filename', type=str, help='Name of the file to write data to')
    parser.add_argument(
        '--log', default=list(ADDRESS_MAP.keys()), nargs='+', choices=list(ADDRESS_MAP.keys()),
        help='What parameters you would like to log from the MPU'
    )
    parser.add_argument('--hertz', type=int, default=100, help='Sampling rate from the MPU')
    args = vars(parser.parse_args())

    bus = smbus.SMBus(BUS_NO)
    mpu_init()

    if not os.path.isdir(OUT_DIR):
        os.makedirs(OUT_DIR)

    sleep_time = 1 / args['hertz']
    if args['filename'] is not None:
        output_path = os.path.join(OUT_DIR, f'{args["filename"]}.csv')
    else:
        output_path = os.path.join(OUT_DIR, f'{datetime.datetime.now().strftime("%Y%m%d_%H%M%S")}.csv')
    log_keys = sorted(args['log'])

    print(f'Outputting data to {output_path:s}')
    print(f'Logging at a sampling rate of {args["hertz"]:d} Hz')
    print(f'Logging: {log_keys}')

    start = time()
    with open(output_path, 'w', newline='') as fp:
        csv_writer = DictWriter(fp, delimiter=',', fieldnames=log_keys + ['time(ms)'])
        csv_writer.writeheader()
        while True:
            csv_writer.writerow({
                **{key: f'{read_raw_data(ADDRESS_MAP[key]) / VALUE_NORMS[key]:.3f}' for key in log_keys},
                **{'time(ms)': f'{(time() - start) * 1000:.1f}'}
            })
            sleep(sleep_time)

# End of Program

Appendix B - First Simplification of Original Program

# *** Abstraction/Simplification/Pseudo Code of Original Accelero Datalogging Program V0.1  tlfon01 2020may13hkt1418

import os
import argparse
import datetime
from   csv import DictWriter
from   time import sleep, time
import smbus

# MPU6050 Registers and their Address
DEVICE_ADDRESS = 0x68; BUS_NO = 1; PWR_MGMT_1 = 0x6B; SMPLRT_DIV = 0x19; CONFIG = 0x1A; ... 

def mpu_init():
    # write to sample rate register
    # write to power management register
    # write to Configuration register
    # write to Gyro configuration register
    # write to interrupt enable register
    return

def read_raw_data(addr):
    # accelerometer and gyro value are 16-bit
    # concatenate higher and lower value
    # to get signed value from mpu6050
    return value

if __name__ == '__main__':

    # (1) *** Config parser ***
    parser = argparse.ArgumentParser()
    parser.add_argument(...)
    parser.add_argument(...)
    parser.add_argument(...)
    args = vars(parser.parse_args())
    bus = smbus.SMBus(BUS_NO)

    # (2) *** Initialize MPU ***
    mpu_init()

    # (3) *** Setup directory and datalogging file ***
    if not os.path.isdir(OUT_DIR): os.makedirs(OUT_DIR)
    sleep_time = ...
    if args['filename'] is not None:
        ...
    else:
        ...

    # (4) *** Print Logging Info
    print(f'Outputting data to {output_path:s}')
    print(f'Logging at a sampling rate of {args["hertz"]:d} Hz')
    print(f'Logging: {log_keys}')


    # (5) *** Start Logging ***
    start = time()
    with open(output_path, 'w', newline='') as fp:
        csv_writer = ...
        csv_writer.writeheader()

        while True:
            csv_writer.writerow(...)
            sleep(sleep_time)
# End of Program

Appendix C - Second Simplification of original program

# *** Abstraction/Simplification/Pseudo Code of Original Accelero Datalogging Program V0.2  tlfon01 2020may13hkt1510

import os
import argparse
import datetime
from   csv import DictWriter
from   time import sleep, time
import smbus

# MPU6050 Registers and their Address
DEVICE_ADDRESS = 0x68; BUS_NO = 1; PWR_MGMT_1 = 0x6B; SMPLRT_DIV = 0x19; CONFIG = 0x1A; ... 

def mpu_init():
    # write to sample rate, power management, config, Gyro config, interrupt register, ... 
    return

def read_raw_data(addr):
    # concatenate higher and lower value to get signed value from mpu6050,
    ...
    return value

if __name__ == '__main__':

    # (1) *** Config parser ***
    ...

    # (2) *** Initialize MPU ***
    mpu_init()

    # (3) *** Setup directory and datalogging file ***
    ...

    # (4) *** Print Logging Info
    print(f'Outputting data to {output_path:s}')
    ...

    # (5) *** Start Logging ***
    with open(.. ) as fp:
        csv_writer.writeheader()
        while True:
            csv_writer.writerow(...)
            sleep(sleep_time)

# End of Program    

Appendix D - [Why] What does if name == 'main' do?

[Why] What does if name == 'main': do? - StackOverflow, asked 11 years ago, 33 Answers,Viewed 2.9m times

...

Why Does It Work This Way?

You might naturally wonder why anybody would want this. Well, sometimes

you want to write a .py file that can be both used by other programs and/or modules as a module, and can also be run as the main program itself.

Examples:

Your module is a library, but you want to have a script mode where it runs some unit tests or a demo.

Your module is only used as a main program, but it has some unit tests, and the testing framework works by importing .py files like your script and running special test functions.

You don't want it to try running the script just because it's importing the module.

Your module is mostly used as a main program, but it also

provides a programmer-friendly API for advanced users.


Appendix E - Python Multiprocessing Demo Program V0.1

This little program demonstrats how to setup a concurrent process (repeatedly saying hello Word), along side a front end looping function repeatedly printing something, concurrently.

The front end repeatedly printing something function is to be later changed to a function to ask the use to hit the 't 'key of the keyboard. This simulates the user pressing a button, toggling the start and stop of the accelerometer data logging program

# helloworld03.py tlfong01 2020may13hkt1949
# Rpi4B buster (r2020feb13), linux 4.19.97
# python 3.7.3 (r2019dec20) thonny v3.2.7 (r2020jan22)

from time            import sleep
from datetime        import  datetime
from multiprocessing import Process

def askUser(question, totalCount, pauseSecond):
    for count in range(totalCount):
        #reply = input('                                      count, Continue (y/n <enter>)? ' )
        reply = 'ask user'
        print(str(datetime.now())[0:19], '                            ', str(count).rjust(4, ' '), '     ', reply)
        sleep(pauseSecond)
    return    

def helloWorld(name, totalCount, pauseTime):
    for count in range(totalCount):
        print(str(datetime.now())[0:19], str(count).rjust(4, ' '), '    Hello World', name)
        sleep(pauseTime)
    return

if __name__ == '__main__':

    print('-------------------------------------------------------------------------')  
    print('                             Process 1                      Main loop')
    print('-------------------------------------------------------------------------')    
    amy     = Process(target = helloWorld, args = ('Amy', 16, 0.1)) # Say Hello World to Amy 16 times, pause 0.25 second each time
    amy.start() 
    askUser('Continue (y/n <enter>)? ', 6, 0.5)                     # Ask user 6 times, pause 0.5 second each time


# *** End of program ***

'''
# *** Sample Output ***

>>> %Run helloworld02.py
-------------------------------------------------------------------------
                             Process 1                      Main loop
-------------------------------------------------------------------------
2020-05-13 19:47:41                                 0       ask user
2020-05-13 19:47:41    0     Hello World Amy
2020-05-13 19:47:41    1     Hello World Amy
2020-05-13 19:47:41    2     Hello World Amy
2020-05-13 19:47:41    3     Hello World Amy
2020-05-13 19:47:41    4     Hello World Amy
2020-05-13 19:47:41                                 1       ask user
2020-05-13 19:47:41    5     Hello World Amy
2020-05-13 19:47:41    6     Hello World Amy
2020-05-13 19:47:41    7     Hello World Amy
2020-05-13 19:47:42    8     Hello World Amy
2020-05-13 19:47:42    9     Hello World Amy
2020-05-13 19:47:42                                 2       ask user
2020-05-13 19:47:42   10     Hello World Amy
2020-05-13 19:47:42   11     Hello World Amy
2020-05-13 19:47:42   12     Hello World Amy
2020-05-13 19:47:42   13     Hello World Amy
2020-05-13 19:47:42   14     Hello World Amy
2020-05-13 19:47:42                                 3       ask user
2020-05-13 19:47:42   15     Hello World Amy
2020-05-13 19:47:43                                 4       ask user
2020-05-13 19:47:43                                 5       ask user
>>>
''' 

Appendix F - How to create a Minimal, Reproducible Example

How to create a Minimal, Reproducible Example - StackOverflow Help Center

When asking a question, people will be better able to provide help if you provide code that they can easily understand and use to reproduce the problem. This is referred to by community members as creating a minimal, reproducible example (reprex), a minimal, complete and verifiable example (mcve), or a minimal, workable example (mwe). Regardless of how it's communicated to you, it boils down to ensuring your code that reproduces the problem follows the following guidelines:

Your code examples should be…

(1) Minimal – Use as little code as possible that still produces the same problem

(2) Complete – Provide all parts someone else needs to reproduce your problem in the question itself

(3) Reproducible – Test the code you're about to provide to make sure it reproduces the problem

The rest of this help article provides guidance on these aspects of writing a minimal, reproducible example.

Minimal

The more code there is to go through, the less likely people can find your problem. Streamline your example in one of two ways:

Restart from scratch. Create a new program, adding in only what is needed to see the problem. Use simple, descriptive names for functions and variables – don’t copy the names you’re using in your existing code.

Divide and conquer. If you’re not sure what the source of the problem is, start removing code a bit at a time until the problem disappears – then add the last part back.

Minimal and readable

Don't sacrifice clarity for brevity when creating a minimal example. Use consistent naming and indentation, and include code comments if needed. Use your code editor’s shortcut for formatting code. Also, use spaces instead of tabs – tabs might not get correctly formatted on Stack Overflow.

Complete

Make sure all information necessary to reproduce the problem is included in the question itself:

If the problem requires some server-side code as well as some XML-based configuration, include code for both. If a web page problem requires HTML, some JavaScript, and a stylesheet, include code for all three. The problem might not be in the code that you think it is in.

Use individual code blocks for each file or snippet you include. Provide a description for the purpose of each block.

Use Stack Snippets to include runnable HTML, JavaScript, or CSS.

DO NOT use images of code. Copy the actual text from your code editor, paste it into the question, then format it as code. This helps others more easily read and test your code.

Reproducible

To help you solve your problem, others will need to verify that it exists:

Describe the problem. "It doesn't work" isn't descriptive enough to help people understand your problem. Instead, tell other readers what the expected behavior should be. Tell other readers what the exact wording of the error message is, and which line of code is producing it. Use a brief but descriptive summary of your problem as the title of your question.

Eliminate any issues that aren't relevant to the problem. If your question isn’t about a compiler error, ensure that there are no compile-time errors. Use a program such as JSLint to validate interpreted languages. Validate any HTML or XML.

Double-check that your example reproduces the problem! If you inadvertently fixed the problem while composing the example but didn't test it again, you'd want to know that before asking someone else to help.

It might help to shut the system down and restart it, or transport the example to a fresh environment to confirm it really does provide an example of the problem.


Appendix G - GpioZero Blink LED Read Button Tutorial

Rpi Essentials - GPIO Zero Electronics - MagPi Free eBook

Chapter 1 - Get started with GPIO Zero

Chapter 2 - Blink a LED

Chapter 3 - Read a push button


Appendix H - Multiprocessing Demo Program V1.0

mp06 1

mp06 2

# multiproc06.py tlfong01 2020may14hkt1652, # Rpi4B buster (r2020feb13)
# python 3.7.3 (r2019dec20) thonny v3.2.7 (r2020jan22)

from time            import sleep
from datetime        import datetime
from multiprocessing import Process, Queue

controlByteDict = { '0.5 second': 0.5, '1 second': 1, '10 times': 10, 'Process 0' :  0, 'Process 1' :  1, 'Process 8' :  8, 
                    'Stop Process 0' : 0, 'Non Stop' :  9, }    

def greeting(processNum, queue, greeting, name, totalCount, pauseTime):
    for count in range(controlByteDict[totalCount]):
        stopProcessCommand = queue.get()
        stopProcessNum = controlByteDict[stopProcessCommand]
        print(str(datetime.now())[0:19], (' ' * 30 * controlByteDict[processNum]), str(count).rjust(4, ' '), '    ', 'Command =', stopProcessCommand)
        if stopProcessNum == controlByteDict[processNum]:
                print(str(datetime.now())[0:19], (' ' * 30 * controlByteDict[processNum]), str(count).rjust(4, ' '), '    ', 'Process stopped')
                break
        sleep(controlByteDict[pauseTime])
        print(str(datetime.now())[0:19], (' ' * 30 * controlByteDict[processNum]), str(count).rjust(4, ' '), '    ', greeting, name)
    print(str(datetime.now())[0:19], (' ' * 30 * controlByteDict[processNum]), str(count).rjust(4, ' '), '    ', 'Process ends')
    return

def sendCommandList(processNum, queue, commandList, pauseTime):
    count = 0
    for command in commandList:
        print(str(datetime.now())[0:19], (' ' * 30 * controlByteDict[processNum]), str(count).rjust(4, ' '), command)        
        queue.put(command)
        count = count + 1
    return

if __name__ == '__main__':    
    queueAmy = Queue()    
    processAmy = Process(target = greeting, args = ('Process 0', queueAmy, 'Hello World,', 'Amy', '10 times', '0.5 second'))
    processAmy.start()    
    sendCommandList('Process 8', queueAmy, ['Non Stop', 'Non Stop', 'Non Stop', 'Non Stop', 'Stop Process 0',], '1 second')

# *** End of program ***

'''
# *** Sample Output ***

%Run multiproc06.py
...                                                                                                                                                                                                                                                    3 Non Stop
                                                                                                                                                                                                                                                   4 Stop Process 0
>>>
2020-05-14 18:09:21     0      Hello World, Amy
2020-05-14 18:09:21     1      Command = Non Stop
2020-05-14 18:09:22     1      Hello World, Amy
2020-05-14 18:09:22     2      Command = Non Stop
2020-05-14 18:09:22     2      Hello World, Amy
2020-05-14 18:09:22     3      Command = Non Stop
2020-05-14 18:09:23     3      Hello World, Amy
2020-05-14 18:09:23     4      Command = Stop Process 0
2020-05-14 18:09:23     4      Process stopped
2020-05-14 18:09:23     4      Process ends

'''

Appendix I - Three Concurrent Processes, two slave (Hello World, Accelero Data Log), one master (Command to start/stop slave processes) Draft V0.1

# multiproc08.py tlfong01 2020may15hkt1534
# Rpi4B buster (r2020feb13), python 3.7.3 (r2019dec20), thonny v3.2.7 (r2020jan22)

# ** Imports ***

from time            import sleep
from datetime        import datetime
from multiprocessing import Process, Queue, Value, Array

# *** Control Byte Dictionaries ***

controlByteDict = { '0.25 second': 0.25, '0.3 second': 0.3, '0.5 second': 0.5, '1 second': 1, '1.1 second': 1.1,
                    '4 times': 4, '5 times': 5, '8 times': 8, '10 times': 10,
                    'Process 0' :  0, 'Process 1' :  1, 'Process 2' :  2, 
                    'Stop Process 0' : 0, 'Non Stop' :  9, }    

# *** Hello World Function ***

def printColumnNames():
    print('----------------------------------------------------------------------------------------------------------------')
    print('Date/Time                      Process 0                     Process 1                     Process 2')
    print('                               Hello Amy                     Welcome Betty                 Command Start/Stop')
    print('----------------------------------------------------------------------------------------------------------------')
    return

def greeting(processNum, sharedInteger, sharedIntegerArray, greetMsg, greetPerson, totalCount, pauseTime):
    for count in range(controlByteDict[totalCount]):
        sleep(controlByteDict[pauseTime])
        print(str(datetime.now())[0:19], (' ' * 30 * controlByteDict[processNum]), str(count).rjust(4, ' '), '    ', greetMsg, greetPerson)
    print(str(datetime.now())[0:19], (' ' * 30 * controlByteDict[processNum]), str(count).rjust(4, ' '), '    ', 'Process stops')
    print(str(datetime.now())[0:19], (' ' * 30 * controlByteDict[processNum]), str(count).rjust(4, ' '), '    ', 'Process ends')
    return

def command(processNum, sharedInteger, sharedIntegerArray, commandMsg, commandName, totalCount, pauseTime):
    for count in range(controlByteDict[totalCount]):
        sleep(controlByteDict[pauseTime])
        print(str(datetime.now())[0:19], (' ' * 30 * controlByteDict[processNum]), str(count).rjust(4, ' '), '    ', commandMsg, commandName)
    print(str(datetime.now())[0:19], (' ' * 30 * controlByteDict[processNum]), str(count).rjust(4, ' '), '    ', 'Process stops')
    print(str(datetime.now())[0:19], (' ' * 30 * controlByteDict[processNum]), str(count).rjust(4, ' '), '    ', 'Process ends')
    return

if __name__ == '__main__':    
    print('multiproc08.py tlfong01 2020may15hkt1534\n')
    printColumnNames()

    queueAmy = Queue()

    intAmy      = Value('i')
    intArrayAmy = Array('i', 8)
    intAll      = Value('i')
    intArrayAll = Array('i', 8)

    processAmy     = Process(target = greeting, args = ('Process 0', intAmy, intArrayAmy, 'Hello World,', 'Amy', '5 times', '0.5 second'))
    processBetty   = Process(target = greeting, args = ('Process 1', intAll, intArrayAll, 'Welcome World,', 'Betty', '8 times', '0.3 second'))
    processCommand = Process(target = greeting, args = ('Process 2', intAll, intArrayAll, 'Non Stop,', 'Master', '4 times', '1.1 second'))

    processAmy.start()
    processBetty.start()
    processCommand.start()

    processAmy.join()
    processBetty.join()
    processCommand.join()

# *** End of program ***

'''
# *** Sample Output  2020may15hkt1627 ***

>>> %Run multiproc07.py
multiproc08.py tlfong01 2020may15hkt1534

----------------------------------------------------------------------------------------------------------------
Date/Time                      Process 0                     Process 1                     Process 2
                               Hello Amy                     Welcome Betty                 Command Start/Stop
----------------------------------------------------------------------------------------------------------------
2020-05-15 16:32:18                                   0      Welcome World, Betty
2020-05-15 16:32:18     0      Hello World, Amy
2020-05-15 16:32:18                                   1      Welcome 
>>> 
# *** End of Sample Output ***
'''

Note: This answer is hitting the StackExchange's 30,000 words limit. So I need to shorten some sections.


End of answer


12
  • 1
    Thank you @tlfong01. Quite a bit of information to process but useful. Let me play around a bit and will get back with more questions. May 14 '20 at 2:18
  • Hi @Maksym Kepskyy, You are welcome. No hurry at all. I am just experimenting things, and do not have a clear direction. You might like to sit back and watch for now
    – tlfong01
    May 14 '20 at 5:10
  • 1
    Thanks again for helping out! May 15 '20 at 22:08
  • 1
    I modified and also simplified a couple of things: I added a power button that turns on and off Pi: howchoo.com/g/mwnlytk3zmm/… and then added a crone command to run the script on start up: @reboot python3 /home/pi/my_script.py May 15 '20 at 22:30
  • 1
    For now I have: Pi starts on button press. When the device is awake, the script for accelerometer starts running automatically and logs the data while the devise on On. When I press the button again, the device shuts down and safes the file with logged data. My next step then is to add another button that will do an interrupt: stops the script and start again if needed and so on. May 15 '20 at 22:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.