Category Archives: easyIPC

Universal Motor Controller

I designed this universal motor controller capable on driving DC-, Stepper-, BLDC- and even AC – motors earlier. The design parameters was 12-24V at 15A. This is quite a capable controller, but I did a mistake that limit the controller to 12-20V since I connected the Gate Drivers to the Motor PSU directly. To compensate for this I need to modify the design and implement a separate 12V PSU. As I correct this I also want to consider some additional changes.

I am considering is to replace the RS485 with an isolated RS485 due to the amount of energy involved. The 3rd change is Ethernet on a separate adapter board. Basically I want to copy the modules I use on the Universal Adapter as soon as I have tested them.

I am not sure about Ethernet. Ethernet sound nice due to the functionality, but it is a clumsy, 4-wire 1:1 solution. RS485 is slower, but it is a 2-wire network. It actually makes more sense having dual RS485 to be honest. CAN & Ethernet is easier to deal with using an adapter board- RS485 is considered a lower level of communication than CAN because CAN have protocols like CANopen, J1939 etc. The reality is that if we use RS-X that changes.

What I probably should do at some point is to create a “Ethernet” on top of RS-X by using a dual RS-X connection. But, that is fun for later…

So the modified design will be

  • STM32F405RG MCU, 168Mhz, 32bit M4, 1MbFlash, 192KbSRAM
  • 4 x separate half bridge drivers, 30V @15A
  • Current sensors on all
  • BEMF sensors
  • PSU Voltage Sensor
  • Separate 3.3V supercap to sustain MCU in power dips.
  • 3 x hall sensors
  • 2 x temperature sensors.
  • 1 x resolver
  • 2 x end sensors
  • 1-2 x RS485
  • Adapter board for battery/caps
  • Adapter board for CAN/Ethernet/Wifi

Applications

  • Solenoid driver
  • DC Motor driver
  • Stepper Motor Driver
  • Brushless 3-Phase motor driver

PLC Modular System

I have worked far to long with 19″ cabinets and things you mount from front, so what I am thinking is a micro-version of a rack system. We box each electronic module with a backbone plug and custom front connectors. We then plug them in, wire using standard wiring (that we probably have to create) in front – no wiring in the back.

These boxes are simple and can easily be printed on a 3D printer. They will also allow us to mount more electronics tighter to address the total size.

A classic PLC uses 2 wires for a 24V pulse signal – we can typically standardize these so that we apply standard, plug & play cables and avoid as much custom wiring as possible. The top front is after all for wiring to equipment, not for internal wiring that is already done in the back-plane. I think this can work, but I need to talk it through with professional automation engineers – luckily I have access to them in numbers.

One drawback I can see straight away is vibration. I was planning to make this so small that it could fit mobile Equipment, but mobile Equipment vibrate a lot. We will need an outer box and holding mechanism that tolerate very high vibration – or more correctly reduce vibration.

Plain – Distributed Processing Part 4

A lot of Plain assembly syntax is experimental and will be reviewed as we move forward. I think it is important to get concept ideas out in the open for discussions – we can always optimize keywords and syntax later.

In Distributed Systems we need to synchronizing data between multiple modules and this  creates a need for a distributed database system. The transaction mechanism we created earlier fit straight into this, but I need to review the concept to cover a few loose ends.

use System
Module LedHat
            Object LedGroup
                        Bit Led1
                        Bit Led2
                        Bit Led3
            End

            Interface C LedGroup leds[1..6]
            ...
End

My previous example shows how I can call a function located on a different device. In this New example I want to set the leds directly from 32xIO by sharing data.

use System
use LedHat
Module 32xIO
            Transaction LedHat.leds[1]
                        LedHat.leds[1].Led1=1
            Update
End

The “leds” array is declared as interface allowing other modules to access it, so we can as well just access the array from 32xIO inside a Transaction statement. What happens is that we use DRA to connect between LedHat and 32xIO as previously explained, but we now need to (1) send a message to lock access, (2) make the changes, (3) commit changes. We get two extra messages, but less code this way. This was the easy part!

The system illustrated above is two systems wired as one just to complicate things. 32xIO #1 need to connect to LedHat #1 and 32xIO #2 need to connect to LedHat #2. This creates ambiguity as we by default will connect at random – first request will get first LedHat in list etc.

One way of solving this would be to use different module names – this is possible – but you will end up maintaining separate code for multiple devices depending on how they are used. Let’s try to avoid that as much as possible! In this case I have two “domains”, each with an array of 3 x 6 leds using the same name. And as I don’t want to hard-code the domain name I need something else.

A classic solution would be a complicated configuration, but I do not want that either – I have spent to many hours configuring complex communication systems to walk into that trap.

The concept I want to test out is a “System Diagram” – some kind off high level description of our system with modules, devices and how they connect. With this in place I would only need to tell my module what role it play in that system – lets give it a try:

use LedHat
use 32xIO
System SpiderRobot
            Domain green owner LedHat
                        LedHat greenLedGroup
                        32xIO greenIO
            End
      
            Domain blue owner LedHat
                        Ledhat blueLedGroup
                        32xIO blueIO
            End
End

The example above create a system “SpiderRobot” with two domain’s – “green” and “blue”.

I did consider using xml for this, but decided that this actually is part of our code and should use Plain syntax. I like xml because it is an excellent data storage format that can be edited manually if we need to – but, as xml syntax also can be very cryptic – difficult to read logic – this should not be part of any programming language – IMO!

pd 32xIO SpiderRobot -d blue

This is a proposed pd (program download) command. I will review the utility command line later, so this is just a quick & dirty proposal – 32xIO and SpiderRobot are plain assembly (*.pln files). -d blueIO tell the pd that the module can see domain “blue” in addition to global domain.

As the 32xIO now request a LedHat it will only be given access to the LedHat in the same domain. As we start LedHat and 32xIO we also report what domain we are, or that we are unassigned – in the later case we need to be assigned domain visibility & roles by an utility later.

use LedHat
use 32xIO
System SpiderRobot
            Domain green owner LedHat
                        LedHat greenLedGroup
                        32xIO greenIO
            End
         
            Domain blue owner LedHat
                        Ledhat blueLedGroup1
                        Ledhat blueLedGroup2
                        32xIO blueIO1
                        32xIO blueIO2
	     Wire blueIO1 to blueLedGroup1
	     Wire blueIO2 to blueLedGroup2
            End
End

This example complicate our story a bit because I decided to add a 2nd LedHat and 32xIO to domain “blue”. In this case I still do not what LedHat to connect to so we need to “wire” the system manually since auto-wiring will not work anymore.

The added “wire” statement solves this, but I just decided that having two LedHat’s was a bit much, so I want to use only one and let the two 32xIO Hat’s access different led Groups.

use LedHat
use 32xIO
System SpiderRobot
            LedHat greenLedGroup
            32xIO greenIO
            32xIO blueIO
            wire greenIO to leds[1]
            wire blueIO to leds[2] as leds[1]
End

In this case I actually don’t need domain grouping so I just specify my 3 Hat’s and how they are wired together. The wire statement only specify visibility and how we view content. The code does in this case program leds[1] so as I wire blueIO to use leds[2] I also need to specify that this is seen as leds[1].

My concern here is that we introduce too many error scenarios, and as this is a highly experimental concept we need to be open minded for better solutions or loose ends.

Plain – Distributed Processing Part 3

The system I described in part 2 needs to send a message from a module in device #2 to a module in device #5.

This tree is basically the physical address of a resource as seen from RPI1 and RPI2. But, as this address might change with wirings we need a more generic way to program this. The key in this case is that we use the module names are a “resource”.

32xIO and LedHat are both reported as resources in the system during startup. The 32xIO module will due to the “use LedHat” statement request a “LedHat” resource and be sent an address in return. This is part of Dynamic Resource Allocation in easyIPC – a topic we have yet to cover. With an address we need to map a message routing from device#2 to device#5 – this is called a stream in easyIPC. A stream is always 2-ways.

1 The VM “32xIO” (Not the device) will initiate a DRA request. And as part of the request we assign a Stream ID on the device.
2 RPI1 decide to forward the request to RPI2 since this own a request of this type.
3 RPI2 will forward the request to the LedHat device using a managing stream id
4 The LedHat will allocate the resources and send a DRA Responce back with a selected stream ID.
5 RPI2 will set up it’s own Routing between this Stream ID’s and RPI1 and forward the response to RPI1
6 RPI1 will set up its own Routing between the stream ID’s and forward the response to 32xIO.

We have now set up a stream. Any message sent from 32xIO on that stream will be forwarded to the LedHat and wise versa.

DRA will also deal with re-allocating of resources and it is more details to it, but this illustrates how we will  (1) report the modules as resources and (2) connect resource streams in easyIPC.

to be continued in part 4 …

Plain – Distributed Processing Part 2

Our concept of distributed processing is going to need some attention to details in the Assembler/VM design, but it will work. We  now have two mechanisms involved:

  • We have an easy way to synchronize data between several modules
  • We can make on module execute logic on a different module.

The principles of how we do this through easyIPC is easy, but we need to dig into the detailson some some loose ends in our design. One such issue is module addressing in a larger network.

The block diagram above consist 7 devices in a system. We have two RPI’s one for controlling the actuator/sensor sub systems, and one for HMI. The HMI contains a Led Hat where I want to blink Leds from the Servo and stepper controllers.

 LedHat example

use System
Module LedHat
            Object LedGroup
                        Bit Led1
                        Bit Led2
                        Bit Led3
            End
            interface C LedGroup leds[1..6];
            Interface Func SetLedStatus(uint32 group, Bit l1, Bit l2, Bit l3)
                        Transaction leds[group]
                                    leds[group].Led1 = l1
                                    leds[group].Led2 = l2
                                   leds[group].Led3 = l3
                        Update
            End
End

32xIO example

use System
use LedHat
Module 32xIO
            LedHat.SetLedStatus(1,0,0,1)
End

These two code examples are the Plain code I expect to write.

to be continued in part 3…

VM Test Ground

I decided to use the 32 x IO (Servo, Analogue, Digital) as my test ground for the VM – the firmware will in this case include easyIPC (SPI in this case) and a 32 channel programmable IO controller. Each of the channels have capabilities like:

  • Servo with a 14 bit pulse resolution.
  • PWM out with 14 bit resolution. This is a bit-banged PWM that can be used on all channels.
  • Digital Signal Input
  • Digital Signal Output

 Some of the channels will have the following:

  • High resolution/frequency PWM signals
  • Analogue Input
  • Analogue output.

This firmware is an excellent test-ground because it includes highly programmable logic and a hard real-time core on the bit-banging part.

Lets draft some PLAIN Assembly code:

Enum uint32 Mode
            Servo=0
            PWM=1
            DigitalIn=2
            DigitalOut=3
            HRPWM=4
            AnalogueIn=5
            Analogueout=6
End

Object Channel 
            Mode chMode = Mode.Servo
            uint32 position=0
            uint32 frequency = 0
            uint32 duty = 0
            uint32 analogueOut = 0
            uint32 analogueIn = 0
End

Channel Ch1
Channel Ch2
Channel Ch3
Channel Ch4
...

Bit digitalIn[32]
Bit digitalOut[32]

This is a draft of how I want PLAIN Assembly to see the easyIPC objects. Ch1.Mode will be located at register 0x8000, but we can also locate data on selected registers as follows

Channel Ch1 at R(0x8010)

In this example I force Ch1 to be located at Register 0x8010.

The more tricky part is the integration with C/C++ code. The challenge is that the module and data we transfer must match what the C/C++ firmware expects. This last mapping is done by the real-time linker in the firmware that receive the above as a “PLAIN Module Specification”. If it fail it will need to reject the module. In theory it should never fail as the assembler should stop us, but it is always the possibility of firmware version mismatch. This part will need to be strict or we will just dig into loads of debug problems.

Map Channel to C(Channel)
Map digitalIn to C(DigIn)
Map digitalOut to C(DigOut)

Assign Ch1.chMode = Mode.Servo
Assign Ch2.chMode = Mode.DigitalIn
Assign Ch3.chMode = Mode.DigitalIn

Event digitalIn[2]
            Assign Ch1.position = 0
End

Event digitalIn[3]
            Assign Ch1.position = 100
End

This example configure Ch1 as a Servo and Ch2, Ch3 as digital input pins. The Map statements link the objects to associated C/C++ code. The Assembler (and real-time linker) will check these exact names and parameters – parameters must match on name and data type.

The Event statement “digitalIn[2]” declare that any change to bit 2 in the digitalIn will cause a call to this bit of logic. This will be called regardless if it is C/C++ or PLAIN assembly that makes the change.

 I think this will work, but I need to let it mature to catch up missing bits and see if I can optimize this. Notice that while this example is ca 40 lines in assembly we would be talking about ca 7 instructions in the resulting code (+ initialization). The initialization will in this case be nothing since 0 is the default value on all registers. The VM will automatically reset this before execution to avoid that we have random, default values. “Event digitalIn[2]” will generate 2 instructions – an Assign and a Return.

But, keep in mind that this draft is work in progress. I will implement this next to see how it actually works out in real life.

PLAIN – Virtual Machine

Languages like Java C# etc all use a virtual machine. This is a software package that need to start and interpret some kind assembly code. Languages like C/C++ compile into native assembly code that is much faster, but also tied to the hardware it run’s on.

A virtual machine have the advantage that we extend the platform with build in features made available in C/C++. This high level code occupy less space than binary code and executes under our control. The drawback is that it executes slower than native code, but I plan to challenge that by introducing very high level assembly instructions.

I would like to create a native assembler at some point, but for now I want to play around with a Virtual Machine design.

VM Block

The diagram above show how we link things together in the firmware. We use easyIPC protocols to communicate, RTOS and HAL + other modules tom access electronics and do complex stuff. The VM executes logic that control what we do.

Instruction Format

Our VM needs it’s own assembly language so we can use a 32 bit design as indicated above. A 8 bit Op-Code + 4 bit Category code leaves 16 pages of 256 instructions. Category 0 is the build in one, but other categories can be used for extended instructions. Length is the added number of 32 bit register, meaning an instruction can be 32 x 16 bits long.

Instruction Move

This show the MOVE R1, R2 that will copy content of R1 into R2. As this is an array of 31 parameters we can extend this to MOVE R1,R2,R3;R4 etc that copies R1 into R2,R3,R4. Op Code 0 is NOP (No Operation).

VM Tables

This diagram illustrate the internal core of the VM. We have a table holding 32 bit instructions stored in Flash. A Registers table that is located in SRAM for generic use in our logic, and an object table that use address 0x8000 to 0xFFFF to access easyIPC mapped content. Notice that the total register size is 64Kb to make the most of a 16 bit parameter. Stack is located in SRAM at 0x7FFF and up. Each PLAIN Module have it’s own, private stack.

PLAIN contains a set of registers known as easyIPC object registers located between 8000h and FFFFh. These are accessed the same way as stack and generic registers, but are wired to other software or hardware. If these registers are changed events will be generated to allow PLAIN or C/C++ to process changes.

The PLAIN specification allows an application to organize it’s own layout of these objects to guarantee that an application will execute correctly. The issue is that registers for selected hardware need to be located somewhere, and with various hardware/software combinations you end up with far too many registers for the world to be unique. To solve this the Assembler will create a map where all software and hardware is mapped correctly with PLAIN logic. This result in a map that follows the application. The run-time engine will need to map and resolve these calls as the PLAIN application is loaded.

This is work in progress so expect changes as we implement this. The design draft above is based on a proof of concept implementation done about a year ago.

Introducing PLAIN

One of the challenges with a distributed system consisting of multiple Raspberry PI’s, multiple Hat’s and multiple RS-X connected devices is how to control it all. At the end we are running a complex, distributed system and coding logic on this level using a classic programming language like C/C++ is not straight forward. C/C++ is unbeatable dealing with low level electronics, performance and algorithms, but it is a bit clumsy to write higher level logic involving distributed logic. I would like to keep C/C++ to deal with low level things and HOW we do things, but I need something better to describe the logic and WHAT we want done. Having used years with various programming languages, PLC and CNC machinery I basically want to create something new that does things a bit differently.

I decided some time ago to name this PLAINProgramming Language for Automation Industry – basically a language/Logic concept to control robotics on distributed systems. We can evolve this a bit as we move forward, but I have a few key requirements:

  • Generic in nature.
  • Extendable and able to use C/C++ modules.
  • Deal with distributed, high level logic.
  • Support a future graphical CASE tool.
  • State-engine and event based Logic at core.
  • Easy to read top-down text, no cryptic syntax.
  • Easy to learn – read Logic in 5 min – yet powerfully to support Professionals.
  • Embeddable into other solutions.
  • Real-Time Centric.

The previous work on easyIPC fits straight into this work as is establish a plug & play communication network using multiple techniques. What I lack is an Ethernet based protocol, but I will return to this later.

At this point I am planning a language specification, compiler and Virtual Machine. The specification will need to evolve as we move forward on try & fail. Actually I want to start with the Virtual Machine.

easyIPC HL – Part 5 Repository

One important part of easyIPC is it’s “repository”, a real-time database that hold all information needed. The repository on devices are very simple and is only a map of objects made available through the interface. Raspberry PI on the other hand will need a repository of all devices as well as a log of data that has been collected. A node hold its own data only and depend on interconnection to other nodes their data. The exception is the dictionary part that need to be on each node so we know what resources we have in our network.

Repository Model

The UML diagram above illustrate the 4 main tables in the repository on Node level. At device level only the Local Object Map is implemented.

Node is a list of main nodes accessible in the system. One of the entries will be “this” node.

Local Object Map is a list of local resources, objects and variables that are available through the interface.

Remote Object Map is the Node’s local info storage about objects. This contain full name, description, PID and other information uploaded from the device at start-up. The Remote Object map can also be loaded/saved locally on the RPI for fast start-up.

Data is a log of data for a selected object/resource.

This is a very early draft so expect some changes as we dig into more details.

easyIPC HL Part 4 – Messages

Our High Level protocol include a 1 byte message code. The reality is that we can also add PID’s as messages with an object containing several parameters. In fact we talked about reserving ranges of PID’s for special needs. With a 2 byte integer we have 65536 possibilities so if we reserve 0 – 0x7FFF for parameters we can use the ranges above for special needs.

I am thinking about something like this:

  • Bottom PID range for variables/Objects.
  • A range for common, mandatory objects like firmware information etc.
  • A range for special purpose PID’s like envelope etc.
  • A range for standard commands (restart etc) or should this be in the main message code?
  • A range for device specific commands.

As for the main message code we need:

  • – Support for the start-up sequence.
  • – Link maintenance messages (ack, nack, repeat etc).
  • – A generic message to act as a container for PID commands that is neither read or write.
  • – A generic read message.
  • – A generic write message.
  • – A subscription/unsubscribe message.
  • – A range dedicated for device specific messages.
  • – A heartbeat/Status message.
  • – Error messages.

What else? Let’s leave this for now. This is an early draft and we will definitely be adding stuff here as we dig into the details. With both a 1 byte main message code and the possibility to use PID ranges as sub-messages I think we should be well covered. We can even let the PID ranges be message specific if we need to.