The main work in this project includes:
an implementation of a CANopen library in order to control the ServoStar drive over a CAN bus. First for a CANUSB interface, then support for a PCAN PCI interface has been included and the library has been optimized for usage of the latter one.
the addition of an interface to use the library to control the steering wheel. The focus was on realtime abilities, as it is very important for the control.
The library consists of three important classes to be able to control the ServoStar drive:
Another class called "PorscheSteeringWheel" is derived from the "ServoStar"-class to provide functions especially for the usage of the steering wheel included in the Sitzkiste assembly. It provides procedures to home the steering wheel by calling the internal functions of the ServoStar as well as to read the actual angle and to set the torque via PDOs. It also includes functions to establish a realtime environment for the steering wheel control.
A CAN bus interface class derived from the "CanInterface" C++-interface. The library includes two such classes: "PcanPci" and "CanUsb". They provide basic send and receive functions for CAN messages.
A class called "CanOpenBus" representing the CAN bus using the CANopen standard. It implements CANopen communication objects like NMT, SYNC, SDO, PDO and Nodeguard.
A "ServoStar"-class that provides functions to control the ServoStar drive. It mainly accesses the object dictionary of the drive to do so.
You can browse through the library documentation made with doxygen.
The class "PorscheSteeringWheel" includes functions to be able to establish a realtime environment. This is important for the usage of the steering wheel control in a car driving simulation. It is designed for the car driving simulator of the HLRS Visualization Department, which runs on a cluster with 32 dual processor nodes.
The realtime functions make use of the realtime support of the Linux kernel 2.6. This includes functions to:
Generally the concept is to define an extra realtime thread (in linux a thread is regarded as a process), which handles the controlling of the steering wheel. Without realtime, the behaviour of the steering wheel can be undefined and finger breaking. (For example a build up of an angle oscillation of the steering wheel is not seldom recognized.)
set the kernel process scheduler to FIFO-mode and set a higher priority for the calling process.
to nice the calling process. (Why that should do any good to improve realtime behaviour is explained later.)
to set the processor affinity of the actual process. Of course, that's only of interest for multi processor machines.
Linux is a time-sharing system that runs processes simultaneous by switching through them. The kernel scheduler decides when to and to which process to switch. You can set the process policy to realtime modes like FIFO or Round Robin in order to get realtime behaviour for that process (so it's not guaranteed). You can also set the process to a higher priority to increase the chance to get the process back running in time (so it's not guaranteed...).
Nice a process
To nice a process means just to decrease the process priority. If you nice a mother process, the realtime behaviour of the child thread can be increased. In Linux a process can nice itself without having root privileges.
You can set the processor affinity of a process in order to lock it on certain processors or a single processor of the machine. Of course, this is only of interest if you have multiple processors or multi-core processors in your machine.
Normally the Linux kernel should handle the process distribution to the processors (if you have a SMP-kernel installed). But we get better results, if we lock the mother process to one processor and the child thread to another by hand.
Process Switching Cycle
Normally the scheduler won't switch from one process to another before the time slice for the running process has been exhausted (an exception would be, if the running process yields his remaining time of the slice). So the time slice is the minimum guaranteed en-bloc-running-time of an process. It is defined by an kernel internal switching cycle: Currently as from kernel 2.6.13, there is a switching frequency of 250Hz, but you can also choose values of 100Hz or 1000Hz in the kernel compile configuration. (Idea behind: Higher frequency -> better realtime behaviour)