Recent Posts

2022-10-28

Andrzej Georgiew - spectacular portraits

 I'm using blogspot for content that I want to preserve publicly. This is about Andrzej Georgiew, a spectacular photographer that did amazing portraits. Check the links:

2021-01-14

On development team metrics

 This article is pure gold:

https://teamplify.com/blog/why-you-shouldnt-rely-on-developer-metrics/

One of the very few articles that apart from saying that life is shit, actually tries to produce some suggestions on how to improve the situation and proposes other metrics to differentiate low and high IT R&D performers.

2019-06-29

Mac backups on Ubuntu 19.04 and Samba 4.10

Ubuntu 19.04 now contains samba 4.10, that should support all the SMB/CIFS extensions needed by MacOS to use the samba shares as TimeMachine storage. Tested with MacOS 10.14.5.

So let's do some TimeMachine backups on Ubuntu 19.04!

Assumptions:

  • your Ubuntu is running on some PC, with some fixed IP,
  • you have your Mac connected to the same network.

First install Samba:
apt install samba
Let's get the old samba config out of the way

mv /etc/samba/smb.conf /etc/samba/smb.confORG

Now create and edit /etc/samba/smb.conf (this is the same as in previous samba mac backups howto)

[global]
server role = standalone server
passdb backend = tdbsam
obey pam restrictions = yes
security = user
printcap name = /dev/null
load printers = no
socket options = TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=524288 SO_SNDBUF=524288
server string = Samba Server %v
dns proxy = no
wide links = yes
follow symlinks = yes
unix extensions = no
acl allow execute always = yes
# Special configuration for Apple's Time Machine
fruit:model = MacPro
fruit:advertise_fullsync = true
fruit:aapl = yes
fruit:time machine = yes
## Definde your shares here
[backup]
path = /space/backups
valid users = backups
writable = yes
durable handles = yes
kernel oplocks = no
kernel share modes = no
posix locking = no
vfs objects = catia fruit streams_xattr
ea support = yes
browseable = yes
read only = No
inherit acls = yes


Create and edit /etc/avahi/services/timemachine.service (this is the same as in previous samba mac backups howto)

<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
<name replace-wildcards="yes">%h</name>
<service>
<type>_smb._tcp</type>
<port>445</port>
</service>
<service>
<type>_device-info._tcp</type>
<port>0</port>
<txt-record>model=RackMac</txt-record>
</service>
<service>
<type>_adisk._tcp</type>
<txt-record>sys=waMa=0,adVF=0x100</txt-record>
<txt-record>dk0=adVN=backup,adVF=0x82</txt-record>
</service>
</service-group>

Add the backup directory, backup user and set permissions on the directory. This also sets the password for SMB/CIFS access:

useradd -m backups
smbpasswd -a backups
mkdir -p /space/backups
chown backups /space/backups
chmod 700 /space/backups

Now either reboot your Ubuntu or restart avahi and samba.

And there, the new backup destination should show up in all macs connected to the same network. REMEMBER KIDS, DO ENCRYPTED BACKUPS!

ps. how to view you mac backups progress:

log stream --style syslog --predicate 'senderImagePath contains[cd] "TimeMachine"' --info

2018-05-12

How to get Mac High Sierra Time Machine backups working on an Ubuntu 18.04 server

There are lot's of howtos out there how to get Linux servers to support TimeMachine networked backups for Mac clients. But lately they all stopped working due to latest Mac High Sierra updates. Apple moves away from Netatalk protocol and recommends using SMB. Unfortunately the latest Samba you will get on Ubuntu 18.04 is 4.7, and this does not support so called fruit extensions needed by Mac to have Time Machine writing it's data to the destinations. We need to get Samba 4.8 that was released not so long ago.

So let's start. I'm assuming you do not have any other samba installed. The backup folder will pop up as "backup on <your linux server name>" and you will be using user name backups with the password you'll set on the way. I strongly recommend to read the howto I've posted at the end. It allows for a multi user setup.

Install samba:
sudo apt-get-repository ppa:linux-schools/samba-latest
sudo apt update
sudo apt install samba
This installs samba 4.8 that is a hard requirement to get SMB based TimeMachine backups working.

Let's get the old samba config out of the way
mv /etc/samba/smb.conf /etc/samba/smb.confORG
Now create and edit /etc/samba/smb.conf

[global]
server role = standalone server
passdb backend = tdbsam
obey pam restrictions = yes
security = user
printcap name = /dev/null
load printers = no
socket options = TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=524288 SO_SNDBUF=524288
server string = Samba Server %v
dns proxy = no
wide links = yes
follow symlinks = yes
unix extensions = no
acl allow execute always = yes
# Special configuration for Apple's Time Machine
fruit:model = MacPro
fruit:advertise_fullsync = true
fruit:aapl = yes
fruit:time machine = yes
## Definde your shares here
[backup]
path = /space/backups
valid users = backups
writable = yes
durable handles = yes
kernel oplocks = no
kernel share modes = no
posix locking = no
vfs objects = catia fruit streams_xattr
ea support = yes
browseable = yes
read only = No
inherit acls = yes

Create and edit /etc/avahi/services/timemachine.service

<?xml version="1.0" standalone='no'?>
<!DOCTYPE service-group SYSTEM "avahi-service.dtd">
<service-group>
 <name replace-wildcards="yes">%h</name>
 <service>
   <type>_smb._tcp</type>
   <port>445</port>
 </service>
 <service>
   <type>_device-info._tcp</type>
   <port>0</port>
   <txt-record>model=RackMac</txt-record>
 </service>
 <service>
   <type>_adisk._tcp</type>
   <txt-record>sys=waMa=0,adVF=0x100</txt-record>
   <txt-record>dk0=adVN=backup,adVF=0x82</txt-record>
 </service>
</service-group>
Create and edit /etc/rc.local as it looks like that samba 4.8 does not come with startup scripts.
#!/bin/bash
echo " # starting samba from rc.local"
smbd
exit 0
Add the backup directory, backup user and set permissions on the directory. This also sets the password for SMB/CIFS access:
useradd -m backups
smbpasswd -a backups
mkdir -p /space/backups
chown backups /space/backups
chmod 700 /space/backups
And let's start this (no reboot required):
/etc/init.d/avahi-daemon restart
smbd
And there, the new backup destination should show up in all macs connected to this network. REMEMBER KIDS, DO ENCRYPTED BACKUPS!

ps. how to view you mac backups progress:
log stream --style syslog --predicate 'senderImagePath contains[cd] "TimeMachine"' --info

Credits:
https://www.reddit.com/r/homelab/comments/83vkaz/howto_make_time_machine_backups_on_a_samba/

2017-06-26

Sim racing and game controllers - part 4 - Arduino leonardo project - TENSIOMETERS

Check the previous entries about the project: part1part2, part3 and the video and problems.

So I'm still using the Arduino racing pad since 2 years. I'm still racing in LFS, now in Assetto Corsa with it. I've complained about what's bad about it. And now I've solved another issue that I've had - the crappy joysticks. I've used FSR402 tensiometers for both accelerator and braking. This seems much more natural than using the lever sticks. And precise. Now I can drive powerful cars with no ABS and TC in Assetto Corsa :)

Why tensiometers?


When I've started thinking about that crappy joysticks, I've looked at what the game consoles are doing for the trigger buttons on the pads:

  • X360 pad uses a potentiometer with clever levers,
  • Playstation uses tensiometers,
  • X One uses Hall Effect sensors.
I wanted to buy the replacement parts for the X360 to check the levers, but the tensiometers are just cheaper. The Hall Effect sensors seem to be a very cool idea, but you really need to have an idea how to sort out the mechanics.

How does it look:

Bad. Ugly. But works.









I've placed the tensiometers along another edge of this beautiful lunch box. And now I can use both methods of controlling the speed of the car by just remapping controls. Frankly speaking - I haven't used the levers since I've got the tensiometers running.

Wiring FSR402 to Arduino:

Check this for examples of wiring and code: https://learn.adafruit.com/force-sensitive-resistor-fsr/using-an-fsr. After wiring the tensiometer properly you use it within the code like any other potentiometer.

Video:


Summary:

This just works. I'm using this for gaming weekly or biweekly (you know, 3 kids) for the last 3-4 months.

Using tensiometers for game controlers has another potential application. People making pedals for racing always look for methods to measure travel for acceleration and pressure for braking - to simulate real car hydraulics. All not ridiculously expensive steering wheels on the market use potentiometers for all pedals. And with a very simple mechanism (1 swing, some foam) you can get a pressure measuring tensiometer based pedal - you'll need a bigger tensiometer thou.

Code:

The requirements for having this running are described in the part3 of this "journey".

#include "HID-Project.h"

const int pinLed = LED_BUILTIN;
const int pinButton = 2;

// this is for printing to COM - set to 1 to get printouts
const int printuj = 0 ;

void setup() {
  pinMode(pinLed, OUTPUT);
  pinMode(pinButton, INPUT_PULLUP);
  Gamepad.begin();

  if ( printuj == 1 ) {
    Serial.begin(9600);
  }
}

void loop() {
  // limits for steering
  float steeringmin=0;
  float steeringmax=1023;
  // limits for joystick braking
  float brakemin=0;
  float brakemax=1023;
  // limits for joystick accelerating
  float accelmax=1023;
  // limits for tensometer acceleration and braking
  float brakemaxb=910;
  float accelmaxb=910;
  float accelmin=0;
  float min=-32767;
  float max=32767;
  float diff=max-min;
  float minB=-123;
  float maxB=+123;
  float diffB=maxB-minB;

  // steering
  float steer = (float)analogRead(0)/(steeringmax-steeringmin)*diff + min;

  // acceleration, braking for joysticks and for tensometers
  float accel = ((float)analogRead(2)/(accelmax-accelmin))*diff + min;
  float brake = ((float)analogRead(1)/(brakemax-brakemin))*diff + min;
  float accelb = ((float)analogRead(4)/(accelmaxb-accelmin))*diffB + minB;
  float brakeb = ((float)analogRead(3)/(brakemaxb-brakemin))*diffB + minB;

  // all 4 buttons readouts
  int gearup = digitalRead(2);
  int geardown = digitalRead(3);

  int gearupb = digitalRead(4);
  int geardownb = digitalRead(5);

  // idiotic deadzones for joystick
  if ((accel <= 3) and (accel >= -3)) {
    accel=0;
  }
  if ((brake <= 3) and (brake >= -3)) {
    brake=0;
  }

  // limits for tensometers
  if (accelb > maxB) {
    accelb=maxB;
  }
  if (brakeb > maxB) {
    brakeb=maxB;
  }

  // this is the COM printing
  if ( printuj == 1 ) {
        Serial.print ((int)steer);
        Serial.print (' ');
        Serial.print (analogRead(0));
        Serial.print (' ');
        Serial.print ((int)accel);
        Serial.print (' ');
        Serial.print (analogRead(2));
        Serial.print (' ');
        Serial.print ((int)brake);
        Serial.print (' ');
        Serial.print (analogRead(1));
        Serial.print (' ');
        Serial.print (gearup);
        Serial.print (' ');
        Serial.print (geardown);
        Serial.print (' ');
        Serial.print (gearupb);
        Serial.print (' ');
        Serial.print (geardownb);
                Serial.print (' ');
                Serial.print (analogRead(3));
                Serial.print (' ');
                Serial.print ((int)brakeb);
            Serial.print (' ');
                Serial.print (analogRead(4));
                Serial.print (' ');
                 Serial.print ((int)accelb);
        Serial.println (' ');
  }

 \\ button switching
 if (gearup == 0)
 {
   Gamepad.press(1);
 } else {
   Gamepad.release(1);
 }

 if (geardown == 0)
 {
   Gamepad.press(2);
 } else {
   Gamepad.release(2);
 }
 if (gearupb == 0)
 {
   Gamepad.press(3);
 } else {
   Gamepad.release(3);
 }

 if (geardownb == 0)
 {
   Gamepad.press(4);
 } else {
   Gamepad.release(4);
 }


 \\ output to axises. xA is 16bit, the rest I don't remember and it does not matter.
 Gamepad.xAxis((int)steer);
 Gamepad.yAxis((int)accel);
 Gamepad.rxAxis((int)brake);
 Gamepad.zAxis((int)accelb);
 Gamepad.rzAxis((int)brakeb);


 Gamepad.write();

}

Next step: getting some better chassis for the device.

2016-04-15

Sim racing and game controllers - part 3 - Arduino leonardo project

The issue

I've posted these articles on the Arduino racing pad that I've built: part1, part2 and the video and problems. I've complained a bit on the fact that what I have done has only 8bits of information for the steering wheel. That should be enough for steering, but when driving straight in LFS, you could see that the steering wheel "jumps" between positions. 8bits of information is 256 possible positions of the wheel and when you get 270 degrees of rotation on a potentiometer, that is visible - you cannot turn the wheel by a half of a degree.

My third kid started sleeping better, so now I have bits of time here and there to play around with toys. After a beer or two I've said to my self "8bits steering improvement - how hard can it be?".

The ingredients

Back then, one year ago, you needed to copy the custom HID.cpp and USBAPI.h files into the Arduino IDE libraries to get the Joystick definition. Now you don't have to. Arduino 1.6.8 IDE allows for libraries to be added and guy named Nico prepared marvelous library called Arduino HID Project 2.4.3. This library contains Gamepad definition with 32 buttons, 2 dpads, 4 16bit axis and 2 8bit axis.

So I've used:
  • Arduino Leonardo with the tupperware racing pad I've build in the previous posts, 
  • Arduino IDE 1.6.8,
  • Arduino HID Project 2.4.3,
  • moderate amount of alcohol.

The solution

The new Arduino HID project makes it very tidy and simple to set up the controler I needed. The code for the Arduino Sketch is given below. When someone will try to copy and play with that, be sure to check which axis has how many bits. X, Y, RX, RY are 16bits, Z and RZ are 8bits.

The Arduino HID needs to be downloaded and copied into the libraries directory of your Arduino IDE installation. I'm sure there are other places you can put it in, but I guess I'm too lazy :)

The results

Now I've got all axis on 16 bits. Arduino Leonardo A/D has 10 bits resolution, so that is an overkill. The USB device is 64 times more precise than what Arduino can return, but it does not matter. I got what I needed on a very simple set of libraries. Now when I turn the wheel knob everything is super smooth. 

Now the only thing keeping me from winning every LFS game is my set of mediocre virtual driving skills.

Next improvement - some other mechanical potentiometers for the throttle and brakes.

The Code


#include "HID-Project.h"

const int pinLed = LED_BUILTIN;
const int pinButton = 2;

void setup() {
  pinMode(pinLed, OUTPUT);
  pinMode(pinButton, INPUT_PULLUP);
  Gamepad.begin();
}

void loop() {
  float steeringmin=0;
  float steeringmax=1023;
  float brakemin=0;
  float brakemax=1023;
  float accelmax=1023;
  float accelmin=0;
  float min=-32767;
  float max=32767;
  float diff=max-min;


  float steer = (float)analogRead(0)/(steeringmax-steeringmin)*diff + min;
  float accel = ((float)analogRead(2)/(accelmax-accelmin))*diff + min;
  float brake = ((float)analogRead(1)/(brakemax-brakemin))*diff + min;
  // on second thought, I just could have multiplied one thing by 64 to get the result
 
  int gearup = digitalRead(2);
  int geardown = digitalRead(3);
 
  if ((accel <= 3) and (accel >= -3)) {
    accel=0;
  }
  if ((brake <= 3) and (brake >= -3)) {
    brake=0;
  }



 
 if (gearup == 0)
 {
   Gamepad.press(1);
 } else {
   Gamepad.release(1);
 }

 if (geardown == 0)
 {
   Gamepad.press(2);
 } else {
   Gamepad.release(2);
 }
 Gamepad.xAxis((int)steer);
 Gamepad.yAxis((int)accel);
 Gamepad.rxAxis((int)brake);
 Gamepad.write();

 // zAxis is 8bit, I wanted to use 16bits on all

}

2015-06-16

My first Arduino racing pad - video and conclusions

Hi!

For future reference, check out the video with the Arduino racing pad, that I've built here: http://jakkul.blogspot.com/2015/06/sim-racing-and-game-controllers-part-2_3.html

My first Arduino racing pad in full glory!


There are some problems with the design that need working on:
  • The ergonomics are not the best. It's hard to use one hand for acceleration, brakes and gears.
  • I think, that 8bits of data fed by Arduino to the PC for steering are not enough.
  • You cannot drink beer while driving. Two hands need to be always on the pad. This is not the case when driving with a mouse or a wheel.
  • The gaming-pad-like joysticks are crap. About half of the axis travel is analogue, the rest is in full on state. 
I have some ideas for the next design. But I guess that will have to wait until autumn, since my 3rd kid is due to be born within next 2-3 weeks :)