Skip navigation
2015

This week I was able to get the DF1 protocol operational. It is not a compete implementation of the protocol, but it implements read and write operations for data transfer to/from a SLC 500 processor.


RS-232 communication

As mentioned in a previous post I am using a USB to RS232(Product LinkProduct Link) cable to be able to communicate to a SLC 500 PLC. The data sheet can be found here http://www.farnell.com/datasheets/814051.pdf. I had to make up a 9 pin (DB9) Female connector to connect to the PLC.

 

The cable pin out can be seen below:

rs232_pinout


The TXD on the cable is connected to the RXD (pin 2) on the SLC and the RXD on the cable is connected to the TXD (pin 3) on the SLC. The GND on the cable is connected to the GND (pin 5) on the SLC. Once connected it works very well. The USB side of the cable has 2 LED's - a red for transmit and a green for receive. So it is very easy to see when signal transmission is happening. I have been very pleased with the performance of the cable.

 

 

DF1 Protocol

I am communicating to an Allen Bradley SLC500 PLC using the DF1 protocol over a  RS-232RS-232 serial connection The protocol can be found in the DF1 Protocol and Command Set Reference Manual http://literature.rockwellautomation.com/idc/groups/literature/documents/rm/1770-rm516_-en-p.pdf). I have found this to not be a complete description of all of the commands.

 

A typical command looks like this:

 

df1_packet

 

 

The protocol uses variable length packets that, with the exception of a couple of commands, start with standard header information of DEST, SRC, CMD, STS, and TNS. SRC and DEST are self explanatory, identifying the address of the device sending the command and the address of the device the message is being sent to. The DF1 protocol has many different CMD’s, but the ones I have programmed are in the ‘0F’ family – Protected Read and Write. The STS is an error code – really only intended for response packets, so set to 0 for commands. The TNS is a unique identifier for each message. The way I have implemented the protocol is to start with TNS of 1 and increment until it reaches 0xFFFF and then start over again.

 

Application specific data includes the protocol function. For reads and writes, the ADDR field is used to identify the data register to read/write to (e.g. N7:30) The SIZE byte specifies how many bytes to read/write. The DATA field is used when writing data to a register(s) and includes the data to be written.

 

The DATA field is delineated along word boundaries (16 bits/2 bytes). The Data must be encoded in ‘Little Endian’ format, where the low byte  resides in bits 8-15 and the high byte resides in bits 0-7. The Raspberry Pi stores data in ‘Big Endian’ format where the high byte resides in bits 8-15 and the low byte resides in bits 0-7. This requires some manipulation of the DATA bytes before sending.

 

The struct module, which allows strings to be interpreted as packed binary data, offers a simple way to do this.

struct.pack('<h', self.Data)















 

where ‘<’ represents encoding in Little Endian format and the ‘h’ represents a signed integer (16 bits)


Response Packet

The handshaking that goes on requires the PLC to 'ACK'nowledge that it has received the command and a short while later it will send the response message. The response message looks very similar to the command message:

response_packet

 

The SRC and DEST bytes are reversed in the response packet - because the PC is now the source and the Pi is the destination. The STS byte will be 0 unless there is an error and then it will hold the error byte. The TNS word will match to the TNS of the command packet. Read commands will have a response with the data requested. Again this data is encoded in Little Endian format.

 

After the message has been successfully received by the Pi, the Pi needs to 'ACK'nowledge the response. This completes the message transfer process.

 

Strings

ST file types took me a little while to figure out. When you read a ST file type, the data returned is 82 bytes, regardless of the length of the actual string. If the string is less than 82 bytes, the string is padded with \x00’s. What took me a while to figure out was that the string data is returned in Little Endian format (every 2 characters are swapped). So if you had a string ‘HELLO WORLD’ it would come across as ‘EHLL OOWLR D’. Once I figured this out, I was able to write code to account for this. It turns out that the first 2 bytes have the length of the string (in Little Endian format of course), so this can be used to eliminate the \x00’s.

 

I imagine that other non purely numeric files (BCD, MSG, PD) are similar, but I have not tested these yet.

 

Code

The code for this portion of the project will be posted at  https://github.com/frellwan/SciFy-Pi.git in the Serial/df1 folder.

 

As with the RS422 communications, I have borrowed heavily from the pymodbus code. This package is well proven and seemed like a good starting point. The serialport instantiating is very simple:

 

options = utilities.Options()
config = SafeConfigParser()
config.read([options['config']])

reader  = LoggingLineWriter(config.get('FTP', 'localLogDir'))

# Create the FTP client
FTPhost = config.get('FTP', 'host')
FTPport = config.getint('FTP', 'port')
ftpEndpoint = TCP4ClientEndpoint(reactor, FTPhost, FTPport)


factory = DF1Factory(reader, ftpEndpoint)
RS232port = config.get('RS-232', 'host')
RS232baud = config.getint('RS-232', 'baudrate')

SerialDF1Client(factory, RS232port, reactor, baudrate = RS232baud)

serialLog.debug("Starting the client")

reactor.run()






 

 

 

At this point the DF1Protocol is now responsible for encoding and sending the packets to the PLC. While I have coded both the encode and decode methods, I am only showing the encode method here. This is the only method I will be using. The decode would be for the case that the PLC was sending a command request to the Pi - I suppose if you needed the Pi to emulate a PLC or to act as a bridge between multiple PLC's.

 

class protectedReadRequest(PDU):
    '''
    Base class for reading a PLC register
    '''
    _frame_size = 18
    cmd = 0x0F
    function = 0xA2

    def __init__(self, dest, parameter, size=1, packet='', src=0, **kwargs):
        ''' Initializes a new instance

        :param address: The destination PLC address
        :param parameter: The PLC address to read
        :param size: The number of elements to read
        :param packet: Used when we already have an encoded packet
        '''
        PDU.__init__(self, **kwargs)
        self.src = src
        self.dest = dest
        self.parameter = parameter
        self.sts = 0x00
        self.size = size
        self.Address = utilities.calcAddress(parameter)
        self.packet = packet
    
    def encode(self):
        ''' Encodes the request packet

        :return: The encoded packet
        '''
        if (not self.skip_encode):
            ############################
            # Packet Start Sequence
            ############################
            self.packet = struct.pack('>BB', 0x10, 0x02)        #DLE STX

            ############################
            # Packet Header Information
            ############################
            data = struct.pack('>BBBBHB', self.dest,
                                          self.src,
                                          self.cmd,
                                          self.sts,
                                          self.transaction_id,
                                          self.function)
            if (self.Address.subElement > 0):
                elementSize = SUBELEMENT_SIZE[self.Address.fileType]*self.size
            else:
                elementSize = ELEMENT_SIZE[self.Address.fileType]*self.size
            
            data += struct.pack('>B', elementSize)

            ###################################################
            # Packet Address Information
            # Note: Use Little Endian format if using 2 bytes
            ###################################################
            if (self.Address.fileNumber > 254):
                data += struct.pack('>B', 0xFF)
                data += struct.pack('<H', self.Address.fileNumber)

            else:
                data += struct.pack('>B', self.Address.fileNumber)

            data += struct.pack('>B', self.Address.fileType)

            if (self.Address.eleNumber > 254):
                data += struct.pack('>B', 0xFF)
                data += struct.pack('<H', self.Address.eleNumber)
            else:
                data += struct.pack('>B', self.Address.eleNumber)

            if (self.Address.subElement > 254):
                data += struct.pack('>B', 0xFF)
                data += struct.pack('<H', self.Address.subElement)
            else:
                data += struct.pack('>B', self.Address.subElement)

            #######################################
            # Calculate CRC before escaping DLE's
            #######################################
            crc = utilities.computeCRC(data)

            ####################################
            # Escape any DLE's ('\x10') in data
            ####################################
            start = 0
            while (data.find('\x10', start, len(data)) != -1):
                i = data.find('\x10', start, len(data))
                data = data[:i] + '\x10' + data[i:]
                start = i+2

            self.packet += data

            ###################################
            # Packet End
            ###################################
            self.packet += struct.pack('>BB', 0x10,0x03)        #DLE ETX
            self.packet += struct.pack('>H', crc)
        else:
            self.packet = packet

        return self.packet


    def __str__(self):
        ''' Returns a string representation of the instance

        :returns: A string representation of the instance
        '''
        return "DataInquiryRequest (%s,%s)" % (self.dest, self.parameter)





 

More to come ....

 

Introduction

IMG_7050.jpg

 

In a previous guide, I covered how to control stepper motors using Gertbot. For this post, I'd like to cover the built-in endstop functionality.

 

Endstops (also know as "limit switches") can be very useful to stop motors when an end position has been reached. This is for example the case with 3D printers or CNC milling machines where the motors controlling each axis, back up until the endstops are triggered. This defines a reference point, also called "home position" with coordinates 0,0,0.

 

There are different types of endstops, just to name a few:

  • mechanical: an ordinary switch makes or cuts a connection when triggered
  • magnetic: a hall-effect sensor is used to measure the magnetic field
  • optical: a sensor reacts to sudden changes in light levels

 

For this guide, I'll be using mechanical endstops, such as the one on the right.

 

Gertbot

 

The Gertbot add-on board for the Raspberry Pi offers the possibility to activate endstops, which when triggered, will automatically stop the associated motors without having to code any additional functions.

 

Pins

 

Four pairs of endstops can be defined: one pair per motor channel, covering two extremities. Seen from the top of the Gertbot, the endstop pairs are positioned as such:

photo (24).JPG

 

The endstop pins are connected to 3.3V using a 4.7kOhm pull-up resistor.

 

Modes

 

The endstops can be configured in three different modes:

  • OFF (0): don't enable the endstops
  • ENDSTOP_LOW (1): enable endstop, stop motor channel when switch to GND is closed and pin is LOW
  • ENDSTOP_HIGH (2): enable endstop, stop motor channel when switch to GND is open and pin is HIGH

 

When using endstops, the safest option is to use the ENDSTOP_HIGH mode, as a broken endstop wire would result in the motor channel to be disabled, ensuring the safest state.

 

Code

 

Activating endstops for a single motor channel is straightforward:

 

// gb.set_endstop(BOARD, CHANNEL, ENDSTOP_A_MODE, ENDSTOP_B_MODE)
// Configure first board's first motor channel with two endstops, triggered with the pin is HIGH
gb.set_endstop(0, 0, 2, 2) // board 0, channel A, endstops A & B in ENDSTOP_HIGH mode





 

Multiple endstop pins can also be hooked up to the same switch. For example if two servo motors are used, with motor #1 on channels A & B and motor #2 on channels C & D, the setup would be as follows:

 

// gb.set_endstop(BOARD, CHANNEL, ENDSTOP_A_MODE, ENDSTOP_B_MODE)
// Configure first board's first motor channel with two endstops, triggered with the pin is LOW
gb.set_endstop(0, 0, 1, 1) // board 0, channel A, endstops A & B in ENDSTOP_LOW mode
gb.set_endstop(0, 2, 1, 1) // board 0, channel C, endstops A & B in ENDSTOP_LOW mode





 

Demo

 

Here's an animation of an endstop being triggered, resulting in the motors to stop. (You may have to click the image)

endstop.gif

 

Conclusion

 

This is a very useful feature of the Gertbot, as the endstop functionality only needs to be activated and works independently from that moment on, without requiring specific code to manage them.

 

So here's the video I could not get uploaded over the weekend. I still want to do a couple more videos to show the readouts better for the demo's since the working screen is on the device and is a TFT 2.8R display. The demo indicates the sensors, switches, some controls and wiring. Schematic to follow.

Introduction

Meditech will be used in many different environments and not always the visual information provided on the screen maybe useful. Receiving helpful audio hints and suggestions on-the-go is a good solution; when the user should activate a probe, start or stop the data acquisition nearby the patient it is very useful to control the entire system with a simple infrared controller but maybe not sufficient. This is the reason that to improve the system usability the TTS (Test-To-Speech) support has been added to enforce the user interaction and system feedback.

The introduction of this feature in the Meditech system has involved two devices: RPI master and RPI slave3 hosting the Cirrus Logic Audio Card.

One of the biggest issues is that as the audio card uses its own custom distribution of the raspian linux with a real-time kernel. Unfortunately it does not support the standard apt-get update and apt-get upgrade features: In few words, the raspian version of the RPI slave 3 should never be updated and there are very few packages that can be installed on this version. In fact the audio card performances are very good and are used for the microphonic stethoscope probe so it is not the worth to replace this hardware with a more flexible one penalising the quality.

Last but not least, the text strings are managed by the controller application installed on the RPI master device.

 

How it works

The scheme below shows the implementation architecture of the TTS feature in the Meditech device.

Screen Shot 2015-07-28 at 11.03.01.png

The synthesized strings can be disabled with the mute button on the controller. When the synthesis is active when the user press a command on the controller the Meditech speakers says a short contextual sentence. The video below shows the interaction effect.

 

TTS sentences generation

The voice synthesis does not need to be used at runtime. To be more clear, this must not used for at least two reasons: the voice synthesis is a resource consuming process and the sentences changes only when a new version of the applications is released. So what we really need is a TTS reliable system that should be run once and a good method to store audio text files on the RPI master device, where there is sufficient space as it has the 120 Gb SSD disk attached.

 

The synthesis tool

The TTS tool that has been adopted is festival that for many reasons if highly customizable, efficient yet reliable, runs on raspian linux and has a good environment for custom commands, voices definitions and more. The Festival Speech Synthesis System has been developed by the Centre for Speech Technology Research of the University of Edinburgh; it is a long-term project, started in 1984 that is already maintained with a wide community of users and developers sharing their knowledge. The actual version that can also be found in the raspian repository is the 2.4 of the end of 2014.

To install Festival in the Raspberry PI 2 (it works fine also in the B+ 512K) it is needed a simple operation:

 

sudo apt-get install festival



 

As the installation provided by the official raspian linux distribution, the best results can be obtained with a more in-depth analisys of the Festival features. To achieve good audible results and understanding a bit more the fascinating world of the Text-to-speech synthesys I strongly suggest to download the Festival package and compile it separately to have more voices, intonations and tools that can dramatically improve the  features provided with the standard installation. Not required but it is a good advantage, an average knowledge on how the lisp language works. As a matter of fact Festival can run in command mode or process batch commands expressed with Scheme list sentences that is a variant of the official lisp language.

One of the features of Festival is the ability to execute the TTS generating wav files for further usage.

 

Speech synthesis batch command

What is needed to synth the text messages in audio format is a method that starting from a simple text string (e.g. "Hello World") a corresponding audio file is generated. The other important implication is that the audio file should follow a specific naming convention. The better way is that the generated file has the same name of the corresponding string ID in the controller program: this means that for the sentence whose ID is 10 the generated audio file should have the name 10.meditech where 'meditech' is the arbitrary file extension for the audio messages.

The resulting bash command create_ttsText.sh has the following format:

 

#!/bin/bash
# Create the text files to convert to TTS
echo "*** Creating TTS $2 ***"
echo $1 > ~/$3
text2wave -o $2 -F 48000 -otype snd ~/$3
rm ~/$3
echo "*** Completed ***"


 

Note that this command uses the text2wave festival scheme script that is part of the festival tts package

 

As far as the festival architecture it is not possible to pass to it a string but it is needed a text file. So the first action of the create_ttsText.sh script is just to convert the input string to a template text file that is deleted after the audio synthesis operation. With this bash command the synthesis parameters are preset to simplify as much as possible the process that will be automated. The text2wave festival script call fixes the output audio file to the snd type and the quality frequency to 48KHz; as a matter of fact these files will be played with a high quality sound card so it is the worth to keep the quality high (48KHz is the standard frequency for the DVD audio quality).

With this batch the number of parameters that should be passed for the synthesis is minimal. For example the generation of the audio file named output.meditech from the test string "hello, Element14 ! How is the weather today?" will be as shown below

 

./create_ttsText.sh "hello, Element14 ! How is the weather today?" output.meditech


 

Audio files creation

The audio files creation has been implemented as a special option in the controller application. This program will run indefinitely when the RPI master device starts (when the Meditech is powered-on) for the real-time process of the infrared controller buttons. When the program instead is launched with the -v (that is, "voice") parameter it executes the audio files creation. This option can be launched also when the program runs as a background process in standard mode so there are not special procedures to follow to generate the files when needed.

 

The audio files are stored in the ~/tts_audio_messages folder where the name of the file is the same of the message ID in the controller program.

pi@RPImaster ~ $ ls tts_audio_messages/
1.meditech   14.meditech  19.meditech  23.meditech  3.meditech  8.meditech
10.meditech  15.meditech  2.meditech   24.meditech  4.meditech  9.meditech
11.meditech  16.meditech  20.meditech  25.meditech  5.meditech
12.meditech  17.meditech  21.meditech  26.meditech  6.meditech
13.meditech  18.meditech  22.meditech  27.meditech  7.meditech

 

To add this feature a new version of the controller application has been created adding the file MessageStrings.h with the strings ID definition and some other useful constants.

// Strings array IDs
#define TTS_SYSTEM_RESTARTED 0
#define TTS_POWER_OFF 1
#define TTS_SHUTDOWN 2
#define TTS_VOICE_ACTIVE 3
#define TTS_MUTED 4
#define TTS_STETHOSCOPE_OFF 5
#define TTS_STETHOSCOPE_RUNNING 6
#define TTS_STETHOSCOPE_ON 7
#define TTS_BLOOD_PRESSURE_OFF 8
#define TTS_BLOOD_PRESSURE_RUNNING 9
#define TTS_BLOOD_PRESSURE_ON 10
#define TTS_HEARTBEAT_OFF 11
#define TTS_HEARTBEAT_RUNNING 12
#define TTS_HEATBEAT_ON 13
#define TTS_TEMPERATURE_OFF 14
#define TTS_TEMPERATURE_RUNNING 15
#define TTS_TEMPERATURE_ON 16
#define TTS_ECG_OFF 17
#define TTS_ECG_RUNNING 18
#define TTS_ECG_ON 19
#define TTS_INFORMATION 20
#define TTS_TESTING 21
#define TTS_TESTING_END 22
#define TTS_SYSTEM_READY 23
#define TTS_START_PROBE 24
#define TTS_PROBE_STOPPED 25
#define TTS_CONTINUOUS_ON 26

 

The strings themselves instead are loaded in an array in the program. In future versions, supporting the language localization a multi-language set of includes should be used to replace the hardcoded strings.

When the main() - i.e. the program itself - is launched it is checked if the -v parameter is passed, to start the generation function instead the normal process.

// Check for main parameters
    if(argc > 1) {
        // Check for valid arguments
        if(argc != 2) {
            printf(MAINEXIT_WRONGNUMPARAM);
            exit(EXIT_FAILURE); // Wrong number of arguments
        }
        // We expect and argument in the format '-x' where 'x' is
        // the option code
        if(strstr(argv[1], VOICE_STRINGS) ) {
            ttsStrings();
            printf(MAINEXIT_DONE);
            exit(0);    // ending
        } // Launch the TTS generation
        else {
            printf(MAINEXIT_WRONGPARAM);
            exit(EXIT_FAILURE); // Wrong argument
        }
    } //

 

With the -v parameter it is called the function ttsStrings() to execute recursively the bash script. As mentioned before, the strings are defined in an array, in the same order of the IDs in the MessageStrings.h header file.

/**
\brief Convert the program application strings to voice messages
*/
void ttsStrings(void) {
   
    //! The strings array with the messages
    const char * MESSAGES[TTS_MAX_MESSAGES] = {
        "System restarted to the power-on conditions. ",
        "Power-off: press the OK button for complete shutdown, any other button to ignore. ",
        "Power-off confirmed. Shutdown-sequence started. ",
        "Voice messages are now active. ",
        "Muted. ",
        "Microphonic Stethoscope is now disabled. ",
        "Microphonic Stethoscope is already active.",
        "Enabled Microphonic Stethoscope. ",
        "Blood Pressure measurement probe is now disabled. ",
        "Blood Pressure measurement probe is already active.",
        "Enabled Blood Pressure measurement probe. ",
        "Heart Beat measurement probe is now disabled. ",
        "Heart Beat measurement probe is already active.",
        "Enabled Heart Beat measurement probe. ",
        "Body Temperature measurement probe is now disabled. ",
        "Body Temperature measurement probe is already active.",
        "Enabled Body Temperature measurement probe. ",
        "E.C.G. probe is now disabled. ",
        "E.C.G. probe is already active.",
        "Enabled E.C.G. probe. ",
        "Look at the Control Panel display for system information. ",
        "Started a Control Panel test cycle. ",
        "Control Panel test cycle ended. ",
        "Startup completed. System ready. ",
        "Press OK button to start the probe collecting data. ",
        "Probe stopped.",
        "Continuous mode running. Press OK to stop collecting data."
    };

    printf(TTS_START_PROCESS);

    // Generate the TTS wav files
    for(int j = 0; j < TTS_MAX_MESSAGES; j++) {

        char fileName[64];
        char fileTemp[64];
        char programName[32];
        char programPath[64];
        char messageText[1024];

        sprintf(fileName, "%s%d.%s", TTS_FOLDER, j + 1, TTS_FORMAT);
        sprintf(fileTemp, "%d.tmp", j + 1);
        sprintf(programName, "%s", TTS_SHELL_COMMAND);
        sprintf(programPath, "%s", TTS_SHELL_PATH);
        sprintf(messageText, "%s", MESSAGES[j]);

        char* arg_list[] = {
            programName,     // argv[0], the name of the program.
            messageText,
            fileName,
            fileTemp,
            NULL
          };
       
        // Spawn a child process running the command. 
        // Ignore the returned child process id.
        spawn (programPath, arg_list);
    }
}

 

There are different methods to execute a shell command from a C++ program using the exec command; the issue is that using a call to exec from the C++ program the second process (launched by exec) runs together with the calling process (our program) and - especially in case like this where there is a loop of many sequential calls - concurrency problems and arise. What we need is to be sure that when we launch the external program with exec our calling program wait until the child process has been completed. To do so, the parameters call is prepared as shown in the scriptlet above but the secondary process is launched spawning our primary process. So what happens is that the primary process launch the child processes in the correct way, then return back and proceed launching the next process and so on. As in this case we don't need to check a return value all the conversion processes can be executed in parallel. The following image explain what is shown on the terminal when the conversion process is started.

Screen Shot 2015-07-28 at 14.51.05.png

 

Playing audio files

In a similar way when the controller is not in mute mode, when a button is processes the corresponding audio file is played as shown in the example below from the function parseIR()

case CMD_RED:
            if(infraredID != controllerStatus.lastKey) {
                if(!controllerStatus.isMuted) {
                    playRemoteMessage(TTS_TESTING);
                }
                cmdString = cProc.buildCommandDisplayTemplate(TID_TEST);
                controllerStatus.serialState = SERIAL_READY_TO_SEND;
                setPowerOffStatus(POWEROFF_NONE);
                // Check the serial status
                manageSerial();
            }
            break;

 

Below there is the playRemoteMessage() function that uses the spawning method as well.

/**
\brief Play a voice message on the remote RPIslave3 with the
Cirrus Logic Audio Card.

\note To the Linux side the two computers should be set to share the
private / public ssh key to avoid passing user and password during the
ssh remote command launch

\param messageID The message ID to play remotely
*/
void playRemoteMessage(int messageID) {
   
        char sshCall[64];
        char sshServer[64];
        char programName[32];
        char programPath[64];

        sprintf(programName, "%s", SSH_COMMAND);
        sprintf(programPath, "%s", SSH_PATH);
        sprintf(sshCall, "%d", messageID + 1);

        char* arg_list[] = {
            programName,
            sshCall,
            NULL
          };
       
        // Spawn a child process running the command. 
        // Ignore the returned child process id.
        spawn (programPath, arg_list);
}

 

Also in this case there is a call to the SSH_COMMAND that is a bash script as shown below.

#!/bin/bash
# Play a message remotely
ssh 192.168.5.4 "/home/pi/play_message.sh $1"

 

Here is the difference. In this case the audio - that is stored on the RPI master linux device, should be played on a different IP address, that is the RPI slave3 linux device hosting the Cirrus Logic Audio Card. To reach this behavior some linux actions were needed:

 

  • The RPI master storage folder ~/tts_audio_messages has been exported, i.e. shared via linux NFS
  • On the RPI slave3 the same empty folder has been created, then has been mounted remotely. The result is that in the mounted folder there are the same files for playing
  • On the RPI slave3 the bash command play_message.sh has been created (see the description below)

 

When the spawned (child) process is launched by the controller program on the RPI master what really happens is that the bash script command play_message.sh is executed on the RPI slave3. The only parameter passed is - again - the message ID. The remote bash command plays the audio file without consuming resources of the RPI master that gain immediately the control of the main program after launching the command.

pi@RPIslave3 ~ $ more play_message.sh
#!/bin/bash
# Play a Meditech controller audio message
AUDIODEV=hw:0 play --no-show-progress -V0 /home/pi/tts_audio_messages/$1.meditech reve
rb 30

 

The updated sources are available on the GitHub repository as usual.

{gallery} Day 93 Picorder in operation

IMG_20150509_141031.jpg

My Partner in crime: Hard at work!!

IMG_20150726_205357.jpg

CHASSIS: Power regulator

IMG_20150726_205350.jpg

Power Supply: 5Vdc for testing

IMG_20150726_205337.jpg

The Face of Pi: New PIR sensor

IMG_20150726_193933.jpg

Power Board: Pull-up resistors

IMG_20150726_192156.jpg

PIR MOUNTING: Standoff Placement

IMG_20150726_192118.jpg

IMPERFBOARD: PIR mounts

IMG_20150725_121418.jpg

SENSOR: removal of CO2 and alcohol sensors

IMG_20150725_120804.jpg

FLAME DETECTOR: sensor module

IMG_20150725_120748.jpg

EASPBERRY PI: B+ model replaced model B

IMG_20150509_141016.jpg

VIDEO CONFERENCE: Collaboration on Picorder Project

Older Posts:

 

The RPi Robot

 

I finally got around to restructuring the RPi Robot and well here's the result.

{gallery} Robot Taking Shape

20150726_183940.jpg

Its Alive!: uuhhh...

yoVwN18aFSbCMvu1uXI01ZAgaDaEgqgna33LZ2QbcmI=w1007-h755-no

Needed Better Screws: .

jzMKfJ27I5vysI8x2rITNyeEWLHejviC8xKeRtMfpSg=w1007-h755-no

Big Battery!: With the 3D printed Clamp for the Display

bjq2pfbMzlYW2UZv8JEe3hWikTVY3xUZl-h92kwGMBY=w1007-h755-no

Hello!:

zywLVFGz9XCWOrs0sCyhKf1g3HSgClBbhqs2flTV8PE=w1007-h755-no

Where do I fix the PI: ?

muvY_v3iHpOsjpHhelblIUuJRSH31KJdvqOaAn6ePtg=w1007-h755-no

Side View

7zE9478-xVHfejwfuKpFXkAjTp_w9Cd988Bad7edL8I=w1007-h755-no

Cardboard Clamp: Fixture for the Motor Driver

uH7DY-Qa2bp7klox3_c_vYn6tepUpL5dST65E9EUi-0=w1007-h755-no

Servo Motor Stand using Cardboard: That'll do.

_IEp5pRr1F_vkKUhjk4newEaVyi_IuyzjWSm9bSFdUA=w1007-h755-no

Make a Servo Motor Stand at Home: DIY

FPaS8ycB3gWr0RLrG3_VoxyiIhJ9Qj1T9JGL5NYtyI8=w1007-h755-no

Joining Hands: Connecting the Camera mount with the Servo Motor

d8AcbrCT2i_gFCkBO1zpR64TJ0zxNE5XignLvq_9Uso=w1007-h755-no

Our Robot Can Nodd:

CyFzKbDBkh4rt8P-wwAEaVN4AGRQcWzVKyUPcYnQs_s=w1007-h755-no

With the Ultrasonic Ranger: Looks a bit crooked

Y88wSQ7Lkhg0525GColw4qITLTtgKo1IFCaoLCfxxBc=w1007-h755-no

Yep!: Its a bit crooked!

g8ogkW5IN0xtY4uX6kSgRBquYTPcFfBLtwsIh8vXhYk=w1007-h755-no

Luke Skywaker Comes to check out the robot!: Are you OK R2?

ynq-0Ts4v19SSQnQvztHHDTSIPMHjtV0RrviGQtZezg=w1007-h755-no

Still needs a few connections... :

Previous posts for this project:

 

 

Project Update

 

I was having so much fun playing with the Beaglebone Black and TI SensorTag that I almost forgot to write this update!

 

Anyway, got some sliders to mount the screen to and made a (rather bulky, but strong) frame to mount to the desk and hold everything in place. The next step will be to add the stepper motors and limit switches to automate the lift. My 3D printer is still acting up, so I'll probably end up making the piece manually. Don't worry, I have a plan ...

 

Here's a short video showing some assembly stages and testing the sliders manually.

 

Regarding Charles Gantt's "Design Challenge Summary, Week Ending July 18th" article and the Picorder project progress:

 

I apologize for the lack of recent pictures of the Picorder to all of element14, challengers, readers and followers. However, previously I wrote that I'm removing the CO2 and alcohol sensors due to their excessive power requirements and replacing them with other types of less power demands which requires redesign of the Picorder. This has been ongoing since that posting.

 

As my last posting stated, I've had to undergo some major redesign of the Picorders sensors, type and quantity. From the time I posted the videos, photo galleries and demos of some of the sensors, the overall physical characteristics of the unit have not changed.

 

The major changes are with getting the scripting to function correctly. The sensor outputs to the GPIO inputs are basically similar in operation regardless of the sensor type for the sensor modules I'm working with.

 

There are three basic type inputs to the raspberry pi as it pertains to the GPIO's.

First we have a standard analog input which accepts a typical analog signal without regard to frequency or amplitude (except that which are minimum/maximum thresholds for recognition by the pi).

 

Secondly, there is a digital signal which can be recognized by the GPIO pins. The digital signal is in the format of binary 1's and 0's and functions as a continuous data stream of transitions per time period. Last but not least is a PWM signal recognized by the pi. This PWM (Pulse Width Modulation) signal as its name implies, is a digital signal of varying time durations (widths) of the binary 1's and 0's between transitions. The varying timing and transitional occurrences’ differentiates this format from the digital signal.

 

These three signal formats allow the Picorder to interpret its GPIO input and respond (or output) very differently. The DHT11 temperature sensor allows the Picorder to interpret the signal constantly, and produces continues change reading of temperature and humidity while the flame sensor supplies a digital (toggle) signal of either ON or OFF to the pi until the sensor reads a change. With the PWM signal to the pi, an on/off signal allows the pi to perform a specific function for a fixed or variable duration (time period).  Incorporating these three variations of signaling formats into the script is challenging.

Unbeknownst to the readers and followers of the “sci fi your pi” challenge, my Picorder, and element14 this challenge has been my introduction to programming languages in general, specifically Python, Bash, and others which I am working through to learn and understand given the time limit of the challenge. Exposure in these areas is limited for me since I seem to have been more hardware oriented than software over the years.

Moving forward; I've torn down the Picorder to rebuild it with some new sensors all the while working on the scripting as I go and taking a line-by-line approach to get the programming to work. As originally outlined at the beginning of the challenge, my intent with the Picorder needs to be a self-contained autonomous sensing device with consistent and continuous readouts for its user to address conditions hazardous or of interest to human life. In unexplored environments as was typical of Star Trek: TOS landing party, such readings could alert the crew to other life forms and unexpected dangers while conducting planetary exploration.

 

I am currently replacing the sensors mentioned above and hope to post some photos not later than tomorrow. They should include the disassembly of the old and installation of the new sensors. I have a circuit diagram I drew last week (with the CO2 and alcohol sensors) and will draw a second one with the replacement sensors and post them both with the new photos. As has happened already with other contestants of this challenge, I’ve encountered some unexpected results and obstacles to overcome. But then that’s what is to be expected with design, engineering, and prototyping. The 90/10 perspiration/inspiration factor wins out every time! More to follow…

As mentioned in a previous post I will be using python Twisted architecture for the asynchronous communications that are required I chose to use twisted partly because I was interested in learning more about it but also because it supports all the functionality that I needed serial communication(for  RS-232RS-232 and RS-422 protocols FTP and SMTP all in one package Twisted certainly is capable of much more but these are the communication channels I need to support

 

All of the popular Linux distributions maintain a python-twisted package as well as packaged versions of Twisted’s dependencies. To install Twisted on a dpkg-based system, run:

sudo apt-get install python-twisted











 

 

To verify that the installation worked and that you have the desired version of Twisted installed, import the twisted module from a Python prompt:


$ python
>>> 
Python 2.7.3 (default, Mar 8 2014, 05:13:23)
Type "help", "copyright", "credits" or "license" for more information.
>>> import twisted
>>> twisted.__version__
'1.0.0'
[GCC 4.6.3] on linux2











 

If the import twisted statement runs with no errors, you have a working Twisted installation.

 

 

RS-422 communication

I am communicating to a Fenner M-Trim motor controller over a RS-422 serial connection. The protocol can be found in the User Manual in chapter 7 (http://www.contrexinc.com/PDF/UserManuals/M-TrimUserManual.pdf). The protocol is a simple 12 byte ASCII string and uses ‘\x02’ as the STX (start of transmission) and ‘\x03’ as the ETX (end of transmission).

 

The protocol looks like this:

Char#

1

2

3

4

5

6

7

8

9

10

11

12

Desc

STX

DEV# 10’s

DEV# 1’s

MSG Type

Par# 10’s

Par# 1’s

Data 1000’s

Data 100’s

Data 10’s

Data 1’s

Data Format

ETX

 

The MSG Type determines whether it is a read or write packet. The Data format determines the decimal position for the data.

 

The code for this portion of the project can be found at https://github.com/frellwan/SciFy-Pi.git in the Serial/MTrim folder.

The finished code will differ slightly due to the fact that the communication on this port will be driven by the SLC 5/04 processor, but for testing purposes I have added code to read and write to parameters to show the concept.

 

As mentioned in a previous post I am using a USB to RS422 cable(USB-RS422-WE-1800-BTUSB-RS422-WE-1800-BT) to be able to communicate to the Fenner M-Trim controller. The data sheet can be found here: USB-RS422-FTDI

The cable pinout can be seen below:

cable diagram

The TXD-/TXD+ on the cable is connected to the RX-/RX+ on the MTrim and the RX-/RX+ on the cable is connected to the TX-/TX+ on the MTrim. The GND on the cable is connected to the GND on the MTrim. Once connected it works very well. The USB side of the cable has 2 LED's - a red for transmit and a green for receive. So it is very easy to see when signal transmission is happening. With the exception of the price of this cable, I am very pleased with its performance.

 

 

I borrowed heavily from the Pymodbus source code. This package is well proven and seemed like a good starting point. The serialport instantiating is very simple

class SerialMTrimClient(serialport.SerialPort):

  def __init__(self, factory, *args, **kwargs):
  ''' Setup the client and start listening on the serial port

  :param factory: The factory to build clients with
  '''
  protocol = factory.buildProtocol()
  self.decoder = ClientDecoder()
  serialport.SerialPort.__init__(self, protocol, *args, **kwargs)


Options = Options()
config = SafeConfigParser()
config.read([options['config']])

framer = AsciiFramer(ClientDecoder())
factory = MTrimFactory(framer)

RS422port = config.get('RS-422', 'host')
RS422baud = config.getint('RS-422', 'baudrate')

SerialMTrimClient(factory, RS422port, reactor, baudrate = RS422baud)

log.debug("Starting the client")

reactor.run()




 

At this point the MTrimProtocol is now responsible for encoding and sending the ASCII string to the MTrin controller.

The Mtrim has 3 types of commands – read, write and control command. Each command type has a different way to encode the data, so they each have their own code for encoding and decoding messages.

class ParameterSendRequest(PDU):
    '''
    Class for writing a MTrim register
    '''
    _frame_size = 12

    def __init__(self, address=1, parameter=1, value=0, **kwargs):
        ''' Initializes a new instance

        :param address: The address of the device to write to
        :paramater: The parameter to write to
        :value: The value to write to the parameter
        '''
        PDU.__init__(self, **kwargs)
        self.address = address
        self.parameter = parameter
        self.msgType = '3'
        self.value = value
        self.Data = ''
        self.dataFormat = '0'
        self.packet = ''

    def encode(self):
        ''' Encodes the request packet

        :return: The encoded packet
        '''
        if (not self.skip_encode):
            self.packet = struct.pack('>B', 0x02)        #STX
            if (self.address <10):
                self.packet += '0' + str(self.address)
            else:
                self.packet += str(self.address)

            self.packet += self.msgType

            if (self.parameter < 10):
                self.packet += '0' + str(self.parameter)
            else:
                self.packet += str(self.parameter)

            strValue = str(self.value)
            if(self.parameter in [20,21,22,23]):
                if (self.value >= 0):
                    if strValue.find('.') == -1:
                        self.dataFormat = '0'
                    else:
                        self.dataFormat = str((len(strValue)-1)-strValue.find('.'))
                if (self.value < 0):
                    if strValue.find('.') == -1:
                        self.dataFormat = '4'
                    else:
                        self.dataFormat = str((len(strValue)-1)-strValue.find('.')+4)
            else:
                self.dataFormat = '0'
              
            if strValue.find('.') == -1:
                for c in range(4-len(strValue)):
                    self.Data += '0'
                self.Data += strValue
            else:
                for c in range(5-len(strValue)):
                    self.Data += '0'
                self.Data += "".join(strValue.split('.'))
                  
            self.packet += self.Data
            self.packet += self.dataFormat
            self.packet += struct.pack('>B', 0x03)       #ETX
                      
        return self.packet

    def decode(self, data):
        ''' Decode a register request packet

        :param data: The request to decode
        '''
        self.address = int(data[1])*10 + int(data[2])
        self.msgType = data[3]
        self.parameter = int(data[4])*10 + int(data[5])
        self.dataFormat = int(data[10])

        self.value = int(data[6:10])
        if (self.dataFormat <= 3):
            self.Data = self.value/(10**self.dataFormat)
        else:
            self.Data = -1 * self.value/(10**(self.dataFormat-4))

        return self
      
    def __str__(self):
        ''' Returns a string representation of the instance

        :returns: A string representation of the instance
        '''
        return "ParameterSendRequest (%d,%d,%d)" % (self.address, self.parameter, self.Data)



 

Here is some video - it didn't turn out as well as I had hoped - hopefully I can get a better video soon

 

The frame is almost completed

I encountered more difficulties than I expected in assembly a structure using steel wires...

 

IMG_20150724_131731.jpg

IMG_20150724_131824.jpg

 

It's not very clear in these pictures, but there are three "parallels" corresponding to three "levels"

On the upper level, the raspberry and the accelerometerers will be mounted

The middle level will host the two engines and propellers

The bottom level will host the control surfaces

At the bottom of the sphere (so outside the sphere) I will place the battery and the two servos that move the control surfaces

Introduction

Meditech internal architecture is built by a network of Raspberry PI devices specialised to manage some acquisition probes producing several kind of data. The information of the running system should be shared with the devices and collected for the graphical representation and for historical purposes so the ideal data collector is represented by a centralised database hosted on the main unit RPI master (Raspberry PI 2).

 

To efficiently organise the data the acquired information are stored and accessed on a MySQL database. This is one of the reasons why the RPI master is equipped with a 120Gb SSD storage.

 

Database organisation

The following scheme shows the central role of the RPI master database in the data collection, storage and distribution.

Screen Shot 2015-07-23 at 14.40.05.png

The MySQL database inside the Meditech architecture represent the main data center. Installed on the same RPI master unit there is also the Apache2 web server and PHP server. The database is also used for store single-record tables with the persistent configuration data of the system.

 

The data sets that should be available from remote can be accessed through a set of PHP APIs; this strategy permit to access from remote the real time information (for external support and assistance) using any Internet-connected device including smartphones and tablets, PC and laptop with a connected browser.

 

As all the Meditech units are connected on the same LAN the data exchange is fast as the MySQL server on the RPI master is accessed by the other units directly via SQL queries using SSH tunnels.

Introduction

One of the core elements of the Meditech software is the controller, managing the user interaction for the entire system. We can consider the controller module as an application - running as a process that never stops - as a simple task-manager and task launcher. The rest of the job is done by the automation components of the Meditech device.

The only one part that is directly managed by the controller software is the control panel communication. The reason is that in the system architecture one of the roles of the control panel is just to be part of the user interaction mechanism.

 

The updated software sources are available on GitHub at the following address: https://github.com/alicemirror/chipkit_serial_pi/tree/master/Meditech_RaspianControlPanel

The last compiled documentation is available at: Meditech control panel software: Main Page while the pdf version can be found in attach to this post.

 

(note: some class methods and documentation are derived from the chipkit control panel documentation so please ignore the references to the ChipKit board. It's a beta version! )

 

How it works

The controller application is launched on startup of the RPI main device (Raspberry PI 2) and runs indefinitely in a main loop. This part consumes very few resources and only when a button on the IR controller is pressed the process activates the parsing of the button for the request recognition.

In the main.cpp there are tre important global objects:

 

//! UART file stream to manage the serial connection
int uart0_filestream = -1;

//! Status flags structure
states controllerStatus;

//! The command string to be sent to the control panel
char* cmdString = '\0';






 

The start sequence of the module is almost simple:

  • Activate the IR lirc process and open a thread
  • If there are no problems on activating the infrared controller, open the serial connection with the control panel board (ChipKit)
  • Setup the serial speed then start the infinite loop.

Until the RPI master is powered on the serial interface is locked and the lirc communication protocol is active with the IR controller.

 

IR commands via lirc library

 

if(lirc_init((char *)LIRC_CLIENT, 1) == -1)
  exit(EXIT_FAILURE);

  //Read the default LIRC config at /etc/lirc/lircd.conf
  if(lirc_readconfig(NULL, &config, NULL) == 0) {
  // Set the lirc status flag
  controllerStatus.isLircRunning = true;
  // As lirc is working intialise the serial connection
  uart0_filestream = open(UART_DEVICE, O_RDWR | O_NOCTTY | O_NDELAY);
  // Check the UART opening status. If a problem occur, the application exits.
  if(uart0_filestream == -1) {
  //Frees the data structures associated with config.
  lirc_freeconfig(config);
  // Closes the connection to lircd and does some internal clean-up stuff.
  lirc_deinit();
  // Set the lirc status flag
  controllerStatus.isLircRunning = false;
  exit(EXIT_FAILURE); // The /etc/lirc/lircd,conf file does not exist.
  } // Problem opening the UART. Exit with error




 

The code above shows how the IR and serial (via direct UART connection) are launched. After the lirc library has been initalized it is read the configuration This means that the known IR keycodes previously set when configuring the Infrared in the raspian Linux are loaded for parsing. At this level when a command is recognised it is simply parsed (see the code below) and depending on the kind of command the corresponding task is launched. In this way it is granted a good reactivity of the controller, despite the actual running task in the system.

 

switch(infraredID) {
  case CMD_MENU:
  if(infraredID != controllerStatus.lastKey) {
  cmdString = cProc.buildCommandDisplayTemplate(TID_DEFAULT);
  setPowerOffStatus(POWEROFF_NONE);
  }
  break;
  case CMD_POWER:
  if(infraredID != controllerStatus.lastKey) {
  setPowerOffStatus(POWEROFF_REQUEST);
  }
  break;
  case CMD_NUMERIC_0:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_NUMERIC_1:
  if(infraredID != controllerStatus.lastKey) {
  cmdString = cProc.buildCommandDisplayTemplate(TID_STETHOSCOPE);
  controllerStatus.serialState = SERIAL_READY_TO_SEND;
  setPowerOffStatus(POWEROFF_NONE);
  // Check the serial status
  manageSerial();
  }
  break;
  case CMD_NUMERIC_2:
  if(infraredID != controllerStatus.lastKey) {
  cmdString = cProc.buildCommandDisplayTemplate(TID_BLOODPRESS);
  controllerStatus.serialState = SERIAL_READY_TO_SEND;
  setPowerOffStatus(POWEROFF_NONE);
  // Check the serial status
  manageSerial();
  }
  break;
  case CMD_NUMERIC_3:
  if(infraredID != controllerStatus.lastKey) {
  cmdString = cProc.buildCommandDisplayTemplate(TID_HEARTBEAT);
  controllerStatus.serialState = SERIAL_READY_TO_SEND;
  setPowerOffStatus(POWEROFF_NONE);
  // Check the serial status
  manageSerial();
  }
  break;
  case CMD_NUMERIC_4:
  if(infraredID != controllerStatus.lastKey) {
  cmdString = cProc.buildCommandDisplayTemplate(TID_TEMPERATURE);
  controllerStatus.serialState = SERIAL_READY_TO_SEND;
  setPowerOffStatus(POWEROFF_NONE);
  // Check the serial status
  manageSerial();
  }
  break;
  case CMD_NUMERIC_5:
  if(infraredID != controllerStatus.lastKey) {
  cmdString = cProc.buildCommandDisplayTemplate(TID_ECG);
  controllerStatus.serialState = SERIAL_READY_TO_SEND;
  setPowerOffStatus(POWEROFF_NONE);
  // Check the serial status
  manageSerial();
  }
  break;
  case CMD_NUMERIC_6:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_NUMERIC_7:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_NUMERIC_8:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_NUMERIC_9:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_UP:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_DOWN:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_LEFT:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_RIGHT:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_RED:
  if(infraredID != controllerStatus.lastKey) {
  cmdString = cProc.buildCommandDisplayTemplate(TID_TEST);
  controllerStatus.serialState = SERIAL_READY_TO_SEND;
  setPowerOffStatus(POWEROFF_NONE);
  // Check the serial status
  manageSerial();
  }
  break;
  case CMD_GREEN:
  if(infraredID != controllerStatus.lastKey) {
  cmdString = cProc.buildCommandDisplayTemplate(TID_INFO);
  controllerStatus.serialState = SERIAL_READY_TO_SEND;
  setPowerOffStatus(POWEROFF_NONE);
  // Check the serial status
  manageSerial();
  }
  break;
  case CMD_YELLOW:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_BLUE:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_OK:
  if(infraredID != controllerStatus.lastKey) {
  if(controllerStatus.powerOff == POWEROFF_REQUEST)
  setPowerOffStatus(POWEROFF_CONFIRMED);
  else
  setPowerOffStatus(POWEROFF_NONE);
  }
  break;
  case CMD_MUTE:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_VOLUMEUP:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_VOLUMEDOWN:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_CHANNELUP:
  setPowerOffStatus(POWEROFF_NONE);
  break;
  case CMD_CHANNELDOWN:
  setPowerOffStatus(POWEROFF_NONE);
  break;

  default:
  break;
  } // Button ID case

  // Update the last key ID
  controllerStatus.lastKey = infraredID;
}



 

Note that some commands should work in continuous while the user keep them pressed (e.g. the +/- buttons) In the cases instead where the command should be pressed once, the control on the lastKey (the previous key pressed) act as a debouncing method avoiding that pressing continuously a button (e.g. the Power button) generates problems.

 

For more details after this short introduction I suggest to see in details the sources documentation for further information.

I've been a little sick this week and I haven't been able to work too intensely on PizzaPi. I did get the parts I ordered. I haven't tested the temp probe, but I'll post more about that soon. The pizza delivery bag was totally disgusting. It did say "used" but I kind of expected at least that they'd wash it! It had a GIANT tomato stain on the inside. After washing it twice, once with the stain inside, once with the stain on the outside, it still remains. I think I will have to scrub it to get it out. That wasn't the worse of it. The worse was the stench that came out of the packing. I can't believe anyone could tolerate that and stick it in a tiny USPS envelope.  At least it no longer smells.

 

In between the horrible pain in my head I've worked a bit more on the sensor code. I have to say, the code is very straight forward. I have found some curious anamolies with the sensor data coming from the accelerometer on the Xtrinsic board. Sometimes the reading is fairly steady and I get the expected 1-g force coming down the z-axis. Then I'll get a blip where there is some factitious g-force spread across all three axes. The next step is to look at the code for the car demo that comes in the install package. There must be something pre-written that handles calibration.

 

Otherwise, that's about it for now. Working a bit slow, I know the deadline is fast approaching. I will be getting some more extensive time off soon, so I'll have to make rapid progress then. The upside is that it's all pretty much a software issue from here on out.

 

Oh! One thing that occurred to me is that a pizza delivery bag generally hosts two, three, or more pizzas. How to keep track of all of them if they go to different customers? Initially I imagined that this PizzaPi would be a new and improved box. But then I realized that you really can't replace the cardboard because it's cheap and everyone likes having something to keep the pizza in. You can't really give a special box to the customer, that would be too expensive. So I'm thinking about making one of the Raspberry Pis actually fit onto the cardboard box and act as a tracker, or maybe another solution would be RFID of some sort...just thinking out loud. I'll get this sorted!

 

I've got to get some rest but I'll be back with another post soon.

Introduction

Meditech device has been  though to be as simple as possible for the user. It is oriented to users that does not need having some kind of IT knowledge and its interface should be extremely simple to use. Usability is one of the most important aspects for two reasons: The possible conditions of use and the accessibility of the device to non-specialized users. Users interact with the device through three components: the controller, the LCD color display and the status LCD alphanumeric display on the control panel. Plus the use of the probes, that are non-invasive medical devices. To use the probe correctly to acquire information from the subject it is expected that the operator has a specific knowledge while the control of the entire system does not require complex training.

 

The controller

IR-Controller.jpgThe infrared controller is one of the innovative approaches that has been adopted to reach this goal. Meditech is a semi automatic system for medial patient data acquisition in extreme conditions or difficult environments; in most of the cases one of the key factors to reach a correct diagnosis is the ability to collect a wide number of data on the patient health status as fast as possible.

The user interaction is simple and strictly oriented to the use of the probes. In fact the data storage, the connection between the internal components and all the tasks that contribute to the creation of the diagnostic visualization and storage of the information are in charge of the system. The user should simply press few buttons, launch a series of chained tasks and manage the probe.

 

Beside the usability the choice of a short range infrared device has the advantage to be managed nearby the patient; the operator should be in the condition to dedicate more attention to the medical diagnostic and first aid activity then to control the device itself.

The device buttons has been divided in usage areas that can assume different meaning depending on task Meditech is executing but are always coherent. As shown in the image these subdivision areas are the following:

 

Power off

It is the power off button. When pressed initiate a full Meditech shutdown process in a secure way avoiding data loss. This action is not reversible and when started can't be stopped.

Note: The power-off button only set the shutdown request. To be effective this actions should be followed by the Ok confirmation button. If any other button is pressed the request is aborted.

 

Reload initial state

This button reset the entire Meditech system to the initial (power on) condition. The actual meaningful parameters are saved avoiding data loss. This action is not reversible and when started can't be stopped.

Note: The power-off button only set the shutdown request. To be effective this actions should be followed by the Ok confirmation button. If any other button is pressed the request is aborted.

 

Direct commands

Every numeric button 0-9 is associated to a direct command to activate a specific probe. The actual beta version has the following associations:

[1] Stethoscope [2] Blood pressure [3] Heart beat [4] Body temperature [5] E.C.G.

 

Mute voice

By default most of the actions of the Meditech device are spoken by a synthetic voice through the two speakers on the control panel. This button enable/disable the voice messages in any moment. The setting of this parameter is persistent at the further work sessions.

 

Generic +/- buttons

The controller includes two set of buttons to increase / decrease interactively some data values, depending on the task in execution.

 

Confirm

The confirm OK button should be used for confirmation of tasks that requires double buttons (i.e. Power off and Reload initial state)

 

Jog control

The jog control button set is used to manage four directions movements.

 

Direct shortcuts

The direct shortcuts buttons are used to activate high priority surrounding functions that are always available, despite what is the task in execution.

 

Interactivity

The following short video shows a test example of the performances of the controller when the user interact with the system.

 

Again I apologize for being late on blogging. Unfortunately my accident included some damage to my eye. My sight is almost back to normal. I had double vision for some time : C

 

Main Components have come together:

 

My goal is to automate the processes as much as possible. I already have the camera installed with dropbox and now can load the pictures to the cloud and access the pictures on my laptop and Blackberry.

 

We were given the Raspberry Pi B+ and the Raspberry Pi2 to design our concepts with. The night camera is on the first Raspberry Pi 2 with the Microstack GPS unit. This is a great design if you have not purchased one you should try it out. The speed is 6 times faster. The cable ports have been changed so you have a nicer alignment of cables for power and display. I tried but could not get the accelerometer to work. IMG_20150712_104513.jpg

 

The second Raspberry Pi contains the GertBot and a second camera. The GertBot will be used to control a robot chassis to provide movement. I will be using something like this from Amazon. I know I will be stacking some boards on top of each other but my roommate and I will figure out the logistics. IMG_20150712_110339.jpg

 

gorobot.jpg

 

The third Raspberry Pi contains the PiFace Control and Display. I wanted to use the display for something cool related to the project. I decided to try Snap Camera and could now control the camera without a keyboard or monitor or mouse. May be a fit for the project.

 

When the application boots the top left corner shows how many pictures have been taken and the upper right shows how many pictures can be taken. The bottom left shows the mode and the bottom right shows the options for that mode. By pressing the rocket switch you can take a picture.

 

IMG_20150320_224745.jpg

 

Navigation:

 

I played with a variety of GPS data from the Microstack GPS unit. I did run the command and went for a walk with the GPS unit:

 

gpxlogger –f test.gpx

This was the result when I uploaded the .gpx file to Google Earth:

 

Screenshot (46).png

 

 

But I don’t want to have to upload the .gpx file manually. I want an automatic upload to Google Earth from the Raspberry Pi every 5 seconds to show the position and path of the Raspberry Pi. So I set up a kml file to refresh Google Earth with the location. I also loaded the Google Earth plugin to access the location and path on any smart phone. The latter I’m still working on. Here’s a pic of the kml file at work. Not what I expected! I took the Pi for a short walk and seen to be all over the place. Okay more to come !

Screenshot (49).png

Previous posts for this project:

 

 

Project Update

 

For this week's update, I worked on bringing the different components of the desk controls in a smaller and less messy form.

 

Making use of a prototyping board, the breakout boards I used and some stackable headers, the result is rather compact. As you'll see, I replaced the B+ for an A+, and the WiPi for a smaller wifi dongle.

 

Enjoy the gallery

 

{gallery} PiDesk

photo 1.JPG

Prototyping board: Started from a prototyping board for Raspberry Pi, combined with Arduino stackable headers

photo 2.JPG

Headers: Not having other stackable headers at my disposal, I used a combination of 1x6 and 1x8 stackable Arduino headers to create a 2x20 header

photo 3.JPG

Test: Testing the headers before soldering them on. Fitting the headers required some sanding on the sides.

photo 4.JPG

Capacitive touch: desoldered the headers on the breakout board to fit new, straight ones.

photo 5.JPG

Boards: The Pi and two add-on boards providing all the necessary features for the desk controls.

photo 11.JPG

RPi A+: In charge of providing wifi connectivity via USB and control add-on boards via GPIO pins.

photo 10.JPG

Proto board: In charge of capacitive touch controls, NeoPixels and audio amplification. Still requires actual soldering of the breakout boards.

photo 9.JPG

Gertbot: In charge of stepper motors and end stops (limit switches).

photo 6.JPG

Stack: The stacked result, providing the full solution.

photo 8.JPG

Stack: The stacked result, providing the full solution.

Here is video of the PiFace LCD menu program in action

 

Hi, again.

 

As promised, here is a video showing the sort of responses that you can expect to get from running the code on GitHub at https://github.com/TaoDude/Shared_I_Ching.git

 

Please read the Readme note about disabling the IR receiver code before running the software, or you will receive the error that Enrico describes in his Comment on my Part I update from Sunday.

 

Introduction

One of the main characteristics of the control panel features - controlled by the ChipKit PI board - is that it supervise all the Meditech status changes, manages the alarms and does not need a control menu. Despite what is shown on the LCD color screen display - controlled by the RPI master Raspberry PI - the control panel is autonomous supporting a bidirectional communication meta-language with the RPI master. In this scenario the LCD display will constantly show the most updated useful information reflecting the current status of the probes and the entire Meditech device.

 

The control panel LCD display

The control panel LCD alphanumeric display receives the strings to be shown in the various conditions directly from the RPI master device; this has the advantage to reduce the code size of the micro controller board and in the meantime can be easily localized for different countries.

 

To reach this goal in a fast and reliable way, every different status to be shown should follow a specific architecture taking in account of the size limits of the hardware: 20 characters x 2 lines only. These are sufficient for spot information and dome frequently updated data i.e. the internal temperature of the Meditech device. In addition depending on the probe that is currently selected, when needed the control panel analog potentiometer can be used for some signal / level calibration with an immediate feedback.

 

To make possible this behavior with a reasonably small amount of code on the ChipKit board I have introduced the use of a templates for every composite display setting that should be presented on the LCD display.

 

How LCD templates are coded

LCD Templates are defined as a series of different objects in the LCDTemplates class. This reduces the LCD definition of a template to a simple case switch. Depending on the selected template, all the fields positions are defined as shown in the following scriptlet:

 

case TID_HEARTBEAT:
      fields.row[HEARTBEAT_TITLE] = 0;
      fields.col[HEARTBEAT_TITLE] = 0;
      fields.row[HEARTBEAT_SPOT] = 1;
      fields.col[HEARTBEAT_SPOT] = 0;
      fields.row[HEARTBEAT_SPOTVAL] = 1;
      fields.col[HEARTBEAT_SPOTVAL] = 5;
      fields.row[HEARTBEAT_AVERAGE] = 1;
      fields.col[HEARTBEAT_AVERAGE] = 10;
      fields.row[HEARTBEAT_AVERAGEVAL] = 1;
      fields.col[HEARTBEAT_AVERAGEVAL] = 15;
      numFields = HEARTBEAT_FIELDS;
    break;

 

As you can see, the advantage is that while the entire LCD screen content is described, only few integers are used. For the better readability every name is defined with a symbolic constant in the corresponding LCDTemplates.h header file (see below).

 

//! Heartbeat frequency template
#define TID_HEARTBEAT 2
#define HEARTBEAT_FIELDS 5
#define HEARTBEAT_TITLE 0
#define HEARTBEAT_SPOT 1
#define HEARTBEAT_SPOTVAL 2
#define HEARTBEAT_AVERAGE 3
#define HEARTBEAT_AVERAGEVAL 4

 

The variable number of fields in every template is represented by an array of the simple field structure as shown in the following scriptlet

 

typedef struct LCDTemplateField {
  int row[6];       ///< Field row
  int col[6];       ///< Field column
} field;

 

Thus every LCD template is encoded with its own ID (in the example above we have used the TID_HEARBEAT ID) there are two further simplifications in the mechanism, improving the response of the system and simplifying the communication.

 

  1. Accordingly with this case example, the RPI master send the 'L' command with the sequence including the Template ID to be used and only the fields content in the same order as they are defined in the class template: @L;02;"Heart Beat";"Spot";"110";"Avg.";"107"
  2. The class and header can be used specular in the RPI master communication process to create the commands. The only difference is that the master also includes the strings definitions sent to the control panel board for visualisation.

 

Template examples

The following images shows a gallery of templates generated by the commands sent to the control panel by the RPI master.

{gallery:width=640,height=480} Control Panel LCD Template
IMG_20150716_112859702.jpgIMG_20150716_110520802.jpgIMG_20150716_113104053.jpgIMG_20150716_112927046.jpgIMG_20150716_113131547.jpg

 

Reference

 

 

A preview copy of the documentation is attached below (PDF format)

I thought this week I would share my adventure into USB enumeration. As I have mentioned in a previous post I am using the following USB/Serial converters

USB to RS232 Cable (Product LinkProduct Link)

USB to RS422 cable (Product LinkProduct Link)

When these cables are plugged in, the system generates a ttyUSBx device in the /dev directory. Serial USB devices are added in the order in which they are recognized, so the first device will be ttyUSB0, the second will be ttyUSB1 and so on. If the cables are plugged in before boot up, it does not seem to cause any issue – the devices are assigned like I need them to be. Although, from what I have read there is no guarantee that it will work like I need it to every time. If they are plugged in after boot and if they are not plugged in in the correct order, they will be assigned differently than I need. Since I need to communicate to a SLC PLC thrugh the RS232 cable and an MTrim controller through the RS422 cable, I need to be able to know which port each is on. If I have written my program to access the RS232 device on /dev/ttyUSB0 and to access the RS422 device on /dev/ttyUSB1 and the port assignments get reversed because of the order they were recognized, my program will no longer work.

Below is an application note from FTDI that describes the USB enumeration process:

http://www.ftdichip.com/Support/Documents/TechnicalNotes/TN_113_Simplified%20Description%20of%20USB%20Device%20Enumeration.pdf

 

I need a way to permanently set the USB ports so that my program can reliably access the correct ports every time. My search led me to Udev. Udev is Linux's device manager which supports persistent device naming that does not depend on the order in which the devices are plugged into the system or the order in which they are recognized at boot. Having persistently named device nodes has the advantage that each device can be accessed by its persistent name every time, e.g. /dev/rs232 and /dev/rs422.


So how do you actually do this? Well,from the udev man page:

          The udev daemon, udevd(8), receives device uevents directly from the kernel whenever a device is added or removed from the system, or it

          changes its state. When udev receives a device event, it matches its configured set of rules against various device attributes to identify

          the device. Rules that match may provide additional device information to be stored in the udev database or to be used to create meaningful

          symlink names.


So udev relies on rules that tell it how to name our devices. The following link is an excellent resource in developing rules:

http://reactivated.net/writing_udev_rules.html                  

   

 

Here are the steps that I followed to set up the devices:

1. Plug in the RS232 and RS422 cables

2. Run the following command, to list all USB devices:

lsusb





 

you should see an output similar to this:

Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp.
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
Bus 001 Device 004: ID 413c:1005 Dell Computer Corp. Multimedia Pro Keyboard Hub
Bus 001 Device 005: ID 046d:c05a Logitech, Inc. Optical Mouse M90
Bus 001 Device 009: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
Bus 001 Device 010: ID 0403:6001 Future Technology Devices International, Ltd FT232 USB-Serial (UART) IC
Bus 001 Device 006: ID 413c:2011 Dell Computer Corp. Multimedia Pro Keyboard





I am interested in Devices 009/010 - the FTDI USB-serial cables. Both devices use FTDI's USB-to-serial converter with the same Vendor and Product ID, so we need some more information to distinguish one from the other.

 

3. To find that extra bit of information, type the following command

udevadm info --name=/dev/ttyUSB0 --attribute-walk





udevadm starts with the device specified by the devpath and then walks up the chain of parent devices. It prints all the possible attributes in the udev rules key format. A rule to match can be composed by the attributes of the device and the attributes from one single parent device. If you mix and match from multiple parents the rule will not work.

Here is a snippet of the output

  looking at device '/devices/platform/bcm2708_usb/usb1/1-1/1-1.5/1-1.5:1.0/ttyUSB0/tty/ttyUSB0':
    KERNEL=="ttyUSB0"
    SUBSYSTEM=="tty"
    DRIVER==""
 
  looking at parent device '/devices/platform/bcm2708_usb/usb1/1-1/1-1.5/1-1.5:1.0/ttyUSB0':
    KERNELS=="ttyUSB0"
    SUBSYSTEMS=="usb-serial"
    DRIVERS=="ftdi_sio"
    ATTRS{port_number}=="0"
    ATTRS{latency_timer}=="1"
 
  looking at parent device '/devices/platform/bcm2708_usb/usb1/1-1/1-1.5/1-1.5:1.0':
    KERNELS=="1-1.5:1.0"
    SUBSYSTEMS=="usb"
    DRIVERS=="ftdi_sio"
    ATTRS{bInterfaceClass}=="ff"
    ATTRS{bInterfaceSubClass}=="ff"
    ATTRS{bInterfaceProtocol}=="ff"
    ATTRS{bNumEndpoints}=="02"
    ATTRS{supports_autosuspend}=="1"
    ATTRS{bAlternateSetting}==" 0"
    ATTRS{bInterfaceNumber}=="00"
    ATTRS{interface}=="USB-RS422 Cable"
 
  looking at parent device '/devices/platform/bcm2708_usb/usb1/1-1/1-1.5':
    KERNELS=="1-1.5"
    SUBSYSTEMS=="usb"
    DRIVERS=="usb"
    ATTRS{bDeviceSubClass}=="00"
    ATTRS{bDeviceProtocol}=="00"
    ATTRS{devpath}=="1.5"
    ATTRS{idVendor}=="0403"
    ATTRS{speed}=="12"
    ATTRS{bNumInterfaces}==" 1"
    ATTRS{bConfigurationValue}=="1"
    ATTRS{bMaxPacketSize0}=="8"
    ATTRS{busnum}=="1"
    ATTRS{devnum}=="9"
    ATTRS{configuration}==""
    ATTRS{bMaxPower}=="300mA"
    ATTRS{authorized}=="1"
    ATTRS{bmAttributes}=="80"
    ATTRS{bNumConfigurations}=="1"
    ATTRS{maxchild}=="0"
    ATTRS{bcdDevice}=="0600"
    ATTRS{avoid_reset_quirk}=="0"
    ATTRS{quirks}=="0x0"
    ATTRS{serial}=="FTX25K1F"
    ATTRS{version}==" 2.00"
    ATTRS{urbnum}=="16"
    ATTRS{ltm_capable}=="no"
    ATTRS{manufacturer}=="FTDI"
    ATTRS{removable}=="removable"
    ATTRS{idProduct}=="6001"
    ATTRS{bDeviceClass}=="00"
    ATTRS{product}=="USB-RS422 Cable" 





There are a number of unique identifiers that I could use in my rule, the most obvious being the ATTR{serial}, but the end product of this project will be used in a production environment and duplicated many times. I don't want to have to build a new rule for every system I put out on the manufacturing floor. There is also the possibility that a cable could go bad and would need to be replaced with another cable with a different ATTR{serial} and the rule would need to be updated. I was able to find a solution that would only require me to label the USB ports, such that the RS232 cable would be attached to only 1 particular USB port and the RS422 cable would be attached to only 1 particular port. To do this we need to look at level 4 of the output. In particular this line:

 

KERNELS=="1-1.5"



This line shows us that the the cable on tty/USB0 is on port 5 (the 5 in 1.5) of bus 1 (the 1 in 1-1). So if we build our rule with this we can make sure that if the cable is connected to port 5 that the device will be assigned to the RS-422 device. I did the same thing for ttyUSB1 and found it to be on port 4 of bus1 (KERNELS=="1-1.4"). I figured out the ports by connecting the cables to different USB ports on the PI. On the PI2 I found that the ports went from 2-5, with port 2 being on the lower left, port 3 on the top left, port 4 on the top right, and port 5 on the bottom right.

 

4. Create the rule.

 

udevd rules are found in /etc/udev/rules.d directory. I created a file in that directory called 99_usbdevices.rules.

 

KERNELS=="1-1.5", SUBSYSTEMS=="usb", SYMLINK+="rs422"
KERNELS=="1-1.4", SUBSYSTEMS=="usb", SYMLINK+="rs232"




Now I can label port 4 for RS232 and port 5 for RS422 and not worry about the order in which the devices are recognized for USB enumeration. My program will access these devices with the new symbolic links /dev/rs422 and /dev/rs232



 


Welcome to crunch time! Since my last posting until day eighty has been, to say the least, challenging. After partially constructing the Picorder in its case, all sorts of unknowns have came to light. I have practically had to throw out all previously conducted testing of hardware and software and start over. That which works in a "black box" environment, rarely functions in the same manner as a complete unit or system. That saying about inventions being 99% perspiration and 1% inspiration holds very true to form!

 

When I previously tested the temperature and humidity component of the Picorder on the bench, it worked flawlessly. Later on, I tested a PCD8544 display for functionality which worked fine, but later decided to go with a full 2.8" 320 x 240 TFT display instead of the smaller screen. Sound testing of the small amplifier I'm using worked fine when I triggered GPIO pins to play pre-recorded sound bytes stored on the SD card. I followed that testing with a flame detector which textually announced the presence or lack of flame displayed on the TFT display and PC.

 

In between tests, I incorporated both an alcohol and a CO2 sensor on the case as I prepared to get the most sensor detection built into the unit that I had physical space. These two devices had operational requirements that I had not previously anticipated. While I had not blogged about it, I had been planning on using either a 6vdc, 4xAA cell battery to power the unit, or possibly at least a 7.5vdc Nicad or lithium cellpack. In order to use either of these power systems, their output would need to be regulated. The Pi requires 5vdc@750ma plus the display, the sound amplifier requires 1.5vdc, and the two sensors even more. To accomodate these requirements I installed, so far, a 7805 voltage regulator to satisfy much of the requirement. I am still ineffective at draining the 1.5vdc from the power supply. As for the gas sensors, they both required additional power to be supplied to heating elements. These elements required 5v to 25v, dc or ac to operate and up to 48 hours of uptime to stabilize. Since the Picorder concept, in the tradition of Star Trek TOS, was to construct a sensing device to be used on unknown worlds, to determine immediate conditions capable to support human life for exploration, and to record the results for further analysis, it became obvious to abandon the use of these two sensors due to their excessive power use and warm-up period. I am now faced with finding other sensors to replace these two that will function in the same capacity or substitute other types of sensors with other capabilities.

 

My intent with the development of the Picorder is to test and record such readings as temperature, humidity, flame, sound, gases, and distance to objects. These were some of the elements and conditions we've seen the landing party characters from Star Trek record while exploring distant planets on their Away Missions. The original tricorder device tested for conditions such as these and did not rely on GPS, the internet, transceivers, satellites, external power systems, etc, to do so. The tricorder is a self-contained scanning, computing and recording device used for immediate detection and future extensive analysis. These readings and others like them needed to be analyzed immediately to avoid or prevent the threats and dangers of unknown planetary conditions.

 

Bench testing of the individual components and processes had been going well. Individual tests with the hardware and software proved promising. The expected reactions and results of the tests occurred as predicted. I've been using the Python code only because I started with it. In some ways, the formatting of the code is most frustrating for me! Unfortunately I do not know C, C+,C++, bash, etc. I am not software savvy with the various shells, languages and scripting methods, and to get this far with the project has been truly amazing. Consolidating the software code to function as desired with all sensors collectively is taking greater effort than even the physical construction of the unit. If ever I needed a miracle to complete ontime, this is the time for one!

 

Today I find myself removing the two gas sensors and needing to replace them with others. Those are the two .5 inch diameter brown cylinders with the silver screen in the previous photos I've posted. Leaving them out is not desirable since the testing of harmful gasses to human life would be paramount on any expedition of any planetary body exploration. So at this late date of the competition, I need to find a viable alternative for the gas sensors. I also need to modify the case to accommodate their replacements once determined and acquired. On top of everything else mentioned, I changed out the Raspberry Pi model B and replced it with the model B+ so I could use the extra GPIO pins made unusable and covered by the header connector of the display.

 

I'm enclosing the code being used so far. It is not in any particular scheme or flow for the device. I just want to put it out there. Obviously I need to consolidate it and work it into a usable format. This is my greatest challenge throughout the entire contest since I don't have a team working with me. One of my biggest concerns is the various libraries and their locations on the SD card. Pointing to them within the software construct is of paramount importance. Referencing those libraries at the appropriate times will be necessary for the recording, storing and displaying of the sensor readings.

 

 

Any suggestions or inclusions by any 'code experts' out there would be greatly appreciated and acknowledged!

 

 

So as of Day 80, reengineering, reformatting, redesigning, replacing, reevaluation and reassessment are the topics of discussion and direction moving forward. The rewards of Science, Technology, Engineering, and Mechanics are unsurpassed in any endeavor.

 

 

Sample code:

##########################################################
# These are excerpts from scripts found on line.         #
# Authorship is either unknown, or not been identified   #
# in found scripts. Parts of those scripts are used here,#
# but none in their entirety or original format.         #
# That which is commented out has been done so in order  #
# to test separate segments of the code. Other sections  #
# are general comment statements to assist in writing.   #
##########################################################


###############################################################################
# Authorship applies to only sections of the Adafruit_DHT, temp/humidity code #
# Copyright (c) 2014 Adafruit Industries      #
# by Author: Tony DiCola      #
###############################################################################
#!/usr/bin/python
#!/usr/bin/env python
#import os
import Adafruit_DHT
#import Adafruit_Python_DHT
# Sensor should be set to Adafruit_DHT.DHT11,
# Adafruit_DHT.DHT22, or Adafruit_DHT.AM2302.
# Copyright (c) 2014 Adafruit Industries
# Author: Tony DiCola


# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:


# The above copyright notice and this permission notice shall be included in all
# copies or substantial portions of the Software.


# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
###############################################################################
###############################################################################




# for instance, using a Raspberry Pi with DHT sensor
# connected to pin 19.


from time import sleep
import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)
GPIO.setup(13, GPIO.IN) # Flame detect
GPIO.setup(18, GPIO.IN)
GPIO.setup(19, GPIO.IN) # Temp, Humidity
#GPIO.setup(21, GPIO.IN)
GPIO.setup(24, GPIO.IN)
GPIO.setup(25, GPIO.IN)


pin = 19
sens = Adafruit_DHT.DHT11


# Take a sensor reading.  The read_retry method which will retry up
# to 15 times to get a sensor reading (2 seconds between retries).


humidity, temperature = Adafruit_DHT.read_retry(sens, pin)


if humidity is not None and temperature is not None:
  print 'Temp={0:0.1f}*C  Humidity={1:0.1f}%'.format(temperature, humidity)
else:
         print 'Obtaining reading. Please wait!'
####################################################################
####################################################################


#input = GPIO.input(13)


################################
## Flame Sensor read routine  ##
################################


#import RPi.GPIO as GPIO
#GPIO.setmode(GPIO.BCM)
#GPIO.setup(13,GPIO.IN)
#input = GPIO.input(13)
while True:
  if (GPIO.input(13)):
    print("Flame detected, take precautions")
  else:
#    print("All clear, no flame detected")
#    print("")
#  sleep (0.1);
#clear




#while True:


#  if (GPIO.input(13)):
#    print("Flame Detected")
# else:
# print("Not Detected")


#    if (GPIO.input(18) == False):
#        os.system('mpg123 -q twohours.mp3 &')


#   if (GPIO.input(21) == False):
# os.system('mpg123 -q access.mp3 &')


#   if (GPIO.input(24) == False):
# os.system('mpg123 -q defense.mp3 &')


#   if (GPIO.input(25)== False):
# os.system('mpg123 -q Destruct.mp3 &')


# Note: sometimes you won't get a reading and
# the results will be null (because Linux can't
# guarantee the timing of calls to read the sensor).
# If this happens, try again.


# might be   time.sleep(0.1);
#   sleep(0.1);
####################################################################
####################################################################










####################################################################
####################################################################
#!/usr/bin/python


# remember to change the GPIO values below to match your sensors
# GPIO output = the pin that's connected to "Trig" on the sensor
# GPIO input = the pin that's connected to "Echo" on the sensor


##    def reading(sensor):
##    import time
##    import RPi.GPIO as GPIO
   
    # Disable any warning message such as GPIO pins in use
##    GPIO.setwarnings(False)
   
    # use the values of the GPIO pins, and not the actual pin number
    # so if you connect to GPIO 25 which is on pin number 22, the
    # reference in this code is 25, which is the number of the GPIO
    # port and not the number of the physical pin
##    GPIO.setmode(GPIO.BCM)
   
##   if sensor == 0:
       
        # point the software to the GPIO pins the sensor is using
        # change these values to the pins you are using
        # GPIO output = the pin that's connected to "Trig" on the sensor
        # GPIO input = the pin that's connected to "Echo" on the sensor
        GPIO.setup(26,GPIO.OUT)
        GPIO.setup(5,GPIO.IN)
        GPIO.output(26,GPIO.LOW)
       
        # found that the sensor can crash if there isn't a delay here
        # no idea why. If you have odd crashing issues, increase delay
        time.sleep(0.5)
       
        # sensor manual says a pulse length of 10Us will trigger the
        # sensor to transmit 8 cycles of ultrasonic burst at 40kHz and
        # wait for the reflected ultrasonic burst to be received
       
        # to get a pulse length of 10Us we need to start the pulse, then
        # wait for 10 microseconds, then stop the pulse. This will
        # result in the pulse length being 10Us.
       
        # start the pulse on the GPIO pin
        # change this value to the pin you are using
        # GPIO output = the pin that's connected to "Trig" on the sensor
        GPIO.output(26, True)
       
        # wait 10 micro seconds (this is 0.00001 seconds) so the pulse
        # length is 10Us as the sensor expects
        time.sleep(0.00001)
       
        # stop the pulse after the time above has passed
        # change this value to the pin you are using
        # GPIO output = the pin that's connected to "Trig" on the sensor
        GPIO.output(26, False)


        # listen to the input pin. 0 means nothing is happening. Once a
        # signal is received the value will be 1 so the while loop
        # stops and has the last recorded time the signal was 0
        # change this value to the pin you are using
        # GPIO input = the pin that's connected to "Echo" on the sensor
        while GPIO.input(5) == 0:
          signaloff = time.time()
       
        # listen to the input pin. Once a signal is received, record the
        # time the signal came through
        # change this value to the pin you are using
        # GPIO input = the pin that's connected to "Echo" on the sensor
        while GPIO.input(5) == 1:
          signalon = time.time()
       
        # work out the difference in the two recorded times above to
        # calculate the distance of an object in front of the sensor
        timepassed = signalon - signaloff
       
        # we now have our distance but it's not in a useful unit of
        # measurement. So now we convert this distance into centimetres
        distance = timepassed * 17000
       
        # return the distance of an object in front of the sensor in cm
##        return distance
       
        # we're no longer using the GPIO, so tell software we're done
        GPIO.cleanup()


##    else:
        print "Incorrect usonic() function varible."


       
print reading(0)
####################################################################
####################################################################








####################################################################
####################################################################
#!/usr/bin/python
import math
f = open('mydata.dat', 'w')
# Loop
for degrees in range(720):
  # Generate three data points
  si = math.sin(math.radians(degrees))
  co = 0.5 * math.cos(math.radians(degrees))
  if si>0:
    sq = 0.6
  else:
    sq = -0.6
  # Write 3 data points to text file
  data = "{} {} {} {}\n".format(degrees,si,co,sq)
  f.write(data)
f.close()




#The entire script can be downloaded from here:
#wget https://bitbucket.org/MattHawkinsUK/rpispy-misc/raw/master/gnuplot/gnuplot_generate_data.py
#
# To run the code:
#sudo python gnuplot_generate_data.py
#
###
#
# Then start 'startx'
#
#startx
#
# Then type:
#plot "mydata.dat"
#
#
#plot "mydata.dat" using 1:2, "mydata.dat" using 1:3, "mydata.dat" using 1:4
#
#
# Setting a Plot Title and Axis Labels
#
#
# To change the plot title you can type the following command :
#
#set title "Example Plot"
#To change the data labels you can modify your plot command :
#
#plot "mydata.dat" using 1:2 title "Sin", "mydata.dat" using 1:3 title "Cos"
#This can be abbreviated to :
#
#plot "mydata.dat" u 1:2 t "Sin", "mydata.dat" u 1:3 t "Cos"
#To change the axis labels you can use the following commands :
#
#set xlabel "Minutes (mins)"
#set ylabel "Temperature (degrees)"
#
#
#Lines and Points


#You can also change the way the data points are represented on the graph. By default points are used. You can change the style to “lines” or “linespoints” using the “with” keyword :
#
#plot "mydata.dat" u 1:2 t "Sin", "mydata.dat" u 1:3 t "Cos" with lines
#This makes the square wave look nicer.
#
#
#
####################################################################
####################################################################




####################################################################
####################################################################
#PyAudio code for recording kept for reference:
#import pyaudio
#import sys


#chunk = 1024
#FORMAT = pyaudio.paInt16
#CHANNELS = 1
#RATE = 44100
#RECORD_SECONDS = 5


#p = pyaudio.PyAudio()


#stream = p.open(format=FORMAT,
#                channels=CHANNELS,
#                rate=RATE,
#                input=True,
#                output=True,
#                frames_per_buffer=chunk)


#print "* recording"
#for i in range(0, 44100 / chunk * RECORD_SECONDS):
#    data = stream.read(chunk)
    # check for silence here by comparing the level with 0 (or some threshold) for
    # the contents of data.
    # then write data or not to a file


#print "* done"


#stream.stop_stream()
#stream.close()
#p.terminate()
####################################################################
####################################################################

Introduction

In the previous post it was explained how the control panel communication between the ChipKit PI and RPI master (Raspberry PI 2) works, based on a rigid syntax sequential command language. The hardware layer of the communication between the two boards implement the TTL direct serial communication at the speed of 38.400 bps. This is an average speed sufficiently high to grant a good data exchange between the two boards without penalising the interrupt-based tasks that are managed by the ChipKit board during the remaining free time processing of the PIC microcontroller (running at 80 MHz)

The tests described to see the protocol in action and have an idea of the response time while the commands are processed are done with the RPI master machine overclocked at 900 MHz (the higher speed without an extra voltage setting to the Raspberry PI processor).

 

Test commands

A series of test commands has been prepared and sent to the ChipKit control panel controller from the raspberry PI via a remote SSH connection over LAN WiFi. On the RPI master (the sender machine) commands has been sent through the MPIDE serial communication connected to the ChipKit PI.

The commands used for test are the following:

 

@L;00;"Stethoscope";"Gain";"00027"
@L;01;"B. Pressure";"Wait...";"Min";"90";"Max";"120"
@L;02;"Heart Beat";"Spot";"110";"Avg.";"107"
@L;03;"Temperature";"Spot";"36.5";"Avg.";"37"
@L;04;"E.C.G.";"Status";"running"
@L;05;"Control Panel";"Test running"
@D;00001;00010;"Hello"


 

The template showing sequences includes the field texts to be displayed so are the longer command strings that should be used. The adopted testing parameters was the following:

 

  • On the RPI master Raspberry PI the minicom terminal has been used to send manually the commands [38.400 bps, 8N1] through the ChipKit serial connection /dev/ttyS0
  • For every command has been set a macro that can be enabled with [F1]...[F7] keys + [RETURN]
  • Echo has been enabled only for pasting manually the commands while when launching the macros echo is disabled
  • Two test cycles: manual pasting of every command and fast command sending via the minicom macros

 

The following image shows the macros settings for the test

Screen Shot 2015-07-13 at 08.23.59.png

 

Test cycle

The following video sows the minicom full test cycle of the commands sending and acknowledgment.

 

The send-response sequence

Every command sent to the board from the RPI master generates a returning acknowledgment string. The RPI master should parse the string to get information on the command execution status.

 

  • Ack return string is sent back after a variable delay depending on the time the requested command need for the execution so when the RPI master receives the ack response it is sure that the command has been managed by the board.
  • The Ack string contains the same number of parameters of the sent command is all the fields was ok else it contains an error code informing the RPI master of what was wrong.

 

For example sending the command

 

@L;01;"B. Pressure";"Wait...";"Min";"90";"Max";"120"

 

We are asking to the board to show the LCD display template, ID=01 with the 6 field strings B. Pressure, Wait..., Min, 90, Max, 120 If the command is completed without errors (fields and syntax are correct and there is not out-of-range data) the RPI master should expect the following Ack string:

 

:L:0:0:0:0:0:0

 

Where the command code 'L' is followed by a '0' (=parameter OK) for every parameter field sent.

If we send for example the same command with the last ';' field separator missing we get the following response:

 

@L;01;"B. Pressure";"Wait...";"Min";"90";"Max""120"

:L:0:0:0:0:0:3

 

In some cases there is not an error returned while managing the string fields. The reason is that this is a machine-to-machine language protocol so the parser excludes typical human errors, e.g. some expected parameter missing because after the commands are correctly implemented in both the sender and receiver it is impossible that these kind of errors (mostly depending on typing mistakes) occur.

The following image shows the various conditions of recognized and unrecognized errors by the parser.

Screen Shot 2015-07-13 at 09.46.14.png

 

Error codes

The error conditions recognized by the parser are the following:

 

Command completion code

COMMAND_OK 0

 

Command unknown to the parser

COMMAND_UNKNOWN 1

 

Wrong or malformed command.

This message occours when the parameters following a command are wrong, incomplete or missing.

COMMAND_WRONG 2

 

The requested parameter separator was missing

COMMAND_MISSINGSEPARATOR 3

 

The requested parameter separator was missing

COMMAND_OUT_OF_RANGE 10

 

The received subcommand is unknown

PARSER_SUBCOMMAND_UNKNOWN 4

 

Probe error conditions

COMMAND_STETHOSCOPE_PARAMERROR 5

COMMAND_ECG_PARAMERROR 6

COMMAND_PRESSURE_PARAMERROR 7

COMMAND_BODYTEMP_PARAMERROR 8

COMMAND_HEARTBEAT_PARAMERROR 9

COMMAND_WRONG_TEMPLATE 10

I had a funny glitch on one of my Raspberry Pis this weekend. Somehow the operating system corrupted and wouldn't boot anymore. Luckily it was on the one running PiFace and I have not done much with it so I didn't lose much. I should have probably run recovery mode....but I forgot. Oh well, I wiped the whole thing and reinstalled the various packages needed to run PiFace and Paho (for communicating with mosquitto, the MQTT broker). This was on an older Raspberry Pi, not on one of the new ones that came in the kit.

 

Right now I'm working on the sensor publish code. I have it sending sensor data from all of the sensors, including the GPS module that is piggy backing on Xtrinsic. All of that data is sent to mosquitto the MQTT broker and the broker then pushes it out to the subscribers (web browser, PiFace). Once I have that code done I will start working on the front-end stuff. This includes a customer web page, a client (the pizza joint) web page, and driver phone app. The back end will be the MySQL server that is already installed on RPI 2 server.

 

In other news, I made a few exciting purchases. I finally purchased a pizza delivery bag to modify. It's an actual delivery bag from Little Caesar's Pizza.

Pizza delivery bag

 

I also purchased an external temperature probe (DS18B20). I was using the temperature sensor that is built into Xtrinsic's sense board, but I noticed that it reads room temperature a little warmer than expected which means its probably getting heat from the board. Also, when I install the boards into the delivery bag, they will be separated from the pizza contents so I'm not sure how well it will sense temperature.

Temperature probe

 

Lastly, I purchased a heating element (PTC ceramic heating element 5V 176F 3W) to test out. This one is a little different from what I had been researching earlier. I decided to experiment with this one instead because the description said it heats surrounding air through convection and it stays at a constant temperature of 176 degrees F. I really have no idea how well it heats the surrounding air, but it is used for a variety of professional applications beyond being used as a foot warmer, so that seems promising. According to what I've read, food needs to be above 140 degrees F to kill bacteria. However, there needs to be a sweet spot because I don't want to cook the pizza, either. Just keep it warm. I definitely don't want to cook the cardboard box, either.

PTC Cermanic heating element

 

Another item on my list is some of that reflective lining to keep the heat in. I think I might find it at a fabric store, but I have to do some research. That's it for now...until my next post!

Introduction

As mentioned elsewhere in the previous posts the Meditech control panel is under the control of the Chipkit PI micro controller board. The board has the following roles in the architecture of the system:

 

  1. Manages the critical event alarms when a overheating occur and the lid open alert when the control panel is opened (this  influences the behaviour of the entire system).
  2. Shows a fast and updated short information on the alphanumeric LCD panel; the LCD screen instead is under the control of the RPI master showing more complex information with different update timing.
  3. Set the probes status LEDs
  4. gives immediate feedback over the active probe control (if any) via the potentiometer that assumes different functions depending on what probe the user has chosen.

 

So a part of the ChipKit micro controller firmware is controlled by periodical scheduled events (tasks) and interrupts running independently by the rest of the system and a part of the firmware executes commands (requests) sent by the RPI master (the main Raspberry PI 2 unit) and send requests to it.

To manage properly a reliable and efficient communication between the two device (control panel and master) has been defined a communication protocol with a rigid syntax. The communication process is bidirectional and any command is always acknowledged to the sender from the receiver.

Screen Shot 2015-07-12 at 21.56.43.png

Syntax

As every command has a different set of parameters (including the case of no parameters), what was needed was not a bare data exchange protocol but something more complex, a real syntax able do represent all the possible (and future) commands conditions. In short words, the assumptions are the following:

 

  • Almost all the possible types (int, long, float, strings) should be represented
  • Every command has a variable number of parameters depending on what the command do, so this aspect can't be standardized
  • The command should be simple to transmit and as fast as possible to be received and processed by the receiver
  • The syntax should support roles that can be expanded in future
  • Every command has a different timing in its execution
  • The syntax should support the implementation of future, not yet known, commands.
  • The syntax should be simple, to make the parser fast also on the - relatively - slow speed of the microcontroller.

 

By the other side we have some great advantages:

 

  • The syntax complexity does no matter as this is a machine-to-machine language
  • The syntax can be rigid: all the rules are software encoded so it does no matter how these are fixed
  • There is no need of a semantic control; these are almost all independent commands. The only option is that a command, if it is received in a wrong condition it is not executed
  • Special boolean condition and loop cycles are not needed. It is a sequential machine.

 

Note that loops and other features are supported but not needed nor used in this version as the parser support the execution of macros that can include cycle repetitions of group of commands and conditional jumps: labels,  conditional jumps and cycles are macro commands (i.e. parameters recognised by the specific command "macro"

 

Syntax rules

The syntax rules are single character operands, including the command name itself, that is the first parameter of a command string.

 

'@' - Command separator: Every command should start with this character; all the characters outside the command separator are ignored and cam be used as comments. Take in account that comment are not parsed but are sent so long comments require more transmission time. The same character is used as command terminator but it is optional as it is added by the parser automatically.

 

';' - Field separator. Every field in a command string should be separated by the field separator character.

 

'<Command Code>' The command code is a single-character command name, case-sensitive.

 

'"' - String delimiter. Every field that is a variable-length string should be in the format "string", just as in almost any programming language.

 

":" - Response separator. It is the character separating the acknowledge string sent to the sender after the parser has completed the command execution.

 

Every command can include a subcommand, processed recursively as the commands. If the parser meet an error the parsing process is immediately stopped and the acknowledge string with the command code and the error code (numeric) is sent to the sender. An exit condition with the error code 0 means that the command execution has been completed successfully.

The limits for every type of recognised fields are the following:

 

Integer: 5 characters in the form 00000

Long Integer: 7 characters in the form 0000000

Floating Point: 1 characters in the form 0000000.000

Field ID (used for row, column positions in the display): 2 characters in the form 00

Boolean: 1 character in the form 0

String: variable length between two string delimiters.

 

The general command syntax is in the following form:


@<command>[;<subcommand>][;<field>];]@

 

Commands

 

E - Enable

Enable a probe and accept setting parameters or disable the probe if already enabled. The subcommand contains the probe subcommand name

 

name: E

usage: E;<subcommand>

example: @E;S

Enable the microphonic stethoscope


The Enable command only activates the set bit of the current probe. If the enable bit is not set the corresponding display layout on the control panel LCD can't be changed due the probe-dependant settings that the probe-enabled status involves. The right method to display a probe template is to enable it then send a template command to the control panel with the display layout parameters.

 

D - Display

This is a descriptive command only, reflecting the state of a user request from the remote IR controller. The row and column values should be integers, zero-based, inside the physical limits of the LCD display.

 

name: D

usage: D;<row(int)>;<column(int)>;<string>

example: @D;01;03;"Test"


This command needs less controls than expected because errors like out of bound string length, wrong cursor position etc. never occurs using the display templates. Templates include file is the same on both the master and the micro controller with the difference that the master also includes the strings definition that are sent when a display should be drawn with a template.

 

L - LCD Template

Parameters to generate a template layout with a variable number of parameters, depending on the requested template.

name: L

usage: L;<Template ID>;[[;<Field String>];]

example: @L;05;"Panel Test";"Running"

 

If the requested layout template is a probe display template the command has effect only if the probe status bit is set to on (current probe active)

 

I - Info

Shows the current health status parameters of the control panel (temperature, fan speed, active flags etc.)

name: I

usage: I

example: @I

 

T - Test

Suspend all the active interrupts and tasks and execute a full test of the control panel.

name: T

usage: T

example: @T

 

R - Receive

Receive from the master the requested value for one of the template fields to show on the display. In most of the cases these are strings managed by the master to save memory space on the board and support the multi-language localisation.

name: R

usage: R;<parameter ID>;<value>

example: @R;03;00123

 

Subcommands

 

S - Enable/disable Stethoscope

Enable or disable the stethoscope probe.

usage: S (bool)status

parameters: the status accepted values are FLAG_ENABLE and FLAG_DISABLE

example: @E;S;001

 

G - Enable/disable E.C.G.

Enable or disable the E.C.G. probe.

usage: G (bool)status

parameters: the status accepted values are FLAG_ENABLE and FLAG_DISABLE

example: @E;G;001

 

P - Enable/disable Pressure sphygmomanometer

Enable or disable the Sphygmomanometer probe.

usage: P (bool)status

parameters: the status accepted values are FLAG_ENABLE and FLAG_DISABLE

example: @E;P;001

 

T - Enable/disable Temperature sensor

Enable or disable the body temperature probe.

usage: T (bool)status

parameters: the status accepted values are FLAG_ENABLE and FLAG_DISABLE

example: @E;T;001

 

H - Enable/disable Heart Beat sensor

Enable or disable the Heart Beat probe.

usage: H (bool)status

parameters: the status accepted values are FLAG_ENABLE and FLAG_DISABLE

example: @E;H;001

Introduction

This is the first part of a blog covering Weeks 6 & 7, as i did not have time to publish last week owing to having to complete a report for work.  Not much to report, except that i have managed to take on board some of Enrico's (Balearic Dynamics) comments on my first set of menus.

 

The PiFaceCAD is a bit cramped for what i am trying to produce, but i am getting there.  Multilevel menu code in Python is now available in a public repository on GitHub:

 

https://github.com/TaoDude/Shared_I_Ching.git:

 

Any comments are welcome.  I will post a video of what it looks like later, once i have edited it.

Previous posts for this project:

 

 

Project Update

 

I started working on the lift assembly this week. After figuring out how to mount everything to the desk, I designed a piece meant to hold the screen and attach it to two threaded rods capable of lifting it.

 

The piece was designed in Sketchup after I had measured the size of the nuts used on the threaded rods and the width of the screen assembly. This is the result:

Screen Shot 2015-07-08 at 10.55.38.pngScreen Shot 2015-07-08 at 10.55.54.png

 

There are two slots to pass the threaded rods through and to keep the nuts in place, and four holes meant to screw the piece to the bottom of the screen assembly. By having the nuts locked in place, turning the rods using a stepper motor will result in the assembly going up or down.

 

The next step was to print the piece. Something I expected would go rather smoothly ... I was wrong. Everything that could go wrong, did go wrong:

 

1) Slipping: one of the timing belts (X-axis) started slipping, resulting in inconsistent results. Perhaps the result of the high summer temperatures resulting in looser belts ?

2) Running out of filament. Annoying, but luckily, I had a spare roll. Prints will no longer be white, but light blue now!

3) Nozzle clogging. Due to incorrect bed levelling. I placed the nozzle to close to the build platform, not allowing enough material out of the nozzle. Fixed by levelling more accurately.

 

photo 1.JPGphoto 2.JPG

 

I hope I can resolve the slipping issue as soon as possible, so I can print te piece and start putting together the lift assembly! And even though the print failed, I was able to validate most of the measurements based on the first layer.

Today the parcel with the components I need for bulding the training sphere arrived

 

06 - Material.jpg

Now that I have the components, I can start making a detailed drawing of the frame.

BTW, after long thinking which material was better (either aluminium or plywood), I made the decision to use plywood since it's easy to work with and there will be no soldering issues.

Let's hope for the best!

Building APM


Since I expect I will have to make some changes to the code, I will now try to build APM fro source code. Working repository for Navio APM port is on GitHub.

I decided to build APM directly on your Raspberry Pi since it does not require to setup a cross-compiling environment and Raspberry Pi has enough computing power to make this step fast enough


Download the APM’s port for Navio:


git clone https://github.com/emlid/ardupilot.git











Switch to the 'navio' branch:

git checkout navio











Navigate to the autopilot’s directory, for example rover, run configuration and build it:

cd ardupilot/ArduCopter
make configure
make navio-heli











I'm not sure the heli configuration fits my needs, but I will try a build with this configuration, then I will change the makefile. Many other frames are supported. To build for other frame types replace heli with one of the following options:

quad tri hexa y6 octa octa-quad heli single obc nologging

 

Executable file will be placed in /tmp/APMcopter.build directory. Copy the binary from tmp directory to your home folder:

cp /tmp/APMcopter.build/APMcopter.elf /home/pi/APMcopter.elf

 

Running APM

To run APM use the following (change APMrover2.elf to ArduCopter.elf or ArduPlane.elf if needed):


sudo ./APMcopter.elf -A udp:192.168.1.2:14550






Where 192.168.1.2 is the IP address of the device with the Ground Control Station – your laptop, smartphone etc.

 

Arguments specify serial ports (TCP or UDP can be used instead of serial ports) :

  • -A is for telemetry
  • -B is for external GPS
  • -C is for secondary telemetry

If you would like to transfer secondary telemetry over the UART port on Navio you can specify it like this:

 

sudo ./APMcopter.elf -A udp:192.168.1.2:14550 -C /dev/ttyAMA0



Autostarting APM on boot

To automatically start APM on boot add the following (change -A and -C options to suit your setup) to /etc/rc.local file on your Raspberry Pi:


sudo /home/pi/APMcopter.elf -A udp:192.168.1.2:14550 -C /dev/ttyAMA0 > /home/pi/startup_log &


I am using the PiFace CAD to display the contents of a configuration file used for the Serial Master program so the user can see and change the parameters that are being used. A snippet of a config file is shown below:

 

[RS-232]
device = /dev/ttyUSB0
baudrate = 19200

[RS-422]
Device = /dev/ttyUSB1
Baudrate = 9600

 

 

I will use ConfigParser to read the configuration file.

 

I believe that a State Machine is the best way to handle the coding for the navigation and display of the different options.

 

state_machine.jpg

 

Wait – Initial State. LCD is turned off. Any button press from the CAD will move to the Menu state. Whenever there have been no button presses for 60 seconds, the state will revert back to this initial state.

 

Menu – The Menu State will allow the operator to scroll through the different ‘Sections’ of the configuration file. Sections are represented inside of ‘[‘ and ‘]’ in the configuration file. The rocker switch can be pushed left or right to scroll through the different section names. Depressing the rocker switch will move to the Sections State

 

Sections – The Sections State will show the different options available for the selected section. The

Rocker switch can be pushed left or right to scroll through the different options available in the given section. Pressing button 4 will take the operator back to the Sections State

 

Options – The Options State will allow the operator to scroll through the different sub-options available for the given option. The rocker switch can be pushed left or right to scroll through the different sub-options. Depressing the rocker switch will move the operator to the Editing State. Pressing Button 4 will move the operator back to the Sections State.

 

Editing – The Editing State will allow the operator to choose the character that they want to change or they can move to the space following the last character to append a character. The operator can use the rocker switch to move the cursor left or right to choose the desired character. Depressing the rocker commit the change and move the user back to the Options State. Button 4 will return the user to the Options State without committing the change. Pressing Button 0 will allow the operator to cycle through capital letters. Button  1 will allow cycling through lower case letters. Button 2 will allow cycling through numbers. Button 3 will allow cycling through punctuation.

 

Scanning – The Scanning State allows the operator to cycle through the characters selected by the previous button press. The rocker switch can be moved left or right to cycle through the selections. Depressing the rocker switch will take the operator back to the Editing State with the change ready to be committed. Pressing Button 4 will take the operator back to the Editing State without showing the change.

 

Code for this part of the project can be found at:

 

https://github.com/frellwan/SciFy-Pi.git  in the PiFace directory

 

 

 

 

The PiFace Control and Display connects to the Raspberry Pi using the expansion connector (GPIO). Follow the below steps to connect the PiFace CAD:

  • First disconnect power from the RaspberryPi.
  • Take special care to make sure all the RaspberryPi expansion pins are lined up with the holes on the PiFace Control and Display socket. For the Pi2 there are more header pins than there are holes in the PiFace CAD socket. Align the holes with the pins closest to the board edge.
  • Make sure that both lines of pins line up with both lines of holes and never force the boards together if they don’t slide smoothly.

 

 

Install the latest PiFace python software by typing the following command in a Terminal:

sudo apt-get install python{,3}-pifacecad

 

The PiFace CAD uses the SPI communication port of the Pi. The Raspian kernel comes with the SPI disabled by default. To enable the SPI port type the following command in a Terminal:

sudo raspi-config

 

This will bring up the configuration screen:

Select option 8 -  Advanced Options" to  view the list of advanced configuration options.

Choose the A5 SPI option,

set this to <Yes>

then select <OK>

then <Finish>

 

To test that everything is working, connect power to the Pi and log in. In a Terminal type:

python3   /usr/share/doc/python3-pifacecad/examples/sysinfo.py

 

Details about the Raspberry Pi’s temperature, memory and I.P. address will appear on the LCD screen.

 

 

The documentation for the PiFace CAD can be found at:

https://media.readthedocs.org/pdf/pifacecad/latest/pifacecad.pdf

 

The documentation gives enough information to get started, but it lacks a lot of the underlying information about the LCD.

 

Initially I tried to use the Scanf tool to allow editing of the configFile. I had instantiated a SwitchEventListener object in my code to navigate through the .ini file. When I wanted to edit the text, I called PiFaceCad.Tools.Scanf to allow the editing. Some very quirky things began to happen. Very few of the button press events were being captured from the edit and when the edit was finished the excess button presses were executed in my original code.

 

Digging into the source code of the PiFace, I found that the Scanf function was instantiating another SwitchEventListener object. The SwitchEventListener object subclasses PortEventListener which starts a thread to read the PiFace switches and instantiates a queue for the events. So with 2 SwitchEventListener objects alive at the same time, there were 2 processes fighting for the same resource.

 

I tried to solve this 2 different ways. The first was to rewrite the PiFace code to only instantiate a single Queue for events – basically a global queue. The PortEventListener would then use a threading.Lock() to determine who had access to the data. This worked fine, but I did not like the arrow that the ScanF function . The second option I tried was to write my own Scanf code. I ended up using my SwitchEventListener to use most of the code in the Scanf module, just bypassing the Scanf function.

 

The other issue that I had was that the debounce on the switches was allowing false events to be passed. Again digging through the code, I was able to find that one of the parameters to the register function was a ‘settling time’. I set this to 200ms and the issues all but disappeared.

Introduction

Screen Shot 2015-07-06 at 09.14.14.png

This update affects the ChipKit PI software for the control panel; the development lifecycle is part of the entire project but it is organised in a dedicated repository.

A series of general updates has been done for better reachability of the sources and documentation described in the list below:

 

  • http://meditech.balearicdynamics.com application and user manual, project documentation and technical information. The pages are under construction and only the home page is shown.
  • The GitHub repository has been organised in a better way for more readability. The master branch includes the sources updates (v 1.0 build 0023 at the actual date) while the automatically generated documentation (Doxygen) is regularly updated in the gh-pages repository.
  • The documentation is accessible also from the GithHub repository documentation pages for the better understandability. The GitHub documentation is only affected by the source code and algorithms.

 

The same methodology describe above will be adopted for all the software modules of the project.

 

Cooler fan speed control

The cooler fan speed is controlled on the temperature periodically checked by a LM32 temperature sensor positioned to the bottom of the RPI master board. The internal temperature is also shown with continuous updates on the rightmost top corner of the display. The proportional speed is set by a PWM frequency so that the RPM speed respect the spot temperature is almost continuous, following the rules described below:

 

  1. Fan Speed PWM frequency will vary between 35 and 255; lower values than 35 has no effect and the motor is always stopped.
  2. The temperature range is between 38C and 60C.
  3. A temperature under 38C keeps the fan stopped and a temperature over 60C generates a overheating error.

 

Every reading of the temperature maps a proportional updated speed (the corresponding PWM frequency) of the cooler fan. In this way, the entire temperature monitoring and control period is controlled by a single short function

 

void setFanSpeed(float temp) {

  //! The filtered temperature to control the out-of-range values
  float filteredTemp;

  // Check the temperature range
  if (temp < MIN_TEMP)
    filteredTemp = MIN_TEMP;
  else
    if (temp > MAX_TEMP)
      filteredTemp = MAX_TEMP;
      else
        filteredTemp = temp;

  int pwmSpeed = map(temp, MIN_TEMP, MAX_TEMP, MIN_FANSPEED, MAX_FANSPEED);

  SoftPWMServoPWMWrite(FAN_SPEED, pwmSpeed);
}











 

Non-invasive and simple debug logging to the serial

Logging events and program flow states as serial messages is probably one of the most efficient ways to implement fast debugging features in the methods. The problem is finding a method to disable it as simple and fast when the logging should be disabled: simple as changing a #define to #undef in a single include header.

So the DebugStrings.h file has been created, to be included in any source that should use it.

The general architecture of the debug/log header file is almost simple:

 

// #define to enable, #undef to disable
#undef __DEBUG

#ifdef __DEBUG
// Debug - log messages strings

#define DEBG_PREFIX "[DEBUG]"
#define DEBG_LIDOPEN  "LID OPEN"
#define DEBG_LIDCLOSED  "LID CLOSED"
#else
// Empty definitions if disabled
#define DEBG_PREFIX ""
#define DEBG_LIDOPEN  "
#define DEBG_LIDCLOSED  ""
#endif








 

For every log string defined, the corresponding empty definition should be created in the bottom section of the file. In every source where the debug should be - eventually - used a debug() function should be defined. It's up to you how the serial log should be sent, the following is a very simple example.

 

void debug(String msg) {
#ifdef __DEBUG
  Serial1 << DEBG_PREFIX << "> " << msg << endl;
#endif
}







 

The everywhere in the source that it is needed a runtime message sent to the serial, it is sufficient to call the function passing the message as a parameter, e.g.

 

debug("Test message");
debug(DEBG_LIDOPEN);







 

As you see above, it is not mandatory to define all the log strings in the DebugStrings.h file. It is a good solution only because when the serial logging is not needed anymore the memory space occupied by the strings is automatically freed, making the application smaller and faster.

 

Working with interrupts and tasks

There are two ChipKit core features that simplified a lot the management of the program priorities: timers and the tasks. The most important difference is that the scheduled tasks are driven by a general interrupt with an approximated triggering, but can operate on long timing in the order of seconds or more. Timers instead make available to trigger more precise events (milliseconds) along periods not greater than 90 seconds.

The ChipKit control panel application should manage two different class of tasks that in some cases has a reciprocal influence; e.g. if the Meditech panel lid is open all the other functions should stop. So the teperature status and cover lid status are checked with two interrupt Timers while the other low priority events (i.e. the display update) are controlled by tasks.

The other class of tasks that are managed by the micro controller program are the command dialog through the serial, controlled externally by the RPI master. This second groups of events is under the control of the program flow, depending on what action the user has requested to the RPI master interacting with the system so no interrupt is required.

 

The setup() function starts two timer services:

 

  // Set and start the timer for lid status
  attachCoreTimerService(isLidStatusChanged);
  // Set and start the timer for fan cooler speed regulation
  attachCoreTimerService(fanSpeedRegulation);





 

The first timer check for the lid status switch through the callback function isLidStatusChanged() every second while the second task updates the fan speed over the internal temperature every 5 seconds.

 

The control panel LCD display has some areas showing information depending on the state of the system but there are some reserver areas, i.e. the rightmost top corner that show the internal temperature every second (no matter the precise frequency this should occur). The updateDisplay() function is scheduled as a task in the setup() function on startup as shown in the code below.

 

  // Create the display update task.
  // This task updates automatically only the reserved display
  // areas, i.e. the temperature monitor and other information.
  updateDispalyTaskID = createTask(updateDisplay, TASK_UPDATEDISPLAY, TASK_ENABLE, NULL);


 

Applying this strategy the loop() function results very simple and fast:

 

/**
  \brief Main loop method

  The main application loop is interrupted by the lid open status generating
  a high priority alarm. Also the internal temperature is checked periodically
  to set the fan speed to the correct value.\n
  When serial data are present (a command waiting from the PI main) the data are
  parsed as needed.
  */
void loop(void) {
  // Check if the lid is open
  if(lidStatus == LIDCLOSED) {
    // Test only !!!
    int pValue = analogRead(CALIBRATION_POT);  // Read the pot value
    steth.updateDisplay(map(pValue, 0, ANALOGDIVIDER, MINGAIN, MAXGAIN));
    checkSerial();
  }
  else {
    // Show the error message
    lcd.clear();
    message(_LID_OPEN, 5, LCDTOPROW);
  }
}

 

The following video shows the startup sequence and the Stethoscope gain setting, while the task updates the internal temperature on the display. As the lid cover is opened the other timer immediately detects the event showing the alert on the display.

Hello, everyone! Just wanted to let you all know that I won't be posting an update until next weekend. I'm on holiday for the Independence Day weekend (and a few weekdays after that). Looking forward to writing an update soon.

Previous posts for this project:

 

 

Project Update

photo (19).JPG

 

Part of the kit we received is the Cirrus Logic Audio Card. It is an expansion board for the Raspberry Pi, that adds audio output and input with various types of connectors. I will however not end up using it in my project for the following reasons:

 

1) I originally planned to use it for the Pi2, used as a desktop computer. From what I understood from this discussion though, is that it is not yet supported on the Pi2 due to incompatible kernel versions. Users have come up with a minimalistic software image capable of using the card on the Pi 2, but it is not suited to be used as a desktop image.

 

2) The second Pi I'm using, the A+ to manage the desk controls, is compatible with the card and the software is available. The card would however be overkill, as the only audio function required is to play sounds when certain buttons are pressed. Taking into account the low cost requirements of the project, the audio card has been deemed unsuitable.

 

I searched for a cheap alternative to get amplified audio output from both Pis and came across the Adafruit breakout boards. There are two boards that seemed affordable and suitable for my project:

 

The mono amplifier would be used for the desk's special effects sounds, the stereo one for the Pi2 desktop computer.

 

photo (20).JPG

To hook everything together, I made a custom stereo cable with female headers capable of connecting to the breakout board's male headers. Power for the breakout board is taken from the Pi's GPIO pins. And finally, the connectors for the speakers were stripped off, and the wires connected in the breakout board's screw terminals. The same process is valid for the mono and stereo breakout boards, except for the fact the the mono breakout board only supports one speakers (obviously ...).

 

As a test, I put one of the sound effect MP3s on the Pi and played it out with following command:

 

pi@PiDesk ~ $ omxplayer -o local example.mp3
Audio codec mp3 channels 1 samplerate 22050 bitspersample 16
Subtitle count: 0, state: off, index: 1, delay: 0
have a nice day 



 

The solution for both Pis combined is still cheaper than one audio card, and is compatible with any model or revision Pi.

Software sources

The Meditech software has been divided into packages everyone related to a specific context. Every package will be included in a separate repository folder following its own lifetime and in the meantime it is accessible from a unique Git entry point on GitHub. that is the user alicemirror.

 

The first setup repository, also used here as example is the chipkit_serial_pi To access the software sources you can download the repo from GitHub at the following address: https://github.com/alicemirror/chipkit_serial_pi or, alternatively, cloning the repository with the command

 

git clone https://github.com/alicemirror/chipkit_serial_pi.git





 

At the actual date third party software used in the sources are open source with the license explicitly declared in the sources. The Meditech sources are distributed with the Apache license but this choice maybe subject to changes in the future as a definitive licensing system has not yet been adopted.

 

Software documentation

To keep the sources documentation always updated with the sources every package has its own documentation automatically created with Doxygen in two formats: html and pdf. And example of the pdf documentation can be downloaded at the bottom.

 

The advantage using Doxygen to generate in-line documentation is to have an always updated program and documentation with a minimum effort. In addition to the usual software documentation (doxygen-encoded) some sources also includes in the header comment documentation pages referred to some special feature or behaviour of the program.

 

The html documentation is updated every new version of the software and is published on the site http://meditech.balearicdynamics.com/doc one folder every repository. This results in a series of independently navigable static sites kept constantly updated, The root to access the Meditech software documentation packages is http://meditech.balearicdynamics.com/doc where every package can be accessed in a specific folder. To see an example check the last update of the ChipKit PI documentation package, as shown in the image below.

Doxygen page sample.png

It's time to start doing something serious!

 

So, according to the plan, I will install the realtime version of the Raspbian. I will use Raspberry Pi Model B. I will install this Raspbian version with real-time kernel for Raspberry Pi 2 Model B. It is based on 2015-02-16-raspbian-wheezy with default kernel replaced to 3.18.9-rt5-v7+ kernel and a few additional tunings.

Default Raspbian kernel 3.18 is configured with PREEMPT option and provides worst case latency around hundreds of microseconds. Real-time demanding applications require lower latencies than that. Real-time patch lowers the worst case latency to tens of microseconds, improving performance of real-time applications such as autopilots to be run on Linux.

Emlid (the company that provides this Raspbian version) provides also some useful performance comparisons

 

04 - RT.png

By the way, the following interrupt latency data (obtained by running command)

sudo cyclictest -l1000000 -m -n -a0 -t1 -p99 -i400 -h400 -q

gives another idea of the performance improvements between Raspberry Pi and Raspberry Pi 2

 

Interrupt Latency

Raspberry Pi

Raspberry Pi 2

No RT

RT

No RT

RT

Min

13 us

11 us

13 us

11 us

Avg

23 us

23 us

21 us

18 us

Max

1153 us

66 us

307 us

58 us

 

The step to install the realtime Raspbian are

  1. download image from
    http://docs.emlid.com/Downloads/Real-time-Linux-RPi2/
  2. unzip the .xs file using 7-Zip. This will create a .img file
  3. dump the image on a SD card using Win32DiskImager

 

Very smooth and easy!

Introduction

After the two first phases, creating an initial beta version of the Meditech hardware including a first series of probes it is time to move the project to the software side consolidating the architecture.

One of the difficulties defining the software architecture is to identify the correct development areas for the different parts: different programming languages and development environments, almost strong hardware interaction, human interface, data collection and management, Internet and remote server data exchange and more. All these parts should be harmonised creating a unique operating device where most of the features are automated processes.

 

Internal hardware organisation

The image below shows the Meditech components how they are organised in the device architecture, the network connection (WiFi and ethernet wired in violet), the acquisition data flow (red), the control-panel autonomous subsystem (green and the Raspberry PI connected peripherals (blue)

Meditech architecture - Tab 1.png

 

Networking

Networking approach involves all the Raspberry PI modules of the system; three units are wired through an ethernet 10/100 switch while the fourth device accesses the system via WiFi connection, as it should operate in mobility near the patient. The settings of this base network connection requires mostly linux commands and special settings, depending on the way every Meditech internal unit should connect with the master unit (RPI master) For every network connection / protocol it is reported the adopted software strategy.]

The most important protocol used are the following: NFS, SSH, HTTP & HTTPS, MySQL, NTP

 

  • NTP server - To grant synchronised date and time with every collected data and event the RPI slave1 act as a NTP server based on the real time clock. RPI slave1 accesses the Internet every boot time (if available) to synch its internal clock device. As the RPI slave3 is connected through the WiFi (on a different network than the other units) the main unit RPI master act as a secondary NTP server for wireless connected devices time synchronisation. [Requires server settings for date and time synchronisation through bash scripting]
  • Network mounted folders - The 120 Gb storage device is directly connected to the RPI master device. All the data produced by the other devices (usually preprocessed locally then send to the master for post-processing and integration) are stored on folders of the RPI master permanently mounted at system startup. [Requires server permanent settings at startup through bash scripting]
  • Raw data streaming - Using differentiated protocols and methods both the audio data from the RPI slave2 unit and video and camera data from the RPI slave3 unit when the probes are active are streamed internally to the RPI master unit while the data that requires storage are saved on the central storage system via network folders. [Requires streaming protocol settings (Linux) and bash scripting for preset]
  • GPS and Accelerometer - The current coordinates position and bearing and orientation data are managed by the RPI slave1 unit that stream continuously the updated information, available by the RPI master unit to attach these information when needed to the collected data from the probes as well as date and time information retrieval. [Requires streaming protocol settings (Linux) and bash scripting for preset]
  • Printing - The Bluetooth printer is managed by the RPI slave1 unit; all the units - depending on some specific conditions are enabled to send printable data to the the RPI slave1 that manages the information using printing templates. [Requires Python scripting for the printer control and the protocol control characters settings, Linux settings and some bash scripting]
  • Remote accessibility - To make remote assistance and support as simple as possible and accessible by potentially any kind of device, the RPI master exposes almost any information that will be available on the local LCD display to remote user through the intermediate server and a set of APIs, the Meditech Remote API. Remote users will access remotely the Meditech device with any browser through the dedicated domain http://meditech.balearicdynamics.com

 

Languages and application contexts

 

C++ under MPIDE for ChipKit PI

All the control panel features are managed as an autonomous system. The ChipKit PI that controls these features hosts a firmware developed in C++ including a dedicated serial communication protocol to enable the board receiving requests from the RPI master unit.

 

C++ for Linux command line

Two class of commands will be available on the system: command line  programs to launch the execution of specific tasks, e.g. processing some information from probes and a set of commands that should run independently by the condition or user interaction running under Linux at startup as services. It is the case of the IR receiver to control the TV controller and the integrated wireless Bluetooth device Keyboard+mouse.

The TV IR controller will be the main controlling device and the choices and menu are shown on the control pane LCD display; this is the reason that the ChipKit PI board should exchange commands with the RPI master unit via TTL serial connection.

 

Another important C++ service application is the ChipKit PI receiver including the notifications of alert and error conditions, e.g. the lid open or excessive internal heating.

 

Qt environment

Some of the internal probes related to the blood and heart conditions are acquired through the BitScope micro device. The real-time data processed by the BitScope librarie are managed through C++ classes to show these images on a Qt-based interface .

As a matter of fact, the LCD Display that is part of the Meditech device in its normal use will show a set of customised areas accordingly with the used probes, the kind of analysis and other data. This display environment shows over the standard Linux X-Server desktop so that only during some maintenance operations (managed by a special authorised user) the standard desktop, commands and Linux applications are visibile.

The graphic design for the Qt environment is developed using the Qt C++ libraries.

 

Python

Python language is used mostly for testing and in some cases to manage low-priority tasks, like the printable data exchange. All where it is possible it is used Python3 while in some cases, where only Python 2.x libraries are available it is used Python 2.7.

The actually python tasks that is expected to be used are: PiFaceCAD, some simple task for data exchange between the Meditech Raspberry PI units and few other.

 

Java

Due to a huge number of classes already available developed to work under the Android environment but simple to port to any other environment Java should be used for some of the printing features (especially the graphic data conversion and the special Esc/POS printers protocol management) and the access to the remote Internet server APIs.

The choice to use Java for the remote access has conditioned by two key factors: the first is that it is my opinion that this language is the better choice to manage JSOON packets, that is the standard adopted to exchange data with the remote server. The second factor is that I can reuse a certain number of classes for parsing and protocol management that are strategical to enable the full printing features instead of a bare text-only printout.

 

SQL

The SQL language is involved locally as all the data sets history is stored in a local SQL database. This means that several scripts and bash linux commands, including queries, SQL data backups and so on, should be provided in the RPI main module for this function.

 

PHP

PHP is the core language of the remote server. The meditech.balearicdynamics.com will expose a number of PHP APIs to the Meditech device connection for many different kind of data exchange. The remote server makes available a page to the remote user assistance showing all the Meditech information in a single graphic page kept updated continuously.

The first thing of this project, is to select the proper configuration.


I'm not an expert in multirotor drones and UAVs, but the selection criteria are quite clear. The configuration must meet, in order of relevance, the following requirements

  1. compact: I want to build a sphere can be safely used indoor, so size matter
  2. easy to control: the control system will be based on a Raspberry Pi board which runs a Linux that, despite any realtime patch, can not be considered a hard realtime operating system. So an intrinsically stable is preferable
  3. easy to build: this is quite an obvious requirement, since timeframe to complete the project and available tools are limited


The selected configuration has a coaxial rotor with counter-rotating blades. This configuration has many advantages

  1. compactness: the two propellers allows this configuration to reach a greater thrust with smaller propellers compared to a traditional helicopter
  2. the counter-rotating propellers gives intrinsic stability to the drone
  3. only two servos are required to control the drone, compared to the four servos required to control a single rotor helicopter


Just for the sake of understanding, here is the the single rotor helicopter configuration


SingleCopter.jpg


and here is the coaxial  helicopter configuration (the configuration I selected)


CoaxCopterTopView1.jpg


After selecting the configuration, it's time to select the proper motors and propellers. As far as brushless motors (which are typically used in multirotor platforms), there are two parameters that are important to consider:

  1. kv: this parameter defines the RPMs the motor reaches for each Volt applied in input. So for example a 980 kv motor powered with a 3 cells LiPo battery (with a total output voltage of 11.1 V) will spin at 11.1 x 980 = 10878 RPM
  2. max input watts: this the maximum power the motor can absorb without burning


On the side of the equation, there are propellers, that are defined by two number:

  1. size: this is the lenghth (typically in inches) from tip to tip
  2. pitch: thi is the displacement a propeller makes in a complete spin of 360° degrees. This means that if we have a propeller of 6” pitch it will advance 6 inches for every complete spin as long as this is made in a solid surface; in a liquid enviroment, the propeller will obviously slide with less displacement.


The factors to consider when selecting the motor and the propeller, there are many facts to take into account

  1. the greater are the size, the greater is the thrust: thrust is proportional to the 4th power of the size of the propeller
  2. the greater the RPMs, the greater is the thrust: thrust is proportional to the 3rd power of the size of the propeller
  3. the greater the RPMs, the greater is the noise
  4. the greater the size and/or the pitch, the lower are RPMs
  5. the greater the RPMs, the greater are the input Watts absorbed by the motor. Also, greater RPMs typically means lower efficiency. If the efficiency drops below 75%, the motor will soon or later burn due the amount of heat that is generated

 

I was initially confused by the number of parameters involved in the selection. Fortunately, I found this very useful tool that allows you to easy calculate a number of parameters

Thanks to this tool, I have been able to compare different configurations.

First, I tried to estimate the final weight of my training sphere. Here are the components and their corresponding weight

 

Raspberry Pi board

31 g

Raspberry Camera

3 g

Engine

2 x 63 g

Propeller

2 x 9 g

Battery (3 cells LiPo)

177 g

Motor controller

30 g

Frame (about 5 m of 2 mm steel)

200 g

Servo

2 x 9 g

Total

594 g

 

The thrust required to lift off is typically said to be three times the weight of the drone, so I need at least a thrust of 1800 grams. Because I have two motors, each motor have to able to lift off 900 grams. After several attempts, I think the best trade-off between propeller size and thrust is a 9 x 6 propeller. In particular, I selected a propeller made by APC, which are said to be very good in terms of quality and lightness.

Once selected the propeller, I played a bit with the motor combo box and I finally made up my mind to used a 980 kv brushless motor. In this configuration, the efficiency is as high as 83%, which leads to a time at full throttle of about 6 minutes. Not that much, but I don't expect to need full throttle all the time!


03 - Propellers.png


I ordered all the stuff and it's now on its way. I'm looking forward to start building the sphere!

Hello all

 

Not posted anything for some time but the project did not stalled at all.

 

What I have done so far:

 

- RaspberryPi + RTC + Display&Control assembled, installed and configured (shown in previous posts, 1, 2, 3)

- build the power board

- build control board for power LED and RGB strip

- assembled charging modules for Li-Ion batteries

- connected together all the above

 

In the following video you'll see a demo of almost all hardware used for Cybernetic Computer Interface project, only headphones, microphone and some wiring are missing. After that, if still interested, you can see modules description.



 

Power board

 

Power board should be able to supply reliable power to RPi and all peripherals.

RPi, sound card, WiFi dongle and SD Card reader need 5V, power LED and RGB strip need 12V.

 

 

For 5V rail I used Pololu 5V, 5A Step-Down Voltage Regulator D24V50F5. May be a little overkill for this application but I like to have some reserve. Besides, keeping a lower load on the converter the drop-out voltage is lower than for higher load, around 1V. If I had used a converter rated for lower current output, 2Amps for example, the load would been higher and drop-out voltage also higher, which is less efficient for a battery powered application.

 

For 12V rail I choose Pololu Adjustable Boost Regulator 4-25V, set at 12V.

 

As power source I used four Li-Ion cells, recovered from a dead laptop, connected in pairs and then in series. Each cell is 2200mA/3.6V so in theory when fully charged this power pack should supply 8.2V/4400mA.

 

To charge the pairs of cells, I used two USB LI-PO BATTERY CHARGERS by Olimex. I choose this solution because I cannot find a 2 cells Li-Ion charger with balancing, small enough to be integrated in my project. Charging time is very long though, each charger can supply only 470mA.

 

Here is the schematic of batteries, chargers and power board connections:

batteries.png

 

 

Power for USB components

 

Most peripherals gets their power and communicate over USB. Because of design constrains, these modules cannot be connected directly to RPi USB ports, so an USB Hub has to be used.

I choose a seven ports USB Hub and hack it to suit my needs.

I remove the Hub enclosure and I cut the power wire (positive (+)) from the cable between RPi and Hub, so RPi won't be back powered through this cable, only data will flow. I'm not sure if this is needed, I thought its safer this way.

Then I powered the Hub with 5V coming from power board, red and blue wires in pictures below.

 

IMG_3732.JPGIMG_3730.JPG

 

LEDs control board

 

I build it on a piece of perf board and consist in four BC639 medium power NPN transistors and current limiting resistor for connection to RPi GPIO pins.

RGB LED strip is connected directly to 12V rail and the 1W power LED have a current limiting resistor.

 

Light intensity for RGB LED strip and power LED is controlled using PWM.

For PWM I used GPIO pins 12, 16, 20 and 21 - BCM notation. To generate PWM on these pins I used RPi.GPIO library.

I tried also RPIO library but so far it is not working on RaspberryPi ver.2

 

Here you can see power board on the left and LEDs control board on the right.

IMG_3729.JPG

And the schematic:

control_board_schem.jpg

 

The next post will be dedicated to the python code that made the whole thing tick.

 

All the best

-=Seba=-