Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Integrate ToF Sensor, Implement emergency Brake, and repellent field #4

Open
wants to merge 90 commits into
base: wifi-with-cytron
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
90 commits
Select commit Hold shift + click to select a range
a507572
adding potential field node and modifying twist_to_pwm to sub to pote…
ronggurmahendra Jan 31, 2023
358cc26
adding potential field as consideration
ronggurmahendra Feb 3, 2023
4bade8e
disable the dynamic speed and implement only the emergency brake
ronggurmahendra Feb 3, 2023
a61cc99
cahnge the emergencyStopThreshold
ronggurmahendra Feb 3, 2023
fe9a3e8
refactor and remove unnecesarry code
ronggurmahendra Feb 3, 2023
d2a9d44
update README.md
ronggurmahendra Feb 3, 2023
1d44b5a
update README.md
ronggurmahendra Feb 6, 2023
d8f340b
changes so that it consider current speed
ronggurmahendra Feb 6, 2023
5c86e50
deleting a unused file
ronggurmahendra Feb 6, 2023
3a75ac3
implement manual mode
ronggurmahendra Feb 6, 2023
a182f4e
fix bug viewer
ronggurmahendra Feb 6, 2023
5bf5994
fix bug at viewer
ronggurmahendra Feb 6, 2023
adbe730
refactor
ronggurmahendra Feb 6, 2023
942cc71
adding repelent field
ronggurmahendra Feb 6, 2023
e5efc7a
implement repelent field
ronggurmahendra Feb 6, 2023
e876461
editting tof_tes
ronggurmahendra Feb 6, 2023
9bdb4ad
adding unit test
ronggurmahendra Feb 6, 2023
197b61d
adding test file
ronggurmahendra Feb 7, 2023
5c10155
add test file cases
ronggurmahendra Feb 8, 2023
748cf03
refactor : move file to different directories
ronggurmahendra Feb 16, 2023
ada812e
refactor : update readme.md, delete cache
ronggurmahendra Feb 16, 2023
31155ec
refactor : add comment to bash file
ronggurmahendra Feb 16, 2023
7e9d54b
refactor : change file name
ronggurmahendra Feb 16, 2023
73ff751
dev : change to numpy min
ronggurmahendra Feb 16, 2023
9558472
refactor : use function at point cloud callback
ronggurmahendra Feb 16, 2023
7d9e460
dev : change tof.py from publishing Twist to publishing pwm
ronggurmahendra Feb 16, 2023
3960ee3
dev : change tof.py from publishing Twist to publishing pwm
ronggurmahendra Feb 16, 2023
238624a
fix minor bug with viewer
ronggurmahendra Feb 16, 2023
755654c
Debug : ignore NaN in min
ronggurmahendra Feb 16, 2023
a4fb1c3
Refactor : adding comment to the code
ronggurmahendra Feb 17, 2023
fe9119f
adding emergency brake from rosparam
ronggurmahendra Feb 17, 2023
aedd093
restore previous version of twist_to_pwm.py
ronggurmahendra Feb 17, 2023
28c50d2
refactor : remove global variable
ronggurmahendra Feb 17, 2023
61e36d8
refactor : move test file
ronggurmahendra Feb 17, 2023
af7ae5b
DEBUG : change the repelentField usage in testfile and change the sys…
ronggurmahendra Feb 17, 2023
84af085
refactor : adding comment to tof_test.py
ronggurmahendra Feb 17, 2023
40b25f2
edit bash file to not run twist_to_pwm.py
ronggurmahendra Feb 23, 2023
bd32c30
Resolving conflict
ronggurmahendra Feb 23, 2023
051e7a5
Delete src/__pycache__ directory
ronggurmahendra Feb 23, 2023
6406555
Delete software/__pycache__ directory
ronggurmahendra Feb 23, 2023
3da675c
Update README.md
ronggurmahendra Mar 1, 2023
5be0e12
Update README.md
ronggurmahendra Mar 1, 2023
0110972
Update README.md
ronggurmahendra Mar 1, 2023
2adaacc
refactor : requested PRchanges
ronggurmahendra Mar 5, 2023
5e99a2d
rename file to be more appropriate and refactor callback function
ronggurmahendra Mar 10, 2023
88a9f7f
fix the logic
ronggurmahendra Mar 10, 2023
f15a962
fix logic and refactor
ronggurmahendra Mar 13, 2023
3519c60
bug fix and add some additinal funciton to reppelent field
ronggurmahendra Mar 13, 2023
e41d699
delete unused code and uncomment import library
ronggurmahendra Mar 13, 2023
d62ac43
make another twist_to_pwm for the branch(skip a few parameter check) …
ronggurmahendra Mar 14, 2023
ff45f46
adding rotation to point cloud based of the installation
ronggurmahendra Mar 14, 2023
d3d6ab1
debug rotation matrix function bbut disable it since it use too many …
ronggurmahendra Mar 14, 2023
5b666d9
refactor and adding functions to repelent field
ronggurmahendra Mar 17, 2023
efa9bc2
resolving conflict
ronggurmahendra Mar 17, 2023
f7e9df5
debug
ronggurmahendra Mar 17, 2023
06e6c31
adding rear camera
ronggurmahendra Mar 17, 2023
d0386da
adding parameter
ronggurmahendra Mar 17, 2023
679b873
changing the quadratic parameter
ronggurmahendra Mar 17, 2023
b6935e6
delete unnessesarry code
ronggurmahendra Mar 19, 2023
d4f7255
adding another quadratic function
ronggurmahendra Mar 19, 2023
0fad87f
resolve conflict
ronggurmahendra Mar 19, 2023
eabad4e
split assisted navigation to 2 node
ronggurmahendra Mar 19, 2023
8ada88f
adding drive mode as a class, refactor assisted navigation iao and dr…
ronggurmahendra Mar 21, 2023
638f887
change parameter to use somulation and add simulation to bash file
ronggurmahendra Mar 22, 2023
1b0ef7d
change namefile of ToF implementation and add a IR sensor version
ronggurmahendra Apr 5, 2023
398ef70
fix a mistake with output linear
ronggurmahendra Apr 5, 2023
a5ee64f
ir publisher overhaul
ronggurmahendra Apr 5, 2023
1f7ddbf
refactor IRversion of assisted navigation
ronggurmahendra Apr 6, 2023
d9af7dd
change file name ro be more consistent
ronggurmahendra Apr 6, 2023
7e23a16
delete previous impelmentation using ToF and change the IR publisher…
ronggurmahendra Apr 6, 2023
6f17f5a
add a stand alone python script all in one for drive controller
ronggurmahendra Apr 6, 2023
904dfd2
remove unnesesarry code and modify according to IRsensor publisher
ronggurmahendra Apr 7, 2023
b6aa824
fix minor bug
ronggurmahendra Apr 7, 2023
6876bcd
resolving conflict
ronggurmahendra Apr 7, 2023
4d6cadd
change the index
ronggurmahendra Apr 7, 2023
2efcda0
add PMWmin to the final published output of the motor and make a simp…
ronggurmahendra Apr 12, 2023
d0f5537
Merge branch 'an_ToF' of https://github.com/Roboy/esp-wheelchair into…
ronggurmahendra Apr 12, 2023
9d725d8
adding USE_EMERGENCYBRAKE TO A ROSPARAM
ronggurmahendra Apr 12, 2023
fdd0ca6
debug minor typo bug
ronggurmahendra Apr 12, 2023
56af55b
change the USE_EMERGENCY BRAKE to rosparam, minor typo bug fix
ronggurmahendra Apr 12, 2023
b62220a
Change the Assisted drive code to a ROS package
ronggurmahendra Apr 13, 2023
6ed6c3a
adding ir_drive_controller to the executable
ronggurmahendra Apr 13, 2023
ce256c3
do recent changes to ir_drive_controller.py
ronggurmahendra Apr 13, 2023
711cf49
adding simulation model and launch file
ronggurmahendra Apr 14, 2023
ff433c3
add setup.py
ronggurmahendra Apr 14, 2023
5875bcf
Merge branch 'an_ToF' of https://github.com/Roboy/esp-wheelchair into…
ronggurmahendra Apr 14, 2023
5dd50b4
adding assisted_Navigation package
ronggurmahendra Apr 14, 2023
697b6c7
update readme.md
ronggurmahendra Apr 14, 2023
61ad4b7
update reamdme.md
ronggurmahendra Apr 14, 2023
37db21b
update readme.md
ronggurmahendra Apr 14, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
114 changes: 114 additions & 0 deletions software/README.md
Original file line number Diff line number Diff line change
@@ -1 +1,115 @@
# ToF Setup

documentation can be accsessed here : https://devanthro.atlassian.net/wiki/spaces/WS2223/pages/2747269188/AN+Software
## Variables :
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

everything related to ToF sensor setup belongs to your team's documentation page and not this repository


Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

markdown is used incorrectly, code is not highlighted and headlines are not used correctly
refer to https://github.com/Roboy/esp-wheelchair/blob/5c101553f75b88ecdbaae51f26349fd8e440acda/README.md for an example

MAC ADDRESS ToF 1 : 3C:FB:96:DC:59:7E
MAC ADDRESS ToF 2 : 3C:FB:96:DC:59:7F

ROS_MASTER_URI=http://192.168.0.104:11311

For this documentation we use this Router Configuration :


TOF1
MAC ADDRESS: 3C:FB:96:DC:59:7E
IP: 192.168.0.122

TOF2
MAC ADDRESS: 3C:FB:96:DC:59:7F
IP: 192.168.0.123

MASTER
IP : 192.168.0.124

## Setup TOF 1

to setup tof1 do these command :

cd etc
nano rc.local

and then add rc.local with these commands:

#stops royale viewer entity
systemctl stop royaleviewer
source /opt/ros/melodic/setup.sh

# if you use other ip for ros master then do “export ROS_MASTER_URI=http://{ROS_MASTER_IP}:11311”
export ROS_MASTER_URI=http://192.168.0.124:11311

# if you use other ip for ToF2 then do “export ROS_HOSTNAME={TOF2_IP}”
export ROS_HOSTNAME=192.168.0.122
roslaunch royale_ros_sample camera_driver.launch node_name:=”tof1”

exit 0

Reset the ToF sensor then ToF should publish data to /tof1/...

## Setup TOF 2

to setup tof2 do these command :

cd etc
nano rc.local

and then add rc.local with these commands:

#stops royale viewer entity
systemctl stop royaleviewer
source /opt/ros/melodic/setup.sh

#if you use other ip for ros master then do “export ROS_MASTER_URI=http://{ROS_MASTER_IP}:11311”
export ROS_MASTER_URI=http://192.168.0.124:11311

#if you use other ip for ToF2 then do “export ROS_HOSTNAME={TOF2_IP}”
export ROS_HOSTNAME=192.168.0.123
roslaunch royale_ros_sample camera_driver.launch node_name:=”tof2”

exit 0

Reset the ToF sensor then ToF should publish data to /tof2/...

## MASTER

Do these command on the ROS master device:

#if you use other ip for ros master then do “export ROS_HOSTNAME={ROS_MASTER_IP}”
export ROS_HOSTNAME=192.168.0.124

#if you use other ip for ros master then do “export ROS_MASTER_URI=http://{ROS_MASTER_IP}:11311”
export ROS_MASTER_URI=http://192.168.0.124:11311
roscore

these code start the ROS MASTER



on a new terminal :

git clone -b an_ToF_emergencyBrake https://github.com/ronggurmahendra/esp-wheelchair.git
cd esp-wheelchair
python3 software/tof_potential_field.py

on a new terminal

cd esp-wheelchair
python3 software/twist_to_pwm.py

on a new terminal

rosrun teleop_twist_keyboard teleop_twist_keyboard.py

SIMULATION

to run the simulation

#asuming you already done the http://wiki.ros.org/catkin/Tutorials/create_a_workspace if not then do so
cd catkin_ws/src
git clone https://github.com/ronggurmahendra/Robody_Sim
cd ..
catkin_make
source devel/setup.sh

#run gazebo world of your choice
roslaunch gazebo_ros shapes_world.launch
Binary file added software/__pycache__/manual.cpython-38.pyc
Binary file not shown.
Binary file added software/__pycache__/repelent_field.cpython-38.pyc
Binary file not shown.
7 changes: 7 additions & 0 deletions software/assistedNavigation.bash
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#export ROS_HOSTNAME=192.168.0.124
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this script belongs to scripts folder and must have a description on top about what exactly it does

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

# if you use other ip for ros master then do “export ROS_MASTER_URI=http://{ROS_MASTER_IP}:11311”
#export ROS_MASTER_URI=http://192.168.0.124:11311
roscore &
python3 software/twist_to_pwm.py &
python3 software/tof.py &
rosrun teleop_twist_keyboard teleop_twist_keyboard.py
6 changes: 6 additions & 0 deletions software/manual.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class ManualMode:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

software folder is dedicated to the code that is running on the microcontroller of the mobile platform. for you python scripts, please create src folder in the root of this repository and move them there. manual.py is not a self-descriptive name. manual_control would be more appropriate. dito for repellent field (also please check your english for typos, there are quite a few of them).

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docstrings for classes are missing, please add

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

def __init__(self):
return

def control(self, inputLinear, inputAngular):
return inputLinear,inputAngular
11 changes: 11 additions & 0 deletions software/repelent_field.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class RepelentMode:
def __init__(self):
return

def control(self, inputLinear, inputAngular, minDistFront, minDistBack):
if inputLinear >= 0:
outputLinear = minDistFront
elif inputLinear < 0:
outputLinear = -1*minDistBack

return outputLinear,inputAngular
55 changes: 55 additions & 0 deletions software/test/tof_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import unittest
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

docstrings missing, wrong location of the script

import rospy

from std_msgs.msg import Float64
from sensor_msgs.msg import PointCloud2
from geometry_msgs.msg import Twist
import pcl
import ros_numpy
import numpy as np
import pcl.pcl_visualization
import sys
sys.path.insert(1, '../esp-wheelchair/software')

from manual import *
from repelent_field import *

class Assisted_Navigation_Test(unittest.TestCase):
def test_Repelent_Field(self):
repelentMode = RepelentMode()
inputLinear = 10
inputAngular = 11
minDistFront = 0.01
minDistBack = 10

outputLiner,outputAngular = repelentMode.control(inputLinear,inputAngular, minDistFront, minDistBack)
# test
# assert(outputLiner == 0 and outputAngular == outputAngular )
self.assertEqual((outputLiner, outputAngular), (0.01, inputAngular))
repelentMode = RepelentMode()
inputLinear = -1
inputAngular = 2
minDistFront = 2
minDistBack = 0.1

outputLiner,outputAngular = repelentMode.control(inputLinear,inputAngular, minDistFront, minDistBack)
# test
self.assertEqual((outputLiner, outputAngular), (-0.1, inputAngular))


def test_Manual_Mode(self):
manualMode = ManualMode()
inputLinear = 10
inputAngular = 1
self.assertEqual(manualMode.control(inputLinear,inputAngular), (inputLinear, inputAngular))

inputLinear = -10
inputAngular = 1
self.assertEqual(manualMode.control(inputLinear,inputAngular), (inputLinear, inputAngular))

inputLinear = 0
inputAngular = -1
self.assertEqual(manualMode.control(inputLinear,inputAngular), (inputLinear, inputAngular))

if __name__ == '__main__':
unittest.main()
104 changes: 104 additions & 0 deletions software/tof.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
# Usage:

# cd esp-wheelchair
# python3 software/tof.py

import rospy
from std_msgs.msg import Float64
from sensor_msgs.msg import PointCloud2
from geometry_msgs.msg import Twist
import pcl
import ros_numpy
import numpy as np
import pcl.pcl_visualization
from manual import *
from repelent_field import *
useVisual = False

emergencyStopThreshold = 0.1
if(useVisual):
viewer_front = pcl.pcl_visualization.PCLVisualizering()
viewer_back = pcl.pcl_visualization.PCLVisualizering()
minDist_front = 9999
minDist_back = 9999
inputLinear = None
inputAngular = None
manualMode = ManualMode()
repelentMode = RepelentMode()

def getNearestDistance(points):
min = 9999
for i in range(len(points)):
if(min > points[i][2]):
min = points[i][2]
return min
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use numpy methods to find min

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


def point_cloud_front_callback(msg):
# change from pointcloud2 to numpy
pc = ros_numpy.numpify(msg)
height = pc.shape[0]
width = pc.shape[1]
np_points = np.zeros((height * width, 3), dtype=np.float32)
np_points[:, 0] = np.resize(pc['x'], height * width)
np_points[:, 1] = np.resize(pc['y'], height * width)
np_points[:, 2] = np.resize(pc['z'], height * width)
if(useVisual):
p = pcl.PointCloud(np.array(np_points, dtype=np.float32))
viewer_front.AddPointCloud(p, b'scene_cloud_front', 0)
viewer_front.SpinOnce()
viewer_front.RemovePointCloud( b'scene_cloud_front', 0)
# find the nearest point
global minDist_front
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not global variables are allowed

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

minDist_front = getNearestDistance(np_points)

def point_cloud_back_callback(msg):
# change from pointcloud2 to numpy
pc = ros_numpy.numpify(msg)
height = pc.shape[0]
width = pc.shape[1]
np_points = np.zeros((height * width, 3), dtype=np.float32)
np_points[:, 0] = np.resize(pc['x'], height * width)
np_points[:, 1] = np.resize(pc['y'], height * width)
np_points[:, 2] = np.resize(pc['z'], height * width)
if(useVisual):
p = pcl.PointCloud(np.array(np_points, dtype=np.float32))
viewer_back.AddPointCloud(p, b'scene_cloud_back', 0)
viewer_back.SpinOnce()
viewer_back.RemovePointCloud( b'scene_cloud_back', 0)
# find the nearest point
global minDist_back
minDist_back = getNearestDistance(np_points)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

copy paste antipattern, identical to point_cloud_front_callback, rewrite to 1 function that can be used for front and back

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


def user_input_callback(msg):
inputLinear = msg.linear.x
inputAngular = msg.angular.z

# manual mode
outputLinear,outputAngular = manualMode.control(inputLinear,inputAngular)

if(minDist_front < emergencyStopThreshold and inputLinear > 0): # asume that this is the front ToF
print ("ABOUT TO COLLIDE FRONT EMERGENCY BRAKE")
outputLinear = 0
elif (minDist_back < emergencyStopThreshold and inputLinear < 0): # asume that this is the back ToF
print ("ABOUT TO COLLIDE BACK EMERGENCY BRAKE")
outputLinear = 0

# reppelent field
# outputLinear,outputAngular = repelentMode.control(inputLinear,inputAngular,minDist_front,minDist_back)

twist = Twist()
twist.linear.x = outputLinear
twist.angular.z = outputAngular
assisted_navigation_pub.publish(twist)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments missing

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


rospy.init_node('assisted_Navigation')

assisted_navigation_pub = rospy.Publisher('/roboy/pinky/middleware/espchair/wheels/assisted_navigation', Twist, queue_size=10)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong topic name and message. /roboy/pinky/middleware/espchair/wheels/left and /roboy/pinky/middleware/espchair/wheels/right are used to control the wheelchair

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

user_input_sub = rospy.Subscriber('/cmd_vel', Twist, user_input_callback)
# point_cloud_sub = rospy.Subscriber('/royale_camera_driver/point_cloud', PointCloud2, point_cloud_callback)

point_cloud_front_sub = rospy.Subscriber('/tof1_driver/point_cloud', PointCloud2, point_cloud_front_callback)
point_cloud__back_sub = rospy.Subscriber('/tof2_driver/point_cloud', PointCloud2, point_cloud_back_callback)

print("publishing to /roboy/pinky/middleware/espchair/wheels/assisted_navigation. Spinning...")
rospy.spin()
34 changes: 15 additions & 19 deletions software/twist_to_pwm.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
# Usage:


# rosrun rosserial_python serial_node.py tcp
# plugin wheelchair power

# cd esp-wheelchair
# python software/twist_to_pwm.py
# python3 software/twist_to_pwm.py
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this script is not used. why are there edits to it?


# start ROS joystick node - atk3 is for logitech joystick
# roslaunch teleop_twist_joy teleop.launch joy_config:=atk3
Expand Down Expand Up @@ -38,25 +37,22 @@ def mapPwm(x, out_min, out_max):


def cb(msg):
if not rospy.get_param('wheelchair_emergency_stopped'):
rospy.loginfo_throttle(5, "Publishing pwm..")
x = max(min(msg.linear.x, 1.0), -1.0)
z = max(min(msg.angular.z, 1.0), -1.0)

l = (msg.linear.x - msg.angular.z) / 2.0
r = (msg.linear.x + msg.angular.z) / 2.0

lPwm = mapPwm(abs(l), PWM_MIN, PWMRANGE)
rPwm = mapPwm(abs(r), PWM_MIN, PWMRANGE)
rospy.loginfo_throttle(5, "Publishing pwm..")
x = max(min(msg.linear.x, 1.0), -1.0)
z = max(min(msg.angular.z, 1.0), -1.0)

pub_l.publish(sign(l)*lPwm)
pub_r.publish(sign(r)*rPwm)
else:
rospy.logwarn_throttle(1, "Emergency stop active. Ignoring cmd_vel")
l = (msg.linear.x - msg.angular.z) / 2.0
r = (msg.linear.x + msg.angular.z) / 2.0

lPwm = mapPwm(abs(l), PWM_MIN, PWMRANGE)
rPwm = mapPwm(abs(r), PWM_MIN, PWMRANGE)
print(" left : ", sign(l)*lPwm, ", right : ",sign(r)*rPwm)
pub_l.publish(sign(l)*lPwm)
pub_r.publish(sign(r)*rPwm)


sub = rospy.Subscriber("/cmd_vel", Twist, cb)
InputTopic = "/roboy/pinky/middleware/espchair/wheels/assisted_navigation"
sub = rospy.Subscriber(InputTopic, Twist, cb)

rospy.loginfo("Subscribed to /cmd_vel, will publish wheelchair PWM. Spinning...")
rospy.spin()
rospy.loginfo("Subscribed to " + InputTopic + ", will publish wheelchair PWM. Spinning...")
rospy.spin()