How to set system variables in start-up scripts - bash

I'm controlling 8 servos using the PWM outputs on the BeagleBone. On start-up the names of the PWMs are dynamically assigned so they vary from boot to boot, so to know which pin matches which PWM I've written this script:
#!/bin/sh
# match BeagleBone PWMCHIP{n} with available pwm controllers
for i in $(/bin/ls /sys/class/pwm); do
link=$(/bin/readlink /sys/class/pwm/$i)
case "$link" in
*48300100*) BBPWM0=$i;;
*48300200*) BBPWM1=$i;;
*48302200*) BBPWM2=$i;;
*48304100*) BBPWM3=$i;;
*48304200*) BBPWM4=$i;;
esac
done
export BBPWM0
export BBPWM1
export BBPWM2
export BBPWM3
export BBPWM4
echo "PWM0 = $BBPWM0" > /home/ormund/servo.log
/home/ormund/servo-server
The system works when I start it from the command line, the servo-server listens on a network port and moves the servos correctly in response to remote commands, but if I start this from systemd at boot, it fails, the BBPWM0 is a null string and the server cant start. What am I doing wrong?

Related

Send data by network and plot with octave

I am working on a robot and my goal is to plot the state of the robot.
For now, my workflow is this:
Launch the program
Redirect the output in a file (robot/bash): rosrun explo explo_node > states.txt
Send the file to my local machine (robot/bash): scp states.txt my_desktop:/home/user
Plot the states with octave (desktop/octave): plot_data('states.txt')
Is there a simple solution to have the data in "real time"? For the octave side. I think that I can with not so much difficulty read from a file as an input and plot the data when data is added.
The problem is how do I send the data to a file?
I am opened to other solutions than octave. The thing is that I need to have 2d plot with arrows for the orientation of the robot.
Here's an example of how you could send the data over the network (as Andy suggested) and plot as it is generated (i.e. realtime). I also think this approach is the most flexible / appropriate.
To demonstrate, I will use a bash script that generates an
pair every 10th of a second, for the
function, in the range
:
#!/bin/bash
# script: sin.sh
for i in `seq 0 0.01 31.4`;
do
printf "$i, `echo "s($i)" | bc -l`\n"
sleep 0.1
done
(Don't forget to make this script executable!)
Prepare the following octave script (requires the sockets package!):
% in visualiseRobotData.m
pkg load sockets
s = socket();
bind(s, 9000);
listen(s, 1);
c = accept(s);
figure; hold on;
while ! isempty (a = str2num (char (recv (c, inf))))
plot (a(:,1), a(:,2), '*'); drawnow;
end
hold off;
Now execute things in the following order:
Run the visualiseRobotData script from the octave terminal.
(Note: this will block until a connection is established)
From your bash terminal run: ./sin.sh | nc localhost 9000
And watch the datapoints get plotted as they come in from your sin.sh script.
It's a bit crude, but you can just reload the file in a loop. This one runs for 5 minutes:
for i = 1:300
load Test/sine.txt
plot (sine(:,1), sine(:,2))
sleep (1)
endfor
You can mount remote directory via sshfs:
sshfs user#remote:/path/to/remote_dir local_dir
so you wouldn't have to load remote file. If sshfs is not installed, install it. To unmount remote directory later, execute
fusermount -u local_dir
To get a robot's data from Octave, execute (Octave code)
system("ssh user#host 'cd remote_dir; rosrun explo explo_node > states.txt'")
%% then plot picture from the data in local_dir
%% that is defacto the directory on the remote server

uenvcmd in uEnv.txt can not be executed automatically

I am using an arm board using TFTP and NFS but it got stuck at kernel loading as shown in the screenshot and I have to input the run uenvcmd then the process will keep going and everything is OK.
Below is my uEnv.txt:
# This uEnv.txt file can contain additional environment settings that you
# want to set in U-Boot at boot time. This can be simple variables such
# as the serverip or custom variables. The format of this file is:
# variable=value
# NOTE: This file will be evaluated after the bootcmd is run and the
# bootcmd must be set to load this file if it exists (this is the
# default on all newer U-Boot images. This also means that some
# variables such as bootdelay cannot be changed by this file since
# it is not evaluated until the bootcmd is run.
autoload=no
ipaddr=192.168.1.100
serverip=192.168.1.13
gatewayip=192.168.1.1
staticip=${ipaddr}:${serverip}:${gatewayip}:255.255.255.0:::off
bootpath=/tftpboot
rootfspath=/opt/ti-processor-sdk-linux-rt-am57xx-evm-03.00.00.04/targetNFS
#setting for kernel loading
kernel_addr=0x82000000
fdt_addr=0x88000000
nfs_args=setenv bootargs console=ttyO0,115200n8 root=/dev/nfs rw nfsroot=${serverip}:${rootfspath} ip=${staticip}
load_zimage=tftp ${kernel_addr} ${bootpath}/zImage
loadfdt=tftp ${fdt_addr} ${bootpath}/am572x-idk.dtb
boot_zimage=bootz ${kernel_addr} - ${fdt_addr}
uenvcmd=run load_zimage; run loadfdt; run nfs_args; run boot_zimage
these is a strange file called uboot.env beside the uEnv.txt, too long to paste here, uboot.env
Problem solved: Just delete the file uboot.env
This should be a bug of SDK. I will report this to TI. Thanks #Notlikethat

How to manage process distribution in mpich

I am running mpi code on host1(quad core) and host2(dual core)
mpiexec -hosts host1,host2 -n 6 ./mytask
I want to assign 4 processes for host1 and 2 for host2. I tried --map-by core but I found that the processes are distributed 3 for each.
This is the mpiexec help output
mpiexec -h
Usage: ./mpiexec [global opts] [local opts for exec1] [exec1] [exec1 args] : [local opts for exec2] [exec2] [exec2 args] : ...
Global options (passed to all executables):
Global environment options:
-genv {name} {value} environment variable name and value
-genvlist {env1,env2,...} environment variable list to pass
-genvnone do not pass any environment variables
-genvall pass all environment variables not managed
by the launcher (default)
Other global options:
-f {name} file containing the host names
-hosts {host list} comma separated host list
-wdir {dirname} working directory to use
-configfile {name} config file containing MPMD launch options
Local options (passed to individual executables):
Local environment options:
-env {name} {value} environment variable name and value
-envlist {env1,env2,...} environment variable list to pass
-envnone do not pass any environment variables
-envall pass all environment variables (default)
Other local options:
-n/-np {value} number of processes
{exec_name} {args} executable name and arguments
Hydra specific options (treated as global):
Launch options:
-launcher launcher to use (ssh rsh fork slurm ll lsf sge manual persist)
-launcher-exec executable to use to launch processes
-enable-x/-disable-x enable or disable X forwarding
Resource management kernel options:
-rmk resource management kernel to use (user slurm ll lsf sge pbs cobalt)
Processor topology options:
-topolib processor topology library (hwloc)
-bind-to process binding
-map-by process mapping
-membind memory binding policy
Checkpoint/Restart options:
-ckpoint-interval checkpoint interval
-ckpoint-prefix checkpoint file prefix
-ckpoint-num checkpoint number to restart
-ckpointlib checkpointing library (none)
Demux engine options:
-demux demux engine (poll select)
Other Hydra options:
-verbose verbose mode
-info build information
-print-all-exitcodes print exit codes of all processes
-iface network interface to use
-ppn processes per node
-profile turn on internal profiling
-prepend-rank prepend rank to output
-prepend-pattern prepend pattern to output
-outfile-pattern direct stdout to file
-errfile-pattern direct stderr to file
-nameserver name server information (host:port format)
-disable-auto-cleanup don't cleanup processes on error
-disable-hostname-propagation let MPICH auto-detect the hostname
-order-nodes order nodes as ascending/descending cores
-localhost local hostname for the launching node
-usize universe size (SYSTEM, INFINITE, <value>)
Please see the intructions provided at
http://wiki.mpich.org/mpich/index.php/Using_the_Hydra_Process_Manager
for further details
There are several options.
pi#RPi:~ $ mpiexec -H rpi,rpi,rpi,rpi5,rpi7,rpi7 -np 6 helloworld.py
Hello World! I am process 3 of 6 on RPi5.
Hello World! I am process 5 of 6 on RPi7.
Hello World! I am process 4 of 6 on RPi7.
Hello World! I am process 0 of 6 on RPi.
Hello World! I am process 2 of 6 on RPi.
Hello World! I am process 1 of 6 on RPi.
The hostfile with the -hostfile filename.
pi#RPi:~ $ cat filename
RPi slots=4 max_slots=4
RPi5 slots=2 max_slots=2
RPi7 slots=4 max_slots=4
Also, use the -nooversubscribe option.

Bash case not properly evaluating value

The Problem
I have a script that has a case statement which I'm expecting to execute based on the value of a variable. The case statement appears to either ignore the value or not properly evaluate it instead dropping to the default.
The Scenario
I pull a specific character out of our server hostnames which indicates where in our environment the server resides. We have six different locations:
Management(m): servers that are part of the infrastructure such as monitoring, email, ticketing, etc
Development(d): servers that are for developing code and application functionality
Test(t): servers that are used for initial testing of the code and application functionality
Implementation(i): servers that the code is pushed to for pre-production evaluation
Production(p): self-explanatory
Services(s): servers that the customer needs to integrate that provide functionality across their project. These are separate from the Management servers in that these are customer servers while Management servers are owned and operated by us.
After pulling the character from the hostname I pass it to a case block. I expect the case block to evaluate the character and add a couple lines of text to our rsyslog.conf file. What is happening instead is that the case block returns the default which does nothing but tell the person building the server to manually configure the entry due to an unrecognized character.
I've tested this manually against a server I recently built and verified that the character I am pulling from the hostname (an 's') is expected and accounted for in the case block.
The Code
# Determine which environment our server resides in
host=$(hostname -s)
env=${host:(-8):1}
OLDFILE=/etc/rsyslog.conf
NEWFILE=/etc/rsyslog.conf.new
# This is the configuration we need on every server regardless of environment
read -d '' common <<- EOF
...
TEXT WHICH IS ADDED TO ALL CONFIG FILES REGARDLESS OF FURTHER CODE EXECUTION
SNIPPED
....
EOF
# If a server is in the Management, Dev or Test environments send logs to lg01
read -d '' lg01conf <<- EOF
# Relay messages to lg01
*.notice ##xxx.xxx.xxx.100
#### END FORWARDING RULE ####
EOF
# If a server is in the Imp, Prod or is a non-affiliated Services zone server send logs to lg02
read -d '' lg02conf <<- EOF
# Relay messages to lg02
*.notice ##xxx.xxx.xxx.101
#### END FORWARDING RULE ####
EOF
# The general rsyslog configuration remains the same; pull it out and write it to a new file
head -n 63 $OLDFILE > $NEWFILE
# Add the common language to our config file
echo "$common" >> $NEWFILE
# Depending on which environment ($env) our server is in, add the appropriate
# remote log server to the configuration with the $common settings.
case $env in
m) echo "$lg01conf" >> $NEWFILE;;
d) echo "$lg01conf" >> $NEWFILE;;
t) echo "$lg01conf" >> $NEWFILE;;
i) echo "$lg02conf" >> $NEWFILE;;
p) echo "$lg02conf" >> $NEWFILE;;
s) echo "$lg02conf" >> $NEWFILE;;
*) echo "Unknown environment; Manually configure"
esac
# Keep a dated backup of the original rsyslog.conf file
cp $OLDFILE $OLDFILE.$(date +%Y%m%d)
# Replace the original rsyslog.conf file with the new version
mv $NEWFILE $OLDFILE
An Aside
I've already determined that I can combine the different groups of code from the case block onto single lines (a total of two) using the | operator. I've listed it in the manner above since this is how it is coded while I'm having issues with it.
I can't see what's wrong with your code. Maybe add another ;; to the default clause. To find the problem add a set -vx as a first line. Will show you lots of debug information.

PowerShell Script Running as a Service Behaves Strangely

PowerShell Script Running as a Service Behaves Strangely
The Project:
Create a background process that determines if the on board network card is connected. If it is connected, disable the wireless network card. When the onboard network card is not connected, re-enable the wireless card.
Why:
Users hot-dock all the time, getting funky routing tables OR get bound to the wrong DNS servers. When they attempt to access a local resource, say printers, they aren’t able to and then are in my cube (they would file a ticket, but that too would be a local resource). Trying to convince users to disable their own wireless (via switch on laptop) or not hot dock has met with limited success.
The Problem:
The PowerShell script below does run, and does work under my testing conditions. Likely under most testing conditions as the code and wmi queries are pretty generic. Running the script manually yields the expected results, HOWEVER running the script as a service via the only method I could find, srvany.exe, yielded unexpected results and “broke stuff”.
Details:
Running the script as a service, via srvany.exe, works ONCE. When the loop comes back around to test the network connection or tries the method to enable or disable it. The errors indicate that “get-wmiobject” is not a proper Cmdlet. Huh? It works, manually, it works once, but a second time after it disabled the wireless network card it does not. Worse yet MY shell , outside of the service, suddenly can’t do a get-wmiobject, until…. until you go into Device Manager and re-enable the wireless network card yourself.
Debugging attempts:
I rewrote the script and cleaned it up a little to allow for it to get the objects outside of the Do While loop. Nothing changed, but I left the script that way as it seems cleaner anyhow. I enabled “Interact with Desktop” in the service properties and sure enough you can see the script trying to work and getting the before mentioned errors.
Please help. Again the object here is to run a background process, one with enough privileges in Vista or 7 to disable and enable the wireless network card.
#***********************************************************************
# "switch-wifi-srv.ps1"
# This script attempts to identify if a wired network card is in use if
# one is, the Wireless network card is disabled, until the wired network
# card is no longer in use.
#
# Written by Aaron Wurthmann - aaron (AT) wurthmann (DOT) com
#
# 2010.02.10 ver 2 (Service Version)
# If you edit please keep my name or at the very least original author's.
# As of this writing I am unsure if script will work with all scenarios,
# however it has worked for me on Dell laptops running Windows 7 x64.
# -----------------------------------------------------------------------
# This script comes with ABSOLUTELY NO WARRANTY.
# You may redistribute copies of the script under
# the terms of the GNU General Public License.
# -----------------------------------------------------------------------
# Service Installation:
# Aquire and install the Windows 2003 Resource Kit OR the srvany.exe.
# Use sc.exe and srvany.exe to create a service....
# sc create SwitchWifiAuto binPath= "C:\Program Files (x86)\Windows Resource Kits\Tools\srvany.exe" DisplayName= "Switch Wifi Automatically"
# Edit registry entry for SwitchWifiAuto, add a key and a string value...
# HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\SwitchWifiAuto\Parameters]
# "Application"="C:\\Windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -ExecutionPolicy RemoteSigned -File C:\\SwitchWifiAuto\\switch-wifi-srv.ps1"
#************************************************************************
$state=""
$wireStatus=""
$wifiStatus=""
# Get Wired and Wireless Card Objects
$objWire=get-wmiobject -class win32_networkadapter -namespace root\CIMV2 | Where-Object {$_.Name -notmatch "Wireless" -and $_.Name -notmatch "Virtual" -and $_.PhysicalAdapter -eq "True"}
$objWifi=get-wmiobject -class win32_networkadapter -namespace root\CIMV2 | where-object {$_.Name -match "Wireless"}
# Get Name of Service to be Used in totally useless Do While Loop
$objService=get-service -display "Switch Wifi Automatically"
# Begin Do While Loop
Do {
# Get status of wired network card. If enabled and connected set $state to Disable (which will later Disable the Wifi network card)
[string]$wireStatus=$objWire | % {$_.NetEnabled}
if($wireStatus -eq "True") {
$state="Disable"
}
# Get Status of wireless card.
if($objWifi){
[string]$wifiStatus=$objWifi | % {$_.NetEnabled}
# If $state is not set to disable and if the wireless card is currently disabled, enable it.
if($state -ne "Disable") {
if($wifiStatus -eq "False") {
Out-Null -InputOject ($objWifi | % {$_.Enable()})
}
# If $state is set to Disable and if wireless card is currently enabled, disable it.
} else {
if($wifiStatus -eq "True") {
Out-Null -InputOject ($objWifi | % {$_.Disable()})
}
}
}
# Reset Checked Variables for good measure
$state=""
$wireStatus=""
$wifiStatus=""
# Sleep for 120 seconds (two minutes)
Start-Sleep -s 120
# Continuing looping (do while) until the service is not running.
# This is of course technically useless as when the service is not running neither is the script to check if the service is not running.
# I made it this way however because I don't like infinite loops and I thought it would be funny to it this way instead of while $var=0
} while ($objService.Status -eq "Running")
Try to remove any output. Service don't have stdout stream. And when the buffer is full strange thing happens. Just a guess ( I never used powershell ).
Debugging attempts: I rewrote the script and cleaned it up a little to
allow for it to get the objects outside of the Do While loop.
You need to include these within the loop or you will not get updated values and the loop will do nothing.

Resources